摘要:
memcpy似乎无法在真实或测试应用程序中在我的系统上传输超过2GB /秒.我该怎么做才能获得更快的内存到内存副本?
详细信息:
作为数据捕获应用程序的一部分(使用一些专用硬件),我需要将大约3 GB /秒的临时缓冲区复制到主内存中.为了获取数据,我为硬件驱动程序提供了一系列缓冲区(每个2MB).硬件将数据DMA数据到每个缓冲区,然后在每个缓冲区已满时通知我的程序.我的程序清空缓冲区(memcpy到另一个更大的RAM块),并将处理后的缓冲区重新发送到卡中再次填充.我遇到了memcpy足够快地移动数据的问题.似乎内存到内存的副本应该足够快,以便在我运行的硬件上支持3GB /秒.Lavalys EVEREST给了我一个9337MB /秒的内存复制基准测试结果,但即使在一个简单的测试程序中,我也无法通过memcpy获得接近这些速度的任何数据.
我通过在缓冲区处理代码中添加/删除memcpy调用来隔离性能问题.没有memcpy,我可以运行全数据速率 - 大约3GB /秒.启用memcpy后,我被限制在大约550Mb /秒(使用当前编译器).
为了在我的系统上对memcpy进行基准测试,我编写了一个单独的测试程序,它只是在某些数据块上调用memcpy.(我已经发布了下面的代码)我在我正在使用的编译器/ IDE(National Instruments CVI)以及Visual Studio 2010中都运行了这个.虽然我目前没有使用Visual Studio,但我愿意如果它将产生必要的性能,则进行切换.然而,在盲目地移动之前,我想确保它能解决我的memcpy性能问题.
Visual C++ 2010:1900 MB /秒
NI CVI 2009:550 MB /秒
虽然我并不感到惊讶,CVI比Visual Studio的显著慢,我很惊讶的是,memcpy的性能是这种低.虽然我不确定这是否可以直接比较,但这远低于EVEREST基准带宽.虽然我不需要那么高的性能水平,但至少需要3GB /秒.当然,标准库的实现不会比EVEREST使用的更糟糕!
在这种情况下,如果有的话,我可以做些什么来更快地使用memcpy?
硬件细节:AMD Magny Cours-4x八核128 GB DDR3 Windows Server 2003 Enterprise X64
测试程序:
#include <windows.h>
#include <stdio.h>
const size_t NUM_ELEMENTS = 2*1024 * 1024;
const size_t ITERATIONS = 10000;
int main (int argc, char *argv[])
{
LARGE_INTEGER start, stop, frequency;
QueryPerformanceFrequency(&frequency);
unsigned short * src = …
Run Code Online (Sandbox Code Playgroud) 使用Windows
所以我从二进制文件中读取一个unsigned int数据值列表.该文件包含按顺序列出的许多数据集.这是从char*中读取单个数据集的函数,指向它的开头:
function read_dataset(char* stream, t_dataset *dataset){
//...some init, including setting dataset->size;
for(i=0;i<dataset->size;i++){
dataset->samples[i] = *((unsigned int *) stream);
stream += sizeof(unsigned int);
}
//...
}
Run Code Online (Sandbox Code Playgroud)
read_dataset在这样的上下文中:
//...
char buff[10000];
t_dataset* dataset = malloc( sizeof( *dataset) );
unsigned long offset = 0;
for(i=0;i<number_of_datasets; i++){
fseek(fd_in, offset, SEEK_SET);
if( (n = fread(buff, sizeof(char), sizeof(*dataset), fd_in)) != sizeof(*dataset) ){
break;
}
read_dataset(buff, *dataset);
// Do something with dataset here. It's screwed up before this, I checked.
offset += profileSize;
}
//... …
Run Code Online (Sandbox Code Playgroud) 我想将va_list传递给另一个函数.这是我想要做的一个例子:
void my_printf_1(char* string, ...) {
va_list ap;
va_start(ap, string);
printf(string, ap);
va_end(ap);
}
void my_printf_2(char* string, ...) {
va_list ap;
va_start(ap, string);
printf(string, *ap);
va_end(ap);
}
int main(void) {
my_printf_1("Hello %i\n", 12); //Shows me the pointer
my_printf_1("Hello \n"); //Runtime Error - too many arguments
my_printf_2("Hello %i\n", 12); //Displays correctly because 12 < char
my_printf_2("Hello %i\n", 500); //Displays incorrectly because 500 > char
my_printf_2("Hello %i %i\n", 12, 12); //Displays 12, then crashes Runtime Error not enough arguments
my_printf_2("Hello \n"); //Runtime …
Run Code Online (Sandbox Code Playgroud)