Размер кэша строки 2-го уровня - C++

233
25 декабря 2017, 13:15

Здравствуйте. Я пишу программу для определения размера строки кэша второго уровня, пользовался статьей habrahabr.ru/post/93263. Но у меня получаются совершенно другие результаты. Через программу Coreinfo я узнал что размер строки первого и второго уровня у меня по 64 байта. Пока решил получить хотя бы размер строки первого уровня, но какие-то совершенно неадекватные результаты получаются.

#include "stdafx.h"
#include <time.h>
#include <iostream>
#include <string>

using namespace std;

int main()
{
    int t;
    const int N = 8000;
    volatile int arr[N];
    unsigned int A;
    char ask1 = 'y';
    srand(time(NULL));
    while (ask1 == 'y')
    {
        for (int j = 0; j < N; j++)
            arr[j] = rand();
        for (int i = 1; i <= 64; i++)
        {
            A = clock();
            for (int k = 0; k < 100000; k++)
                for (int j = 0; j < N; j += i)
                {
                    t = arr[j];
                }
            //cout << i << "\tstep, time\t" << clock() - A << '\t' << t << endl;
            arr[i] = (clock() - A); //Вместо печати, чтобы не рушить кэш, я решил занести время выполнения в тот же самый массив, а потом его вывести
        }
        for (int i = 1; i <= 64; i++)
            cout << i << "\tstep, time\t" << arr[i] << endl;
        cout << "Repeat?(y/n): ";
        cin >> ask1;
        cout << endl;
    }
    /**/

    const int n = 1600000000;
    int l;
    unsigned int a;
    char ask = 'y';
    srand(time(NULL)); //это просто для рандома, чтобы он был разный, хотя тут мне это и не особо нужно
    while (ask == 'y')
    {
        volatile int byte8[2];
        for (int j = 0; j < 2; j++)
            byte8[j] = rand(); //рандомим массив
        a = clock();//записываем время до циклов считывания массива
        for (int k = 0; k < n / 2; k++) /*делим n на количество повторений внутреннего цикла, чтобы везде в
                                        сумме получилось одинаковое число повторений */
            for (int i = 0; i < 2; i++)
                l = byte8[i];
        cout << size(byte8) * 4 << "\tbytes\t" << clock() - a << endl; //выводим количество ms понадобившихся для считывания
                                                                       //далее повторяем то же самое для массивов большей длинны

        volatile int byte16[4];
        for (int j = 0; j < 4; j++)
            byte16[j] = rand();
        a = clock();
        for (int k = 0; k < n / 4; k++)
            for (int i = 0; i < 4; i++)
                l = byte16[i];
        cout << size(byte16) * 4 << "\tbytes\t" << clock() - a << endl;
        volatile int byte32[8];
        for (int j = 0; j < 8; j++)
            byte32[j] = rand();
        a = clock();
        for (int k = 0; k < n / 8; k++)
            for (int i = 0; i < 8; i++)
                l = byte32[i];
        cout << size(byte32) * 4 << "\tbytes\t" << clock() - a << endl;
        /*
        int byte60[15];
        for (int j = 0; j < 15; j++)
        byte60[j] = rand();
        a = clock();
        for (int k = 0; k < n / 15; k++)
        for (int i = 0; i < 15; i++)
        l = byte60[i];
        cout << size(byte60) * 4 << "\tbytes\t" << clock() - a << endl;
        */
        volatile int byte64[16];
        for (int j = 0; j < 16; j++)
            byte64[j] = rand();
        a = clock();
        for (int k = 0; k < n / 16; k++)
            for (int i = 0; i < 16; i++)
                l = byte64[i];
        cout << size(byte64) * 4 << "\tbytes\t" << clock() - a << endl;
        /*
        int byte68[17];
        for (int j = 0; j < 17; j++)
        byte68[j] = rand();
        a = clock();
        for (int k = 0; k < n / 17; k++)
        for (int i = 0; i < 17; i++)
        l = byte68[i];
        cout << size(byte68) * 4 << "\tbytes\t" << clock() - a << endl;
        */
        volatile int byte96[24];
        for (int j = 0; j < 24; j++)
            byte96[j] = rand();
        a = clock();
        for (int k = 0; k < n / 24; k++)
            for (int i = 0; i < 24; i++)
                l = byte96[i];
        cout << size(byte96) * 4 << "\tbytes\t" << clock() - a << endl;
        volatile int byte128[32];
        for (int j = 0; j < 32; j++)
            byte128[j] = rand();
        a = clock();
        for (int k = 0; k < n / 32; k++)
            for (int i = 0; i < 32; i++)
                l = byte128[i];
        cout << size(byte128) * 4 << "\tbytes\t" << clock() - a << endl;
        volatile int byte192[48];
        for (int j = 0; j < 48; j++)
            byte192[j] = rand();
        a = clock();
        for (int k = 0; k < n / 48; k++)
            for (int i = 0; i < 48; i++)
                l = byte192[i];
        cout << size(byte192) * 4 << "\tbytes\t" << clock() - a << endl;
        volatile int byte256[64];
        for (int j = 0; j < 64; j++)
            byte256[j] = rand();
        a = clock();
        for (int k = 0; k < n / 64; k++)
            for (int i = 0; i < 64; i++)
                l = byte256[i];
        cout << size(byte256) * 4 << "\tbytes\t" << clock() - a << endl;
        volatile int byte512[128];
        for (int j = 0; j < 128; j++)
            byte512[j] = rand();
        a = clock();
        for (int k = 0; k < n / 128; k++)
            for (int i = 0; i < 128; i++)
                l = byte512[i];
        cout << size(byte512) * 4 << "\tbytes\t" << clock() - a << endl;

        cout << "Repeat?(y/n): ";
        cin >> ask;
        cout << endl;
    }
    system("pause");
    return 0;
}

