您现在的位置是:主页 > news > 网络营销跟做网站有什么区别/aso关键词优化计划

网络营销跟做网站有什么区别/aso关键词优化计划

admin2025/6/28 23:20:29news

简介网络营销跟做网站有什么区别,aso关键词优化计划,网站设计风格说明,建设局局长我们最近购买了一些新的服务器,并且正在经历糟糕的memcpy性能。 与我们的笔记本电脑相比,服务器上的memcpy性能要慢3倍。服务器规格底盘和Mobo:SUPER MICRO 1027GR-TRFCPU:2x Intel Xeon E5-2680 2.70 Ghz内存:8x 16G…

网络营销跟做网站有什么区别,aso关键词优化计划,网站设计风格说明,建设局局长我们最近购买了一些新的服务器,并且正在经历糟糕的memcpy性能。 与我们的笔记本电脑相比,服务器上的memcpy性能要慢3倍。服务器规格底盘和Mobo:SUPER MICRO 1027GR-TRFCPU:2x Intel Xeon E5-2680 2.70 Ghz内存:8x 16G…

我们最近购买了一些新的服务器,并且正在经历糟糕的memcpy性能。 与我们的笔记本电脑相比,服务器上的memcpy性能要慢3倍。

服务器规格

底盘和Mobo:SUPER MICRO 1027GR-TRF

CPU:2x Intel Xeon E5-2680 @ 2.70 Ghz

内存:8x 16GB DDR3 1600MHz

编辑:我也在另一台具有更高规格的服务器上进行测试,并看到与上述服务器相同的结果

服务器2规格

底盘和Mobo:SUPER MICRO 10227GR-TRFT

CPU:2x Intel Xeon E5-2650 v2 @ 2.6 Ghz

内存:8x 16GB DDR3 1866MHz

笔记本电脑规格

机箱:联想W530

CPU:1x Intel Core i7 i7-3720QM @ 2.6Ghz

内存:4x 4GB DDR3 1600MHz

操作系统

$ cat /etc/redhat-release

Scientific Linux release 6.5 (Carbon)

$ uname -a

Linux r113 2.6.32-431.1.2.el6.x86_64 #1 SMP Thu Dec 12 13:59:19 CST 2013 x86_64 x86_64 x86_64 GNU/Linux

编译器(在所有系统上)

$ gcc --version

gcc (GCC) 4.6.1

还根据@stefan的建议使用gcc 4.8.2进行了测试。 编译器之间没有性能差异。

测试代码下面的测试代码是一个罐装测试,用于复制我在生产代码中看到的问题。 我知道这个基准是简单的,但它能够利用和识别我们的问题。 代码在它们之间创建两个1GB缓冲区和memcpys,为memcpy调用计时。 您可以使用以下命令在命令行上指定备用缓冲区大小:./ big_memcpy_test [SIZE_BYTES]

#include

#include

#include

#include

class Timer

{

public:

Timer()

: mStart(),

mStop()

{

update();

}

void update()

{

mStart = std::chrono::high_resolution_clock::now();

mStop = mStart;

}

double elapsedMs()

{

mStop = std::chrono::high_resolution_clock::now();

std::chrono::milliseconds elapsed_ms =

std::chrono::duration_cast<:chrono::milliseconds>(mStop - mStart);

return elapsed_ms.count();

}

private:

std::chrono::high_resolution_clock::time_point mStart;

std::chrono::high_resolution_clock::time_point mStop;

};

std::string formatBytes(std::uint64_t bytes)

{

static const int num_suffix = 5;

static const char* suffix[num_suffix] = { "B", "KB", "MB", "GB", "TB" };

double dbl_s_byte = bytes;

int i = 0;

for (; (int)(bytes / 1024.) > 0 && i < num_suffix;

++i, bytes /= 1024.)

{

dbl_s_byte = bytes / 1024.0;

}

const int buf_len = 64;

char buf[buf_len];

// use snprintf so there is no buffer overrun

int res = snprintf(buf, buf_len,"%0.2f%s", dbl_s_byte, suffix[i]);

// snprintf returns number of characters that would have been written if n had

// been sufficiently large, not counting the terminating null character.

// if an encoding error occurs, a negative number is returned.

if (res >= 0)

{

return std::string(buf);

}

return std::string();

}

