簡體   English   中英

以編程方式獲取緩存行大小?

[英]Programmatically get the cache line size?

歡迎所有平台,請指定您回答的平台。

一個類似的問題: How to programmatically get the CPU cache page size in C++?

在 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 共享此緩存。 如果您正在使用共享數據進行多線程編程,這非常有用(如果共享數據的線程也共享緩存,您將獲得更好的結果)。

在 Linux 上查看 sysconf(3)。

sysconf (_SC_LEVEL1_DCACHE_LINESIZE)

您也可以使用 getconf 從命令行獲取它:

$ getconf LEVEL1_DCACHE_LINESIZE
64

我一直在研究一些緩存線的東西,需要編寫一個跨平台的函數。 我將它提交給https://github.com/NickStrupat/CacheLineSize的 github 存儲庫,或者您可以使用下面的源代碼。 隨意用它做任何你想做的事。

#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

在 x86 上,您可以使用帶有函數 2 的CPUID指令來確定緩存和 TLB 的各種屬性。 解析函數 2 的輸出有些復雜,所以我將向您介紹Intel 處理器標識和 CPUID 指令 (PDF) 的第 3.1.3 節。

要從 C/C++ 代碼中獲取此數據,您需要使用內聯匯編、編譯器內在函數或調用外部匯編函數來執行 CPUID 指令。

如果您使用的是 SDL2,則可以使用此功能:

int SDL_GetCPUCacheLineSize(void);

它返回 L1 緩存行大小的大小,以字節為單位。

在我的 x86_64 機器上,運行以下代碼片段:

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

產生CacheLineSize = 64

我知道我有點晚了,但只是為未來的訪客添加信息。 SDL 文檔目前說返回的數字以 KB 為單位,但實際上以字節為單位。

在 Windows 平台上:

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

GetLogicalProcessorInformation 函數將為您提供系統使用的邏輯處理器的特征。 您可以遍歷函數返回的 SYSTEM_LOGICAL_PROCESSOR_INFORMATION,查找類型為 RelationCache 的條目。 每個這樣的條目都包含一個 ProcessorMask,它告訴您該條目適用於哪個處理器,並且在 CACHE_DESCRIPTOR 中,它告訴您正在描述什么類型的緩存以及該緩存的緩存行有多大。

ARMv6及以上有C0或Cache Type Register。 但是,它僅在特權模式下可用。

例如,來自Cortex™-A8 技術參考手冊

高速緩存類型寄存器的目的是確定指令和數據高速緩存的最小行長度(以字節為單位),以使地址范圍無效。

緩存類型寄存器是:

  • 只讀寄存器
  • 只能在特權模式下訪問。

Cache Type Register 的內容取決於具體的實現。 圖 3-2 顯示了緩存類型寄存器的位排列...


不要假設 ARM 處理器有緩存(顯然,有些可以沒有緩存)。 確定它的標准方法是通過C0 ARM ARM ,第 B6-6 頁:

從 ARMv6 開始,系統控制協處理器緩存類型寄存器是定義 L1 緩存的強制方法,請參閱第 B6-14 頁的緩存類型寄存器。 對於早期的架構變體,這也是推薦的方法。 此外,第 B6-12 頁上的額外緩存級別的注意事項描述了 2 級緩存支持的體系結構指南。

從 C++17 開始,您可以使用std::hardware_破壞性_interference_size
其定義為:

兩個對象之間的最小偏移量,以避免錯誤共享。 保證至少是 alignof(std::max_align_t)

您也可以嘗試通過測量一些時間以編程方式進行。 顯然,它並不總是像 cpuid 之類的那樣精確,但它更便攜。 ATLAS 在其配置階段執行此操作,您可能需要查看它:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM