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

Я хотел бы, чтобы моя программа считывала размер строки кэша процессора, на котором она работает в C++.

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

Для Linux я мог прочитать содержимое /proc/cpuinfo и разобрать строку, начинающуюся с cache_alignment. Может быть, есть лучший способ, связанный с вызовом API.

Для Windows я просто понятия не имею.

8 ответов

Решение

На винде

#include <Windows.h>
#include <iostream>

using std::cout; using std::endl;

int main()
{
    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);
    cout << "Page Size Is: " << systemInfo.dwPageSize;
    getchar();
}

В линуксе

http://linux.die.net/man/2/getpagesize

На Win32, GetLogicalProcessorInformation вернет вам SYSTEM_LOGICAL_PROCESSOR_INFORMATION который содержит CACHE_DESCRIPTOR, в котором есть нужная вам информация.

В Linux попробуйте библиотеку proccpuinfo, независимый от архитектуры C API для чтения /proc/cpuinfo

Похоже, что по крайней мере в Unix SCO ( http://uw714doc.sco.com/en/man/html.3C/sysconf.3C.html) есть _SC_CACHE_LINE для sysconf. Возможно, на других платформах есть нечто подобное?

Для x86 инструкция CPUID. Быстрый поиск в Google показывает некоторые библиотеки для win32 и C++. Я использовал CPUID через встроенный ассемблер.

Еще немного информации:

Вот пример кода для тех, кто задается вопросом, как использовать функцию в принятом ответе:

#include <new>
#include <iostream>
#include <Windows.h>


void ShowCacheSize()
{
    using CPUInfo = SYSTEM_LOGICAL_PROCESSOR_INFORMATION;
    DWORD len = 0;
    CPUInfo* buffer = nullptr;

    // Determine required length of a buffer
    if ((GetLogicalProcessorInformation(buffer, &len) == FALSE) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
    {
        // Allocate buffer of required size
        buffer = new (std::nothrow) CPUInfo[len]{ };

        if (buffer == nullptr)
        {
            std::cout << "Buffer allocation of " << len << " bytes failed" << std::endl;
        }
        else if (GetLogicalProcessorInformation(buffer, &len) != FALSE)
        {
            for (DWORD i = 0; i < len; ++i)
            {
                // This will be true for multiple returned caches, we need just one
                if (buffer[i].Relationship == RelationCache)
                {
                    std::cout << "Cache line size is: " << buffer[i].Cache.LineSize << " bytes" << std::endl;
                    break;
                }
            }
        }
        else
        {
            std::cout << "ERROR: " << GetLastError() << std::endl;
        }

        delete[] buffer;
    }
}

Я думаю тебе нужно NtQuerySystemInformation от ntdll.dll,

Если поддерживается вашей реализацией, C++17std::hardware_destructive_interference_sizeдаст вам верхнюю границу (и..._constructive_...нижняя граница), принимая во внимание такие вещи, как аппаратная предварительная выборка пар строк.

Но это константы времени компиляции, поэтому они не могут быть правильными для всех микроархитектур для ISA, которые допускают разные размеры строк. (например, более старые процессоры x86, такие как Pentium III, имели 32-байтовые строки, но все более поздние процессоры x86 использовали 64-байтовые строки, включая все x86-64. Теоретически возможно, что некоторые будущие микроархитектуры будут использовать 128-байтовые строки, но многопоточные. двоичные файлы, настроенные для 64-байтовых строк, широко распространены, поэтому для x86 это маловероятно.)

По этой причине некоторые текущие реализации предпочитают вообще не реализовывать эту функцию C++. GCC реализует это, а clang — нет (Godbolt). Он становится частью ABI, когда код использует его в макетах структур, поэтому компиляторы не могут изменить его в будущем, чтобы соответствовать будущим процессорам для той же цели.


GCC определяет как конструктивное, так и деструктивное как64x86-64, пренебрегая деструктивными помехами, которые может вызвать предварительная выборка смежных строк, например, в семействе Intel Sandybridge. Это не так катастрофично, как ложное совместное использование в строке кэша в случае высокой конкуренции, поэтому вы можете использовать только 64-байтовое выравнивание для разделения объектов, к которым разные потоки будут обращаться независимо.

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