void doMemmove(void* pDest, const void* pSource, std::size_t sizeBytes)

{

memmove(pDest, pSource, sizeBytes);

}

int main(int argc, char* argv[])

{

std::uint64_t SIZE_BYTES = 1073741824; // 1GB

if (argc > 1)

{

SIZE_BYTES = std::stoull(argv[1]);

std::cout << "Using buffer size from command line: " << formatBytes(SIZE_BYTES)

<< std::endl;

}

else

{

std::cout << "To specify a custom buffer size: big_memcpy_test [SIZE_BYTES] \n"

<< "Using built in buffer size: " << formatBytes(SIZE_BYTES)

<< std::endl;

}

// big array to use for testing

char* p_big_array = NULL;

/

// malloc

{

Timer timer;

p_big_array = (char*)malloc(SIZE_BYTES * sizeof(char));

if (p_big_array == NULL)

{

std::cerr << "ERROR: malloc of " << SIZE_BYTES << " returned NULL!"

<< std::endl;

return 1;

}

std::cout << "malloc for " << formatBytes(SIZE_BYTES) << " took "

<< timer.elapsedMs() << "ms"

<< std::endl;

}

/

// memset

{

Timer timer;

// set all data in p_big_array to 0

memset(p_big_array, 0xF, SIZE_BYTES * sizeof(char));

double elapsed_ms = timer.elapsedMs();

std::cout << "memset for " << formatBytes(SIZE_BYTES) << " took "

<< elapsed_ms << "ms "

<< "(" << formatBytes(SIZE_BYTES / (elapsed_ms / 1.0e3)) << " bytes/sec)"

<< std::endl;

}

/

// memcpy

{

char* p_dest_array = (char*)malloc(SIZE_BYTES);

if (p_dest_array == NULL)

{

std::cerr << "ERROR: malloc of " << SIZE_BYTES << " for memcpy test"

<< " returned NULL!"

<< std::endl;

return 1;

}

memset(p_dest_array, 0xF, SIZE_BYTES * sizeof(char));

// time only the memcpy FROM p_big_array TO p_dest_array

Timer timer;

memcpy(p_dest_array, p_big_array, SIZE_BYTES * sizeof(char));

double elapsed_ms = timer.elapsedMs();

std::cout << "memcpy for " << formatBytes(SIZE_BYTES) << " took "

<< elapsed_ms << "ms "

<< "(" << formatBytes(SIZE_BYTES / (elapsed_ms / 1.0e3)) << " bytes/sec)"

<< std::endl;

// cleanup p_dest_array

free(p_dest_array);

p_dest_array = NULL;

}

/

// memmove

{

char* p_dest_array = (char*)malloc(SIZE_BYTES);

if (p_dest_array == NULL)

{

std::cerr << "ERROR: malloc of " << SIZE_BYTES << " for memmove test"

<< " returned NULL!"

<< std::endl;

return 1;

}

memset(p_dest_array, 0xF, SIZE_BYTES * sizeof(char));

// time only the memmove FROM p_big_array TO p_dest_array

Timer timer;

// memmove(p_dest_array, p_big_array, SIZE_BYTES * sizeof(char));

doMemmove(p_dest_array, p_big_array, SIZE_BYTES * sizeof(char));

double elapsed_ms = timer.elapsedMs();

std::cout << "memmove for " << formatBytes(SIZE_BYTES) << " took "

<< elapsed_ms << "ms "

<< "(" << formatBytes(SIZE_BYTES / (elapsed_ms / 1.0e3)) << " bytes/sec)"

<< std::endl;

// cleanup p_dest_array

free(p_dest_array);

p_dest_array = NULL;

}

// cleanup

free(p_big_array);

p_big_array = NULL;

return 0;

}

构建CMake文件

project(big_memcpy_test)

cmake_minimum_required(VERSION 2.4.0)

include_directories(${CMAKE_CURRENT_SOURCE_DIR})

# create verbose makefiles that show each command line as it is issued

set( CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "Verbose" FORCE )

# release mode

set( CMAKE_BUILD_TYPE Release )

# grab in CXXFLAGS environment variable and append C++11 and -Wall options

set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -march=native -mtune=native" )

