Czy programowo uzyskać rozmiar linii pamięci podręcznej?

177

Witamy na wszystkich platformach, proszę określić platformę dla swojej odpowiedzi.

Podobne pytanie: Jak programowo uzyskać rozmiar strony pamięci podręcznej procesora w C ++?

paxos1977
źródło
8
FWIW, C ++ 17 zapewni przybliżenie w czasie kompilacji: stackoverflow.com/questions/39680206/ ...
GManNickG
pomijając C / C ++, jeśli nie masz nic przeciwko używaniu asemblera do uzyskania takich informacji, możesz rzucić okiem (rozwijając informacje z odpowiedzi negamartin) na kod źródłowy SDL_GetCPUCacheLineSizefunkcji SDL2 , a następnie przyjrzeć się, cpuid macroktóry ma kod źródłowy asemblera dla każdego modelu procesora. Możesz zajrzeć na stronę imgur.com/a/KP57m6s lub bezpośrednio zerknąć na źródło.
haxpor

Odpowiedzi:

186

W Linuksie (z całkiem nowym jądrem) możesz pobrać te informacje z / sys:

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

Ten katalog ma podkatalog dla każdego poziomu pamięci podręcznej. Każdy z tych katalogów zawiera następujące pliki:

coherency_line_size
level
number_of_sets
physical_line_partition
shared_cpu_list
shared_cpu_map
size
type
ways_of_associativity

Daje to więcej informacji o pamięci podręcznej, niż kiedykolwiek miałbyś nadzieję, w tym rozmiar cacheline ( coherency_line_size), a także to, które procesory współużytkują tę pamięć podręczną. Jest to bardzo przydatne, jeśli robisz programowanie wielowątkowe z udostępnionymi danymi (uzyskasz lepsze wyniki, jeśli wątki udostępniające dane również współużytkują pamięć podręczną).

spinfire
źródło
4
który z plików zawiera rozmiar linii pamięci podręcznej? Zakładam coherency_line_size? lub Physical_line_partition?
paxos1977
27
coherency_line_size
spinfire
6
Dla pewności: to jest w bajtach, tak?
Jakub M.
6
Tak, coherency_line_size jest w bajtach.
John Zwinck
4
@android: Używam maszyny fedora-18 x64 z procesorem core-i5. cat /sys/devices/system/cpu/cpu0/cache/index0/coherency_line_sizewraca 64do mojego systemu. To samo dotyczy folderów index1,2,3.
Abid Rahman K.
141

W Linuksie spójrz na sysconf (3).

sysconf (_SC_LEVEL1_DCACHE_LINESIZE)

Możesz go również pobrać z wiersza poleceń za pomocą getconf:

$ getconf LEVEL1_DCACHE_LINESIZE
64
ob.
źródło
4
proste odpowiedzi są po prostu najlepsze!
FrankH.
3
@warunapww Jest w bajtach.
Maarten Bamelis
Wreszcie! mam nadzieję, że więcej facetów zobaczy tę odpowiedź, aby zaoszczędzić czas.
elinx
118

Pracowałem nad pewnymi kwestiami dotyczącymi linii pamięci podręcznej i potrzebowałem napisać funkcję międzyplatformową. Przekazałem to do repozytorium github pod adresem https://github.com/NickStrupat/CacheLineSize lub możesz po prostu użyć źródła poniżej. Możesz z nim robić, co chcesz.

#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
źródło
15
Może lepiej będzie użyć sysconf (_SC_LEVEL1_DCACHE_LINESIZE) dla Linuksa.
Matt
@Matt why? Po prostu ciekawy :-).
user35915
31

Na x86 można użyć instrukcji CPUID z funkcją 2 do określenia różnych właściwości pamięci podręcznej i TLB. Przetwarzanie danych wyjściowych funkcji 2 jest nieco skomplikowane, dlatego odsyłam do sekcji 3.1.3 dotyczącej identyfikacji procesora Intel i instrukcji CPUID (PDF).

