Programaticamente obter o tamanho da linha de cache?

177

Todas as plataformas são bem-vindas, especifique a plataforma para sua resposta.

Uma pergunta semelhante: como obter programaticamente o tamanho da página de cache da CPU em C ++?

paxos1977
fonte
8
FWIW, C ++ 17 fornecerá uma aproximação em tempo de compilação disso: stackoverflow.com/questions/39680206/…
GManNickG 12/16
Além do C / C ++, se você não se importa em usar o assembly para obter essas informações, pode dar uma olhada (expandindo as informações da resposta de negamartin) no código-fonte da SDL_GetCPUCacheLineSizefunção do SDL2 e , em seguida, dar uma olhada no cpuid macroqual possui o código-fonte do assembly para cada do modelo de processador. Você pode dar uma olhada em imgur.com/a/KP57m6s ou espreitar diretamente a fonte.
haxpor 7/02/19

Respostas:

186

No Linux (com um kernel razoavelmente recente), você pode obter essas informações em / sys:

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

Este diretório possui um subdiretório para cada nível de cache. Cada um desses diretórios contém os seguintes arquivos:

coherency_line_size
level
number_of_sets
physical_line_partition
shared_cpu_list
shared_cpu_map
size
type
ways_of_associativity

Isso fornece mais informações sobre o cache do que você esperaria saber, incluindo o tamanho da linha de cache ( coherency_line_size), bem como quais CPUs compartilham esse cache. Isso é muito útil se você estiver fazendo programação multithread com dados compartilhados (você obterá melhores resultados se os threads que compartilham dados também estiverem compartilhando um cache).

spinfire
fonte
4
qual dos arquivos contém o tamanho da linha de cache? Estou assumindo o coherency_line_size? ou a partição_line_física?
paxos1977
27
coherency_line_size
spinfire
6
Para ter certeza: isso é em bytes, sim?
Jakub M.
6
Sim, coherency_line_size está em bytes.
John Zwinck
4
@android: Eu uso a máquina fedora-18 x64 com o processador core-i5. cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_sizeretorna 64no meu sistema. O mesmo para as pastas index1,2,3 também.
Abid Rahman K
141

No Linux, veja sysconf (3).

sysconf (_SC_LEVEL1_DCACHE_LINESIZE)

Você também pode obtê-lo na linha de comando usando o getconf:

$ getconf LEVEL1_DCACHE_LINESIZE
64
ob.
fonte
4
respostas simples são as melhores!
FrankH.
3
@warunapww Está em bytes.
Maarten Bamelis
finalmente! espero que mais pessoas vejam essa resposta para economizar tempo.
Elinx #
118

Eu tenho trabalhado em algumas coisas de linha de cache e precisava escrever uma função de plataforma cruzada. Eu o comprometi com um repositório do github em https://github.com/NickStrupat/CacheLineSize , ou você pode simplesmente usar a fonte abaixo. Sinta-se livre para fazer o que quiser com ele.

#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
Nick Strupat
fonte
15
Talvez seja melhor usar o sysconf (_SC_LEVEL1_DCACHE_LINESIZE) para linux.
Matt
@ Mat porque? Apenas curioso :-).
User35915
31

No x86, você pode usar a instrução CPUID com a função 2 para determinar várias propriedades do cache e do TLB. A análise da saída da função 2 é um pouco complicada, por isso, consultarei a seção 3.1.3 da Identificação do processador Intel e a instrução CPUID (PDF).

Para obter esses dados do código C / C ++, você precisará usar assembly embutido, intrínsecas do compilador ou chamar uma função de assembly externo para executar a instrução CPUID.

Adam Rosenfield
fonte
alguém sabe sobre como fazer isso com outros processadores com cache embutido?
paxos1977
3
@ceretullis: Errr ... o x86 foi construído em cache. Quais "outros processadores" você está procurando especificamente? O que você está pedindo depende da plataforma.
Billy ONeal
9

Se você estiver usando SDL2, poderá usar esta função:

int SDL_GetCPUCacheLineSize(void);

Que retorna o tamanho do tamanho da linha de cache L1, em bytes.

Na minha máquina x86_64, executando este trecho de código:

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

Produz CacheLineSize = 64

Sei que estou um pouco atrasado, mas apenas adicionando informações para futuros visitantes. A documentação SDL atualmente diz que o número retornado está em KB, mas na verdade está em bytes.

negamartin
fonte
Oh meu isso é realmente útil. Eu vou escrever algum jogo em SDL2 assim que este vai ser realmente útil
Nicholas Humphrey
7

Na plataforma Windows:

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

A função GetLogicalProcessorInformation fornecerá características dos processadores lógicos em uso pelo sistema. Você pode percorrer o SYSTEM_LOGICAL_PROCESSOR_INFORMATION retornado pela função procurando entradas do tipo RelationCache. Cada entrada contém uma ProcessorMask que informa a quais processadores a entrada se aplica e, no CACHE_DESCRIPTOR, informa qual tipo de cache está sendo descrito e qual o tamanho da linha de cache para esse cache.

Lorenzo Boccaccia
fonte
4

O ARMv6 e superior tem C0ou o Registro de tipo de cache. No entanto, está disponível apenas no modo privilegiado.

Por exemplo, no Manual de referência técnica Cortex ™ -A8 :

O objetivo do Registro de tipo de cache é determinar o comprimento mínimo da linha do cache de instruções e dados em bytes para permitir que um intervalo de endereços seja invalidado.

O Registro do tipo de cache é:

  • um registro somente leitura
  • acessível apenas nos modos privilegiados.

O conteúdo do Registro de tipo de cache depende da implementação específica. A Figura 3-2 mostra o arranjo de bits do Registro de tipo de cache ...


Não assuma que o processador ARM possui um cache (aparentemente, alguns podem ser configurados sem um). A maneira padrão de determinar isso é via C0. No ARM ARM , página B6-6:

No ARMv6, o registro de Tipo de cache do coprocessador de controle do sistema é o método obrigatório para definir os caches L1, consulte Registro de tipo de cache na página B6-14. É também o método recomendado para variantes anteriores da arquitetura. Além disso, Considerações para níveis adicionais de cache na página B6-12 descrevem diretrizes de arquitetura para suporte ao cache de nível 2.

jww
fonte
3

Você também pode tentar fazê-lo programaticamente medindo algum tempo. Obviamente, nem sempre será tão preciso quanto a CPU e os gostos, mas é mais portátil. ATLAS faz isso em seu estágio de configuração, você pode querer olhar para ele:

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

David Cournapeau
fonte