message( INFO "CMAKE_CXX_FLAGS = ${CMAKE_CXX_FLAGS}" )

# sources to build

set(big_memcpy_test_SRCS

main.cpp

)

# create an executable file named "big_memcpy_test" from

# the source files in the variable "big_memcpy_test_SRCS".

add_executable(big_memcpy_test ${big_memcpy_test_SRCS})

检测结果

Buffer Size: 1GB | malloc (ms) | memset (ms) | memcpy (ms) | NUMA nodes (numactl --hardware)

---------------------------------------------------------------------------------------------

Laptop 1 | 0 | 127 | 113 | 1

Laptop 2 | 0 | 180 | 120 | 1

Server 1 | 0 | 306 | 301 | 2

Server 2 | 0 | 352 | 325 | 2

正如您所看到的,我们服务器上的memcpys和memset比我们笔记本电脑上的memcpys和memset要慢得多。

改变缓冲区大小

我尝试过从100MB到5GB的缓冲区都有类似的结果(服务器比笔记本电脑慢)

NUMA Affinity

我读到了与NUMA有性能问题的人,所以我尝试使用numactl设置CPU和内存亲和力,但结果保持不变。

服务器NUMA硬件

$ numactl --hardware

available: 2 nodes (0-1)

node 0 cpus: 0 1 2 3 4 5 6 7 16 17 18 19 20 21 22 23

node 0 size: 65501 MB

node 0 free: 62608 MB

node 1 cpus: 8 9 10 11 12 13 14 15 24 25 26 27 28 29 30 31

node 1 size: 65536 MB

node 1 free: 63837 MB

node distances:

node 0 1

0: 10 21

1: 21 10

笔记本电脑NUMA硬件

$ numactl --hardware

available: 1 nodes (0)

node 0 cpus: 0 1 2 3 4 5 6 7

node 0 size: 16018 MB

node 0 free: 6622 MB

node distances:

node 0

0: 10

设置NUMA亲和力

$ numactl --cpunodebind=0 --membind=0 ./big_memcpy_test

任何帮助解决这个问题非常感谢。

编辑:GCC选项

根据评论,我尝试使用不同的GCC选项进行编译:

使用-march和-mtune进行编译设置为native

g++ -std=c++0x -Wall -march=native -mtune=native -O3 -DNDEBUG -o big_memcpy_test main.cpp

结果:完全相同的性能(没有改进)

使用-O2而不是-O3进行编译

g++ -std=c++0x -Wall -march=native -mtune=native -O2 -DNDEBUG -o big_memcpy_test main.cpp

结果:完全相同的性能(没有改进)

编辑:更改memset以写入0xF而不是0以避免NULL页面(@SteveCox)

使用0以外的值进行memset时没有改进(在这种情况下使用0xF)。

编辑:Cachebench结果

