我的问题是有关了解Linux perf
工具度量标准。我做了一个优化与我的代码中的预取/缓存未命中相关,现在速度更快。但是,perf并没有告诉我(或者更确定地说,我不明白perf
显示了我)。无法理解由“perf”返回的有关缓存未命中的度量标准
回到它开始的地方。我做了一个调查,以便speed up random memory access using prefetch。
这里是我的程序做:
采取的所有值
- 它同样采用了尺寸
- 的两个int缓冲区它读取一个接一个的第一缓冲器的所有值
- 每个值都是第二个缓冲区中的随机索引
- 它读取第二个缓冲区中索引处的值
- 它总结从第二缓冲器
- 它全部为越来越大
- 前面的步骤最后,我打印随意和不随意CPU上下文的数量切换
我最后的调音后,我的代码是以下之一:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/time.h>
#include <math.h>
#include <sched.h>
#define BUFFER_SIZE ((unsigned long) 4096 * 50000)
#define PADDING 256
unsigned int randomUint()
{
int value = rand() % UINT_MAX;
return value;
}
unsigned int * createValueBuffer()
{
unsigned int * valueBuffer = (unsigned int *) malloc(BUFFER_SIZE * sizeof(unsigned int));
for (unsigned long i = 0 ; i < BUFFER_SIZE ; i++)
{
valueBuffer[i] = randomUint();
}
return (valueBuffer);
}
unsigned int * createIndexBuffer()
{
unsigned int * indexBuffer = (unsigned int *) malloc((BUFFER_SIZE + PADDING) * sizeof(unsigned int));
for (unsigned long i = 0 ; i < BUFFER_SIZE ; i++)
{
indexBuffer[i] = rand() % BUFFER_SIZE;
}
return (indexBuffer);
}
double computeSum(unsigned int * indexBuffer, unsigned int * valueBuffer, unsigned short prefetchStep)
{
double sum = 0;
for (unsigned int i = 0 ; i < BUFFER_SIZE ; i++)
{
__builtin_prefetch((char *) &valueBuffer[indexBuffer[i + prefetchStep]], 0, 0);
unsigned int index = indexBuffer[i];
unsigned int value = valueBuffer[index];
double s = sin(value);
sum += s;
}
return (sum);
}
unsigned int computeTimeInMicroSeconds(unsigned short prefetchStep)
{
unsigned int * valueBuffer = createValueBuffer();
unsigned int * indexBuffer = createIndexBuffer();
struct timeval startTime, endTime;
gettimeofday(&startTime, NULL);
double sum = computeSum(indexBuffer, valueBuffer, prefetchStep);
gettimeofday(&endTime, NULL);
printf("prefetchStep = %d, Sum = %f - ", prefetchStep, sum);
free(indexBuffer);
free(valueBuffer);
return ((endTime.tv_sec - startTime.tv_sec) * 1000 * 1000) + (endTime.tv_usec - startTime.tv_usec);
}
void testWithPrefetchStep(unsigned short prefetchStep)
{
unsigned int timeInMicroSeconds = computeTimeInMicroSeconds(prefetchStep);
printf("Time: %u micro-seconds = %.3f seconds\n", timeInMicroSeconds, (double) timeInMicroSeconds/(1000 * 1000));
}
int iterateOnPrefetchSteps()
{
printf("sizeof buffers = %ldMb\n", BUFFER_SIZE * sizeof(unsigned int)/(1024 * 1024));
for (unsigned short prefetchStep = 0 ; prefetchStep < 250 ; prefetchStep++)
{
testWithPrefetchStep(prefetchStep);
}
}
void setCpuAffinity(int cpuId)
{
int pid=0;
cpu_set_t mask;
unsigned int len = sizeof(mask);
CPU_ZERO(&mask);
CPU_SET(cpuId,&mask);
sched_setaffinity(pid, len, &mask);
}
int main(int argc, char ** argv)
{
setCpuAffinity(7);
if (argc == 2)
{
testWithPrefetchStep(atoi(argv[1]));
}
else
{
iterateOnPrefetchSteps();
}
}
在我以前的计算器的问题,我求你结束ght我有所有的元素:为了避免缓存未命中我做了我的代码预取数据(使用__builtin_prefetch
),我的程序更快。一切看起来尽可能正常
但是,我想使用Linux perf
工具研究它。于是,我开始了我的程序的两个执行之间的比较:
./TestPrefetch 0
:这样做,因为它是这只是后读取的数据进行预取是无效的(当数据被访问,它不能是加载到CPU缓存中)。运行持续时间:21.346秒./TestPrefetch 1
:这里的预取效率要高得多,因为数据在读取之前被读取一个循环迭代。运行时间:12.624秒
的perf
输出以下的:
$ gcc -O3 TestPrefetch.c -o TestPrefetch -lm && for cpt in 0 1; do echo ; echo "### Step=$cpt" ; sudo perf stat -e task-clock,cycles,instructions,cache-references,cache-misses ./TestPrefetch $cpt; done
### Step=0
prefetchStep = 0, Sum = -1107.523504 - Time: 21346278 micro-seconds = 21.346 seconds
Performance counter stats for './TestPrefetch 0':
24387,010283 task-clock (msec) # 1,000 CPUs utilized
97 274 163 155 cycles # 3,989 GHz
59 183 107 508 instructions # 0,61 insn per cycle
425 300 823 cache-references # 17,440 M/sec
249 261 530 cache-misses # 58,608 % of all cache refs
24,387790203 seconds time elapsed
### Step=1
prefetchStep = 1, Sum = -1107.523504 - Time: 12623665 micro-seconds = 12.624 seconds
Performance counter stats for './TestPrefetch 1':
15662,864719 task-clock (msec) # 1,000 CPUs utilized
62 159 134 934 cycles # 3,969 GHz
59 167 595 107 instructions # 0,95 insn per cycle
484 882 084 cache-references # 30,957 M/sec
321 873 952 cache-misses # 66,382 % of all cache refs
15,663437848 seconds time elapsed
在这里,我有困难明白为什么我更好:
- 的
cache-misses
数几乎是一样的(我甚至还有一点点):我不明白为什么和(总体)如果是这样,我为什么更快? - 什么是
cache-references
? - 什么是任务时钟和周期?它们是否包含在缓存未命中时等待数据访问的时间?
'insn per cycle'是所有执行的平均值,不是吗?我的程序现在更快(12.624秒,相对于21.346秒),因此每个循环的逻辑“insn”更高。但我仍然不明白为什么'cache-missses'更高 –
事实上,我仍然不明白为什么'cache-missses'更高 –
_“这些指令是乱序执行的”_你是什么确切的意思_“如果下一条指令需要某些未准备好的数据,则会执行其他指令”_我不明白你的意思?你能给我提供例子还是很好的链接?谢谢 –