关于Google Benchmark测试代码中::posix_memalign与void* memory的疑问
缓存与RAM读写基准测试代码疑问解答
我希望对缓存与RAM的读写速度进行基准测试,计划使用Google Benchmark库,在查看如下示例代码后大致理解逻辑,但存在以下疑问:
- 代码中的memory是什么?为何将其定义为void*类型指针?
- 为何posix_memalign前要加::?是否是因为引用Google Benchmark类?同时我想理解该C++代码中这些符号的含义。
示例代码:
#include <cstddef> #include <cstdlib> #include <string.h> #include <emmintrin.h> #include <immintrin.h> #include "benchmark/benchmark.h" #define ARGS \ ->RangeMultiplier(2)->Range(1024, 2*1024*1024) \ ->UseRealTime() template <class Word> void BM_write_seq(benchmark::State& state) { void* memory; if (::posix_memalign(&memory, 64, state.range_x()) != 0) return; void* const end = static_cast<char*>(memory) + state.range_x(); Word* const p0 = static_cast<Word*>(memory); Word* const p1 = static_cast<Word*>(end); Word fill; ::memset(&fill, 0xab, sizeof(fill)); while (state.KeepRunning()) { for (Word* p = p0; p < p1; ++p) { benchmark::DoNotOptimize(*p = fill); } } ::free(memory); }
问题1:代码中的memory是什么?为何定义为void*类型指针?
memory就是咱们为基准测试专门分配的内存块的起始指针,这块内存就是测试写入速度的目标区域。
把它定义成void*主要有两个原因:
- 适配分配函数的要求:
posix_memalign这个函数的第一个参数要求是void**,用来返回分配好的内存地址,用void*作为存储变量刚好能匹配这个接口。 - 保证内存的通用性:因为这是个模板函数(
template <class Word>),咱们需要这块内存能转换成任意数据类型的指针(比如int*、double*甚至SIMD指令用的宽类型指针),void*是C++里的通用无类型指针,完美满足这种“通用内存块”的需求,后面通过static_cast就能转成咱们需要的Word*类型。
问题2:为何posix_memalign前要加::?C++中::符号的含义
::是C++里的全局作用域解析运算符,简单来说就是告诉编译器:“我要调用的是全局命名空间里的那个函数,不是当前代码里某个局部作用域的同名函数”。
示例里的::posix_memalign、::memset、::free都加了这个符号,原因很简单:
- 避免命名冲突:比如如果
benchmark库或者咱们自己的代码里刚好有个同名的memset函数,不加::的话编译器可能会优先调用局部的那个,但咱们实际需要的是标准库提供的全局版本。 - 和Google Benchmark类没关系:这和引用
benchmark类完全不沾边,纯粹是为了确保调用的是正确的标准库函数,避免潜在的bug。
额外小细节帮你理解代码逻辑
benchmark::DoNotOptimize:这是Google Benchmark的工具函数,用来防止编译器耍小聪明——如果编译器发现咱们写入的值后续没被用到,可能会直接把整个循环优化掉,这个函数就是告诉编译器“别优化这个操作,我要测真实的写入速度”。posix_memalign的第二个参数64:这是要求内存对齐到64字节边界,而64字节刚好是大多数CPU缓存行的大小,这样分配的内存不会跨缓存行,测试结果会更准确。ARGS宏:用来设置测试的内存大小范围(从1KB到2MB,每次翻倍),还指定了用真实时间来统计结果,而不是CPU时间。
内容的提问来源于stack exchange,提问作者aikhs
相关产品推荐
相关产品推荐

