C++ - volatile при замере времени

98
26 октября 2021, 04:30

Есть вот такой вот код, замеряющий время работы трех разных функции умножения матриц и записывающий их в файл:

#include "building_mode.h"
#ifdef TIMING_MODE
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <ctime>
#include "matrix.h"
#include "matrix_math.h"
unsigned long long tick()
{
    unsigned long long d;
    __asm__ __volatile__ ("rdtsc" : "=A" (d) );
    return d;
}
void fill_matrix(Matrix &m)
{
    for (unsigned i = 0; i < m.height(); ++i)
        for (unsigned j = 0; j < m.width(); ++j)
            m[i][j] = rand();
}
int main()
{
    srand(time(NULL));
    std::ofstream fout("time_results.csv");
    fout << "Size;Simple;Vinograd;Optimized Vinograd\n";
    Matrix first, second, result;
    unsigned long long t1, t2, t3, t4;
    for (unsigned i = 100, divider = 1; i <= 1000; i += 100, ++divider)
    {
        std::cout <<"Timetesting on " << i <<'x' << i <<"...\n";
        unsigned long long ts = 0, tv = 0, tvo = 0;
        first.reset_height(i);
        first.reset_width(i);
        second.reset_height(i);
        second.reset_width(i);
        fill_matrix(first);
        fill_matrix(second);
        unsigned limit = 10 / divider;
        for (unsigned j = 0; j < limit; ++j)
        {
            t1 = tick();
            simple_multiplication(result, first, second);
            t2 = tick();
            vinograd_multiplication(result, first, second);
            t3 = tick();
            vinograd_optimized_multiplication(result, first, second);
            t4 = tick();
            ts += t2 - t1;
            tv += t3 - t2;
            tvo += t4 - t3;
            if (!(t1 < t2 && t2 < t3 && t3 < t4))
                std::cout <<"achtung\n";
        }
        ts /= limit;
        tv /= limit;
        tvo /= limit;
        fout << i << ";" << ts << ";" << tv << ";" << tvo << "\n";
    }
    fout << ";;;\n";
    for (unsigned i = 101, divider = 1; i <= 1001; i += 100, ++divider)
    {
        std::cout <<"Timetesting on " << i <<'x' << i <<"...\n";
        unsigned long long ts = 0, tv = 0, tvo = 0;
        first.reset_height(i);
        first.reset_width(i);
        second.reset_height(i);
        second.reset_width(i);
        fill_matrix(first);
        fill_matrix(second);
        unsigned limit = 10 / divider;
        for (unsigned j = 0; j < limit; ++j)
        {
            t1 = tick();
            simple_multiplication(result, first, second);
            t2 = tick();
            vinograd_multiplication(result, first, second);
            t3 = tick();
            vinograd_optimized_multiplication(result, first, second);
            t4 = tick();
            ts += t2 - t1;
            tv += t3 - t2;
            tvo += t4 - t3;
        }
        ts /= limit;
        tv /= limit;
        tvo /= limit;
        fout << i << ";" << ts << ";" << tv << ";" << tvo << "\n";
    }
    std::cout <<"Finished timetesting\n";
}
#endif

В котором функция tick() взята давным-давно у преподавателя и должна выдавать прошедшее время в тиках, согласно ассемблерной инструкции rdtsc. Как я понял, ключевое слово __volatile__ здесь помогает избежать багов, связанных с оптимизацией, отключая кеширование полученного значения и заставляя c++ пересчитывать его каждый раз заново. Однако этот код более чем много раз выводит achtung, т.е. периодически не выполняется условие t1<t2<t3<t4, что портит все результаты замеров. Объясните, пожалуйста, почему это происходит, и как это исправить.
PS: функция изначально писалась под Си

READ ALSO
Передача string_view по ссылке или значению

Передача string_view по ссылке или значению

Как правильно передавать std::string_view в функцию, если не надо изменять строку?

179
Как компилировать быстрее?

Как компилировать быстрее?

Есть Incredibuild, но она вроде платная?

83
Предупреждение о неинициализированном массиве

Предупреждение о неинициализированном массиве

Как убрать предупреждение о неинициализированном массиве в следующем коде, ведь все элементы инициализированы?

241