Почему у функции printf () гораздо больше процессорного времени при использовании подсистемы MSYS2 mingw64, чем при использовании подсистемы msys2 или Visual Studio? - PullRequest
0 голосов
/ 10 июля 2020

Я изучаю C, и последние несколько дней я потратил на понимание того, как получить процессорное время данного процесса или фрагмента кода. Я использую Windows 10 x64, и у меня установлен MSYS2 с настроенными подсистемами «msys2» и «mingw64», поэтому я могу сравнить код, необходимый для этой задачи, как в Windows, так и в совместимом с POSIX система (или, по крайней мере, ее эмуляция). Кроме того, я установил Visual Studio Community 2019, чтобы увидеть, есть ли разница в производительности между ним и mingw64 с точки зрения процессорного времени для запуска простого l oop с printf ().

Это POSIX подход, который я взял из одного из комплектов CS50 Course. Для этого я использовал подсистему msys2 для компиляции:

#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>

double calculate(const struct rusage *b, const struct rusage *a);

int main(void)
{
    struct rusage before, after;

    getrusage(RUSAGE_SELF, &before);

    // Activity to be timed
    for(int i = 0; i < 100000; i++)
    {
        printf("%i\n", i);
    }    

    getrusage(RUSAGE_SELF, &after);

    double time = calculate(&before, &after);

    printf("Time: %.2f\n", time);
}

double calculate(const struct rusage *b, const struct rusage *a)
{
    if (b == NULL || a == NULL)
    {
        return 0.0;
    }
    else
    {
        return ((((a->ru_utime.tv_sec * 1000000 + a->ru_utime.tv_usec) -
                  (b->ru_utime.tv_sec * 1000000 + b->ru_utime.tv_usec)) +
                 ((a->ru_stime.tv_sec * 1000000 + a->ru_stime.tv_usec) -
                  (b->ru_stime.tv_sec * 1000000 + b->ru_stime.tv_usec)))
                / 1000000.0);
    }
}

И здесь используется Windows API. Я скомпилировал это, используя как подсистему mingw64 (g cc), так и Visual Studio:

#Include <stdio.h>
#include <windows.h>

int GetProcessCPUTime(HANDLE hProcess, double* cpu_time);

int main(void)
{
    double before;
    if (GetProcessCPUTime(GetCurrentProcess(), &before) == 0)
    {
        return 1;
    }    

    // Activity to be timed 
    for (int i = 0; i < 100000; i++)
    {
        printf("%i\n", i);
    }

    double after;
    if (GetProcessCPUTime(GetCurrentProcess(), &after) == 0)
    {
        return 1;
    }

    double total = after - before;

    printf("Time: %.2f\n", total);
}

int GetProcessCPUTime(HANDLE hProcess, double* cpu_time)
{
    FILETIME creation, exit, kernel, user;

    if (GetProcessTimes(hProcess, &creation, &exit, &kernel, &user) == 0)
    {
        return 0;
    }

    ULARGE_INTEGER kernel_t;
    ULARGE_INTEGER user_t;
    kernel_t.LowPart = kernel.dwLowDateTime;
    kernel_t.HighPart = kernel.dwHighDateTime;
    user_t.LowPart = user.dwLowDateTime;
    user_t.HighPart = user.dwHighDateTime;

    *cpu_time = (kernel_t.QuadPart + user_t.QuadPart) / 10000000.0;
    return 1;
}

Моя гипотеза заключалась в том, что подход POSIX будет работать медленнее, потому что он должен использовать msys-2.0.dll, и и mingw64, и MSV C будут быстрее и с аналогичными результатами. Но это было не так. Результаты были (в среднем): msys2 3s mingw64 8s Visual Studio 1s

Я удивлен. Почему mingw64 такой медленный? Разве он не использует библиотеку времени выполнения Windows C? Является ли мой подход с использованием Windows API эквивалентом функции POSIX getrusage ()? Если это актуально, я использовал cmd для запуска всех трех исполняемых файлов.

Спасибо!

...