以编程方式获取缓存线大小。

欢迎所有平台,请注明您的回答平台。

类似的问题:如何在C++中以编程方式获取CPU缓存页面大小?

96135 次浏览

在x86上,可以将CPUID指令与函数2一起使用,以确定高速缓存和TLB的各种属性。解析函数2的输出有些复杂,因此请参阅英特尔处理器标识与CPUID指令(PDF)的第3.1.3节。

要从C/C++代码中获取此数据,您需要使用内联汇编、编译器内部函数或调用外部汇编函数来执行CPUID指令。

您还可以尝试通过测量一些时间来以编程方式执行此操作。显然,它不会总是像CPUID等那样精确,但它更便携。Atlas在其配置阶段就做到了这一点,您可能想看看它:

http://math-atlas.sourceforge.net/.

在Linux上(使用相当新的内核),您可以从/sys:

/sys/devices/system/cpu/cpu0/cache/

对于每个缓存级别,此目录都有一个子目录。这些目录中的每一个都包含以下文件:

coherency_line_size
level
number_of_sets
physical_line_partition
shared_cpu_list
shared_cpu_map
size
type
ways_of_associativity

这为您提供了更多关于缓存的信息,包括缓存行大小(coherency_line_size)以及哪些CPU共享该缓存。如果您正在使用共享数据进行多线程编程,这将非常有用(如果共享数据的线程也共享缓存,您将获得更好的结果)。

在Windows平台上:

http://blogs.msdn.com/oldnewthing/archive/2009/12/08/9933836.aspx

GetLogicalProcessor信息 功能会给你特点。 正在使用的逻辑处理器的 该系统。你可以走 系统_逻辑_处理器_信息 由查找的函数返回 类型为RelationCache的条目。每一个 此类条目包含处理器掩码 它告诉您哪些处理器 项适用于,而在 缓存_描述符,它告诉你什么 正在描述缓存的类型,并且 该缓存线有多大 缓存.

在Linux上查看sysconf(3)。

sysconf (_SC_LEVEL1_DCACHE_LINESIZE)

您也可以使用getconf从命令行获取它:

$ getconf LEVEL1_DCACHE_LINESIZE
64

我一直在做一些缓存线的东西,需要写一个跨平台的功能。我在https://github.com/NickStrupat/CacheLineSize将其提交给GitHub repo,或者您可以只使用下面的源代码。你想怎么做就怎么做吧。

#ifndef GET_CACHE_LINE_SIZE_H_INCLUDED
#define GET_CACHE_LINE_SIZE_H_INCLUDED


// Author: Nick Strupat
// Date: October 29, 2010
// Returns the cache line size (in bytes) of the processor, or 0 on failure


#include <stddef.h>
size_t cache_line_size();


#if defined(__APPLE__)


#include <sys/sysctl.h>
size_t cache_line_size() {
size_t line_size = 0;
size_t sizeof_line_size = sizeof(line_size);
sysctlbyname("hw.cachelinesize", &line_size, &sizeof_line_size, 0, 0);
return line_size;
}


#elif defined(_WIN32)


#include <stdlib.h>
#include <windows.h>
size_t cache_line_size() {
size_t line_size = 0;
DWORD buffer_size = 0;
DWORD i = 0;
SYSTEM_LOGICAL_PROCESSOR_INFORMATION * buffer = 0;


GetLogicalProcessorInformation(0, &buffer_size);
buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION *)malloc(buffer_size);
GetLogicalProcessorInformation(&buffer[0], &buffer_size);


for (i = 0; i != buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); ++i) {
if (buffer[i].Relationship == RelationCache && buffer[i].Cache.Level == 1) {
line_size = buffer[i].Cache.LineSize;
break;
}
}


free(buffer);
return line_size;
}


#elif defined(linux)


#include <stdio.h>
size_t cache_line_size() {
FILE * p = 0;
p = fopen("/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size", "r");
unsigned int i = 0;
if (p) {
fscanf(p, "%d", &i);
fclose(p);
}
return i;
}


#else
#error Unrecognized platform
#endif


#endif

ARMv6及更高版本具有C0或缓存类型寄存器。但是,它仅在特权模式下可用。

例如,从Cortex™-A8技术参考手册

高速缓存类型寄存器的

目的是确定指令 和数据高速缓存的最小行长度(以字节为单位),以启用 要作废的地址。

缓存类型寄存器为:

  • 只读寄存器
  • 仅在特权模式下可访问。
缓存类型寄存器的

内容取决于具体的 实施。图3-2显示了高速缓存的位排列 类型寄存器..


不要假设ARM处理器有高速缓存(显然,有些可以配置为没有高速缓存)。确定它的标准方法是通过C0。从手臂手臂第B6-6页:

在ARMv6中,系统控制协处理器缓存类型寄存器是 定义一级缓存的授权方法,请参阅上的缓存类型寄存器 第B6-14页。这也是早期变体的推荐方法。 建筑。此外,对其他级别的考虑 第B6-12页上的缓存描述了第2级的体系结构指南 缓存支持.

如果您正在使用SDL2,则可以使用此函数:

int SDL_GetCPUCacheLineSize(void);

其返回L1高速缓存线的大小,以字节为单位。

在我的x86_64机器上,运行以下代码片段:

printf("CacheLineSize = %d",SDL_GetCPUCacheLineSize());

产生CacheLineSize = 64

我知道我有点晚了,但只是为未来的访问者添加信息。 SDL文档目前说返回的数字以KB为单位,但实际上是以字节为单位。

自C++17以来

,您可以使用硬件_破坏性_干扰_大小
其定义为:

避免假共享的两个对象之间的

最小偏移。保证 至少为ALIGNOF(STD:Max_ALIGN_T)