Дело в том, что мне нельзя пользоваться функциями типа GetLogicalProcessorInformation, мне нужно определить тестом. Запускаю в Visual Studio 2017 с конфигурацией на Release

Answer 1

По первому циклу, массив слишком маленький (8000*4<32К): он полностью помещается в кеше L1, а потом снова и снова молотится ЦП без обращения к памяти. Поэтому время, как и ожидается, обратно пропорционально i.

Пример корректного варианта:

(Си; amd64; требует 1G+ памяти)

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <assert.h>
typedef uint64_t my_int_t;
void mesureArrayMult (my_int_t *arr, size_t sz, size_t step) {
    clock_t start_time = clock();
    for (size_t i = 0; i < sz; i += step) {
        arr[i]*=i;
    }
    double work_time_us = (clock() - start_time) * (1000. / CLOCKS_PER_SEC);
    printf ("%4zd (%4zd): %7.3lfus\n", step, sizeof(my_int_t) * step, work_time_us);
}
int main()
{
    const size_t sz = 128*1024*1024;
    my_int_t *arr = (my_int_t *) malloc (sizeof(arr[0]) * sz);
    assert(arr);
    memset (arr, 1, sizeof(arr[0])*sz);
    size_t i=1;
    for ( ; i< 8; i+= 1) { mesureArrayMult( arr, sz, i ); }
    // for ( ; i<16; i+= 2) { mesureArrayMult( arr, sz, i ); }
    for ( ; i<=1024; i*=2) { mesureArrayMult( arr, sz, i ); }
    free (arr);
    return 0;
}

Вообще говоря, излишняя оптимизация испортит результат не должна, но дабы быть спокойным по этому поводу, желательно запретить встраивание (-fno-inline на gcc и подобных).

Вывод, как и ожидаемо, для шага <=64 байта примерно одинаков, для бо́льших — обратно пропорционален шагу(со значительной погрешностью):

   1 (   8): 122.007us
   2 (  16): 122.161us
   3 (  24): 120.396us
   4 (  32): 119.503us
   5 (  40): 120.545us
   6 (  48): 121.657us
   7 (  56): 121.623us
   8 (  64): 122.529us
  16 ( 128):  82.049us
  32 ( 256):  46.452us
  64 ( 512):  20.682us
 128 (1024):   9.905us
 256 (2048):   5.207us
 512 (4096):   2.986us
1024 (8192):   1.570us
READ ALSO
Не запускается JAR файл

Не запускается JAR файл

Написал JavaFX приложение, в настройках проекта настроил Artifacts, и сделал Build ArtifactsJar Файл создался, но не запускается

232
JSOUP+ Picasso. Парсинг картинок

JSOUP+ Picasso. Парсинг картинок

Привет всем молодым перспективным программистамМоя проблема обстоит так: На скриншоте у меня выделен код который отвечает за(как я понял)...

208
Как сменить Javascript на Java в Intellij idea?

Как сменить Javascript на Java в Intellij idea?

Когда нажимаю "new", то там можно создать только файл js, а мне нужно javaКак это исправить?

177