- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我已经编写了两个程序来检查 clflush 是否正在从缓存中逐出我的数据。在我编写的两个程序中,只有一个给出了正确的结果(按照我的预期,在 clflush 之后,访问时间必须比刷新之前更长)。
这是我得到预期结果的 Program1。
#include <stdio.h>
#include <stdint.h>
inline void clflush(volatile void *p)
{
asm volatile ("clflush (%0)" :: "r"(p));
}
inline uint64_t rdtsc()
{
unsigned long a, d;
asm volatile ("cpuid; rdtsc" : "=a" (a), "=d" (d) : : "ebx", "ecx");
return a | ((uint64_t)d << 32);
}
static int i=10; // static variable
inline void test()
{
uint64_t start, end;
int j;
start = rdtsc();
j = i;
end = rdtsc();
printf("took %lu ticks\n", end - start);
}
int main(int ac, char **av)
{
test();
test();
printf("flush: ");
clflush((void *)&i);
test();
test();
return 0;
}
这是我的输出(符合预期)
took 314 ticks
took 282 ticks
flush: took 442 ticks
took 272 ticks
这是另一个程序,我没有得到预期的结果。
#include <stdio.h>
#include <stdint.h>
inline void clflush(volatile void *p)
{
asm volatile ("clflush (%0)" :: "r"(p));
}
inline uint64_t rdtsc()
{
unsigned long a, d;
asm volatile ("cpuid; rdtsc" : "=a" (a), "=d" (d) : : "ebx", "ecx");
return a | ((uint64_t)d << 32);
}
static const int i=10; // I make this as constant
inline void test()
{
uint64_t start, end;
int j;
start = rdtsc();
j = i;
end = rdtsc();
printf("took %lu ticks\n", end - start);
}
int main(int ac, char **av)
{
test();
test();
printf("flush: ");
clflush((void *)&i);
test();
test();
return 0;
}
这是我的输出(符合预期)
took 314 ticks
took 282 ticks
flush: took 282 ticks // same as previous
took 272 ticks
--------
took 314 ticks
took 282 ticks
flush: took 272 ticks // lower than previous
took 272 ticks
如果我让 static int i=10;进入 static const int i=10;那么结果并不符合我的预期。在 clflush 之后,我获得了更低的值(value)/平等的访问时间。
谁能解释为什么会这样?我怎样才能按照我的期望(在 clflush 之后访问时间更长)(在 C 或 C++ 中)作为程序 1)?
我在 Fedora19 linux 下使用 GCC。任何帮助将不胜感激。
最佳答案
我很确定这里的问题是 CPUID + RDTSC 与“指令之间的指令”相比太长了。
我得到非常不同的结果,大概取决于代码最终运行在哪个实际 CPU 上的“运气”,其他 CPU 正在做什么,等等。
这是第二个程序的连续三个运行:
took 92 ticks
took 75 ticks
flush: took 75 ticks
took 474 ticks
took 221 ticks
took 243 ticks
flush: took 221 ticks
took 242 ticks
took 221 ticks
took 221 ticks
flush: took 221 ticks
took 230 ticks
但是,我认为我们不能由此得出“clflush 不起作用”的结论。只是处理器中有足够的时钟周期和足够的乱序执行来克服缓存刷新并重新加载数据。
如果您有大量数据,比如几千字节,您可能会得到更明显的效果。我稍后会做一些实验,但现在我需要一些食物......
#include <stdio.h>
#include <stdint.h>
inline void clflush(volatile void *p)
{
__asm volatile ("clflush (%0)" :: "r"(p));
}
inline uint64_t rdtsc()
{
unsigned long a, d;
__asm volatile ("rdtsc" : "=a" (a), "=d" (d) : : "ebx", "ecx");
return a | ((uint64_t)d << 32);
}
static int v[1024];
uint64_t t[5];
int r[5];
int ti = 0;
static inline void test()
{
uint64_t start, end;
int j;
start = rdtsc();
for(int i = 0; i < 1024; i++)
{
j += v[i];
}
end = rdtsc();
r[ti] = j;
t[ti++] = end - start;
}
int main(int ac, char **av)
{
for(int i = 0; i < 1024; i++)
{
v[i] = i;
}
test();
test();
t[ti++] = 0;
for(int i = 0; i < 1024; i+=4)
{
clflush((void *)&v[i]);
}
test();
test();
for(int i = 0; i < ti; i++)
{
if (t[i] == 0)
{
printf("flush\n");
}
else
{
printf("Test %lu [res=%d]\n", t[i], r[i]);
}
}
printf("\n");
return 0;
}
我将 printf 移出测试路径,以减少在那里花费的时间,并使刷新区域更大。这提供了更长的运行时间,这无疑有助于测量。
Test 2538 [res=523776]
Test 2593 [res=523776]
flush
Test 4845 [res=523776]
Test 2592 [res=523776]
Test 2550 [res=523776]
Test 2771 [res=523776]
flush
Test 4782 [res=523776]
Test 2513 [res=523776]
Test 2550 [res=523776]
Test 2708 [res=523776]
flush
Test 4356 [res=523776]
Test 2593 [res=523776]
如您所见,flush 之后,与第一次访问相比,数据的获取时间大约是原来的两倍。
编辑:
像这样使用const
static const int v[1024] =
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
/* snip 62 lines equal to this */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
};
给出这个结果:
Test 14139 [res=8704]
Test 2639 [res=8704]
flush
Test 5287 [res=8704]
Test 2597 [res=8704]
Test 12983 [res=8704]
Test 2652 [res=8704]
flush
Test 4859 [res=8704]
Test 2550 [res=8704]
Test 12911 [res=8704]
Test 2581 [res=8704]
flush
Test 4705 [res=8704]
Test 2649 [res=8704]
如您所见,第三次访问明显比第二次和第四次慢。第一次访问速度较慢,因为在第一次访问时缓存中根本没有任何内容(包括页表等)。
关于c++ - clflush 在 i7 中没有给出 const 数据类型的正确答案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21575080/
我正在尝试了解使用 CLFLUSH 对性能的影响。为此,我写了一个小指针追逐基准测试。我拿 std::vector>其中第一个元素是下一个条目的偏移量,第二个元素是有效载荷。我从条目 0 转到下一个条
我想尝试测量内存访问的时间差异,从缓存访问时和从主内存访问时。 考虑这个程序: #include #include #include #include #include #include
你能告诉我如何使用 clflush() 指令吗?我编写了以下简单代码来测量从缓存中读取变量的执行时间与从缓存中逐出变量后的执行时间之间的差异。但是我没有找到确凿的结果。使用 clflush() 清除缓
考虑以下代码段: #include #include #include #define ARRAYSIZE(arr) (sizeof(arr)/sizeof(arr[0])) inline vo
我们正在尝试使用 Intel CLFLUSH 指令在用户空间刷新 Linux 中进程的缓存内容。 我们创建了一个非常简单的 C 程序,它首先访问一个大数组,然后调用 CLFLUSH 来刷新整个数组的虚
我正在尝试使用 clflush 手动逐出缓存行以确定缓存和行大小。我没有找到任何关于如何使用该指令的指南。我所看到的只是一些代码为此目的使用了更高级别的函数。 有一个内核函数void clflush_
我最近了解到 row hammer攻击。为了执行此攻击,程序员需要刷新 CPU 的完整缓存层次结构以获取特定数量的地址。 我的问题是:为什么是 CLFLUSH x86 有必要吗?如果所有 L* 缓存都
是clflush 1 还刷新关联的 TLB 条目吗?我认为不会,因为 clflush 在缓存行粒度上运行,而 TLB 条目存在于(更大的)页面粒度 - 但我准备好感到惊讶。 1 ...或 clflus
OpenCL clFinish() API 调用会阻塞,直到命令队列上的所有命令都已完成执行。相关函数, clFlush() ,据说 Issues all previously queued Open
通常,缓存行是 64B,但非 volatile 内存的原子性是 8B。 例如: x[1]=100; x[2]=100; clflush(x); x缓存行对齐,初始设置为 0 . 系统崩溃 clflus
我已经编写了两个程序来检查 clflush 是否正在从缓存中逐出我的数据。在我编写的两个程序中,只有一个给出了正确的结果(按照我的预期,在 clflush 之后,访问时间必须比刷新之前更长)。 这是我
英特尔文档中的 clflush 描述称“刷新包含 m8 的缓存行。”。此外,在 Intel 文档中,m8 表示“内存中的一个字节”。 我很困惑为什么它只是m8,它只有一个字节。因为对于32位或64位系
英特尔文档中的 clflush 描述称“刷新包含 m8 的缓存行。”。此外,在 Intel 文档中,m8 表示“内存中的一个字节”。 我很困惑为什么它只是m8,它只有一个字节。因为对于32位或64位系
我是一名优秀的程序员,十分优秀!