为了排除我的测试程序过于简单,我下载了一个真正的基准程序LLCacheBench([http://icl.cs.utk.edu/projects/llcbench/cachebench.html]]

我分别在每台机器上构建了基准测试,以避免架构问题。 以下是我的结果。

PTqZJ.png

请注意,在较大的缓冲区大小上,性能差异很大。 测试的最后一个尺寸(16777216)在笔记本电脑上以18849.29 MB /秒和在服务器上以6710.40执行。 这是性能差异的3倍。 您还可以注意到服务器的性能下降比笔记本电脑更陡峭。

编辑:memmove()比服务器上的memcpy()快2倍

基于一些实验,我尝试在我的测试用例中使用memmove()而不是memcpy(),并在服务器上找到了2倍的改进。 笔记本电脑上的Memmove()运行速度比memcpy()慢,但奇怪的是运行速度与服务器上的memmove()相同。 这引出了一个问题,为什么memcpy这么慢?

更新了代码以测试memmove和memcpy。 我必须将memmove()包装在一个函数中,因为如果我离开它内联GCC优化它并执行与memcpy()完全相同(我假设gcc将其优化为memcpy,因为它知道位置没有重叠)。

更新结果

Buffer Size: 1GB | malloc (ms) | memset (ms) | memcpy (ms) | memmove() | NUMA nodes (numactl --hardware)

---------------------------------------------------------------------------------------------------------

Laptop 1 | 0 | 127 | 113 | 161 | 1

Laptop 2 | 0 | 180 | 120 | 160 | 1

Server 1 | 0 | 306 | 301 | 159 | 2

Server 2 | 0 | 352 | 325 | 159 | 2

编辑:天真的Memcpy

根据@Salgar的建议,我已经实现了我自己的天真memcpy功能并对其进行了测试。

天真的Memcpy来源

void naiveMemcpy(void* pDest, const void* pSource, std::size_t sizeBytes)

{

char* p_dest = (char*)pDest;

const char* p_source = (const char*)pSource;

for (std::size_t i = 0; i < sizeBytes; ++i)

{

*p_dest++ = *p_source++;

}

}

天真的Memcpy结果与memcpy()相比

Buffer Size: 1GB | memcpy (ms) | memmove(ms) | naiveMemcpy()

------------------------------------------------------------

Laptop 1 | 113 | 161 | 160

Server 1 | 301 | 159 | 159

Server 2 | 325 | 159 | 159

编辑:装配输出

简单的memcpy源码

#include

#include

int main(int argc, char* argv[])

{

size_t SIZE_BYTES = 1073741824; // 1GB

char* p_big_array = (char*)malloc(SIZE_BYTES * sizeof(char));

char* p_dest_array = (char*)malloc(SIZE_BYTES * sizeof(char));

memset(p_big_array, 0xA, SIZE_BYTES * sizeof(char));

memset(p_dest_array, 0xF, SIZE_BYTES * sizeof(char));

memcpy(p_dest_array, p_big_array, SIZE_BYTES * sizeof(char));

free(p_dest_array);

free(p_big_array);

return 0;

}

装配输出:这在服务器和笔记本电脑上完全相同。 我节省空间而不是粘贴两者。

.file "main_memcpy.cpp"

.section .text.startup,"ax",@progbits

.p2align 4,,15

.globl main

.type main, @function

main:

.LFB25:

.cfi_startproc

pushq %rbp

.cfi_def_cfa_offset 16

.cfi_offset 6, -16

movl $1073741824, %edi

pushq %rbx

.cfi_def_cfa_offset 24

.cfi_offset 3, -24

subq $8, %rsp

.cfi_def_cfa_offset 32

call malloc

movl $1073741824, %edi

movq %rax, %rbx

call malloc

movl $1073741824, %edx

movq %rax, %rbp

movl $10, %esi

movq %rbx, %rdi

call memset

movl $1073741824, %edx

movl $15, %esi

movq %rbp, %rdi

call memset

movl $1073741824, %edx

movq %rbx, %rsi

movq %rbp, %rdi

call memcpy

movq %rbp, %rdi

call free

movq %rbx, %rdi

call free

addq $8, %rsp

.cfi_def_cfa_offset 24

xorl %eax, %eax

popq %rbx

.cfi_def_cfa_offset 16

popq %rbp

.cfi_def_cfa_offset 8

ret

.cfi_endproc

.LFE25:

.size main, .-main

.ident "GCC: (GNU) 4.6.1"

.section .note.GNU-stack,"",@progbits

进展!!!!ASMLib程序

根据@tbenson的建议,我尝试使用memml的asmlib版本运行。 我的结果最初很差但是在将SetMemcpyCacheLimit()更改为1GB(我的缓冲区的大小)后,我的速度与我的天真for循环相同!

坏消息是memmove的asmlib版本比glibc版本慢,它现在运行在300ms标记(与glibc版本的memcpy相同)。 奇怪的是,在我的SetMemcpyCacheLimit()大量的笔记本电脑上它会伤害性能......

在下面的结果中,标记为SetCache的行将SetMemcpyCacheLimit设置为1073741824.没有SetCache的结果不会调用SetMemcpyCacheLimit()

使用asmlib函数的结果:

Buffer Size: 1GB | memcpy (ms) | memmove(ms) | naiveMemcpy()

------------------------------------------------------------

Laptop | 136 | 132 | 161

Laptop SetCache | 182 | 137 | 161

Server 1 | 305 | 302 | 164

Server 1 SetCache | 162 | 303 | 164

Server 2 | 300 | 299 | 166

Server 2 SetCache | 166 | 301 | 166

开始倾向于缓存问题,但是会导致什么呢?