Программно получить размер строки кэша?

Все платформы приветствуются, пожалуйста, укажите платформу для вашего ответа.

Аналогичный вопрос: Как программно получить размер страницы кэша ЦП в C++?

9 ответов

В 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), а также какие процессоры разделяют этот кеш. Это очень полезно, если вы занимаетесь многопоточным программированием с общими данными (вы получите лучшие результаты, если потоки, совместно использующие данные, также совместно используют кеш).

В Linux посмотрите на sysconf(3).

sysconf (_SC_LEVEL1_DCACHE_LINESIZE)

Вы также можете получить его из командной строки, используя getconf:

$ getconf LEVEL1_DCACHE_LINESIZE
64

Я работал над некоторыми строками кеша и мне нужно было написать кроссплатформенную функцию. Я отправил его в репозиторий github по адресу https://github.com/NickStrupat/CacheLineSize, или вы можете просто использовать приведенный ниже источник. Не стесняйтесь делать все, что вы хотите с ним.

#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 вы можете использовать инструкцию CPUID с функцией 2 для определения различных свойств кэша и TLB. Анализ выходных данных функции 2 несколько сложен, поэтому я отсылаю вас к разделу 3.1.3 " Идентификация процессора Intel" и "Инструкция CPUID" (PDF).

Чтобы получить эти данные из кода C/C++, вам потребуется использовать встроенную сборку, встроенные функции компилятора или вызвать функцию внешней сборки для выполнения инструкции CPUID.

Если вы используете SDL2, вы можете использовать эту функцию:

int SDL_GetCPUCacheLineSize(void);

Который возвращает размер строки кэша L1 в байтах.

На моем компьютере с архитектурой x86_64 выполняется следующий фрагмент кода:

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

Производит CacheLineSize = 64

Я знаю, что немного опаздываю, но просто добавляю информацию для будущих посетителей. Документация SDL в настоящее время говорит, что возвращаемое число находится в килобайтах, но на самом деле это в байтах.

Вы можете использовать std::hardware_destructive_interference_size начиная с C++17.
Его определяют как:

Минимальное смещение между двумя объектами, чтобы избежать ложного разделения. Гарантируется как минимум alignof(std::max_align_t)

На платформе Windows:

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

Функция GetLogicalProcessorInformation предоставит вам характеристики логических процессоров, используемых системой. Вы можете просмотреть SYSTEM_LOGICAL_PROCESSOR_INFORMATION, возвращаемую функцией, для поиска записей типа RelationCache. Каждая такая запись содержит ProcessorMask, который сообщает вам, к какому процессору (-ам) относится данная запись, а в CACHE_DESCRIPTOR он сообщает, какой тип кэша описывается и насколько велика строка кэша для этого кэша.

ARMv6 и выше имеет C0 или регистр типа кэша. Тем не менее, он доступен только в привилегированном режиме.

Например, из Технического справочного руководства Cortex™-A8:

Назначение регистра типа кэша состоит в том, чтобы определить минимальную длину строки команд и кэша данных в байтах, чтобы разрешить аннулирование диапазона адресов.

Регистр типа кэша:

  • регистр только для чтения
  • доступно только в привилегированных режимах.

Содержимое регистра типа кэша зависит от конкретной реализации. Рисунок 3-2 показывает расположение битов регистра типа кэша...


Не думайте, что процессор ARM имеет кеш (очевидно, некоторые могут быть настроены без него). Стандартный способ определить это через C0, От ARM ARM, стр. B6-6:

Начиная с ARMv6, регистр типа кэша сопроцессора управления системой является обязательным методом для определения кэшей L1, см. Регистр типа кэша на странице B6-14. Это также рекомендуемый метод для более ранних вариантов архитектуры. Кроме того, Рекомендации по дополнительным уровням кэша на стр. B6-12 описывают рекомендации по архитектуре для поддержки уровня 2 кэша.

Вы также можете попытаться сделать это программно, измерив некоторое время. Очевидно, что он не всегда будет таким же точным, как cpuid и подобные, но он более переносим. ATLAS делает это на этапе настройки, вы можете посмотреть на это:

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

Другие вопросы по тегам