Aby uzyskać te dane z kodu C / C ++, musisz użyć zestawu wbudowanego, elementów wewnętrznych kompilatora lub wywołać zewnętrzną funkcję asemblera w celu wykonania instrukcji CPUID.

Adam Rosenfield
źródło
ktoś wie, jak to zrobić z innymi procesorami z wbudowaną pamięcią podręczną?
paxos1977
3
@ceretullis: Errr ... x86 ma wbudowaną pamięć podręczną. Jakich „innych procesorów” szukasz? To, o co prosisz, zależy od platformy.
Billy ONeal
9

Jeśli używasz SDL2, możesz użyć tej funkcji:

int SDL_GetCPUCacheLineSize(void);

Zwraca rozmiar linii pamięci podręcznej L1 w bajtach.

Na moim komputerze x86_64 uruchamiam ten fragment kodu:

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

Produkuje CacheLineSize = 64

Wiem, że jestem trochę spóźniony, ale dodam tylko informacje dla przyszłych gości. Dokumentacja SDL mówi obecnie, że zwracana liczba jest w KB, ale w rzeczywistości jest to w bajtach.

negamartin
źródło
Ojej, to jest naprawdę pomocne. Mam zamiar napisać jakąś grę w SDL2, więc będzie to naprawdę przydatne
Nicholas Humphrey
7

Na platformie Windows:

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

Funkcja GetLogicalProcessorInformation podaje charakterystykę procesorów logicznych używanych przez system. Możesz przejść SYSTEM_LOGICAL_PROCESSOR_INFORMATION zwrócone przez funkcję szukającą wpisów typu RelationCache. Każdy taki wpis zawiera maskę procesora, która mówi ci, do którego procesora (-ów) odnosi się wpis, aw CACHE_DESCRIPTOR, mówi ci, jaki typ pamięci podręcznej jest opisywany i jak duża jest linia pamięci podręcznej dla tej pamięci podręcznej.

Lorenzo Boccaccia
źródło
4

ARMv6 i nowsze wersje mają C0lub Rejestr typu pamięci podręcznej. Jednak jest dostępny tylko w trybie uprzywilejowanym.

Na przykład w Podręczniku technicznym Cortex ™ -A8 :

Celem rejestru typu pamięci podręcznej jest określenie minimalnej długości linii pamięci podręcznej instrukcji i danych w bajtach, aby umożliwić unieważnienie zakresu adresów.

Rejestr typu pamięci podręcznej to:

  • rejestr tylko do odczytu
  • dostępne tylko w trybach uprzywilejowanych.

Zawartość rejestru typu pamięci podręcznej zależy od konkretnej implementacji. Rysunek 3-2 przedstawia rozmieszczenie bitów rejestru typu pamięci podręcznej ...


Nie zakładaj, że procesor ARM ma pamięć podręczną (najwyraźniej niektóre można skonfigurować bez niej). Standardowym sposobem określenia tego jest metoda C0. Z ARM ARM , strona B6-6:

Począwszy od ARMv6, rejestr typu pamięci podręcznej koprocesora kontroli systemu jest obowiązkową metodą definiowania pamięci podręcznych L1, patrz Rejestr typu pamięci podręcznej na str. B6-14. Jest to również zalecana metoda dla wcześniejszych wariantów architektury. Ponadto Rozważania dotyczące dodatkowych poziomów pamięci podręcznej na stronie B6-12 zawierają wytyczne dotyczące architektury dla obsługi pamięci podręcznej poziomu 2.

jww
źródło
3

Możesz również spróbować zrobić to programowo, mierząc czas. Oczywiście nie zawsze będzie tak precyzyjny jak cpuid i tym podobne, ale jest bardziej przenośny. ATLAS robi to na etapie konfiguracji, warto się temu przyjrzeć:

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

David Cournapeau
źródło