Страницы

Поиск по вопросам

воскресенье, 8 декабря 2019 г.

Сравнение эффективности потоков C++ и файлов C

#cpp #c #windows #visual_cpp #console


Навеяно вопросом о том, что следует использовать - потоки или файловые функции, и
что потоки обычно медленнее.

Набросал тестовую программу (код ниже), испытал на Open Watcom и Visual C++ 2015.
Сравниваются результаты вывода в консольное окно и в файл функциями для работы с потоками
и с файлами. Чтоб работало со старым Watcom, для замера использовал clock(), попутно
выяснилось, что в OW рекомендованная в упомянутом вопросе функция ios::sync_with_stdio()
без параметров и obsolete, так что для этого компилятора ее убрал.

Проверял под Windows 7 x64. Вопросов, собственно, два - а что делается у других компиляторов
и операционных систем, и как, собственно, можно ускорить вывод - как консольный вообще,
так и потоковый до уровня функций C. Есть ли какие-то варианты оптимизации? Чем обусловлен
наблюдаемый разброс?

Вот код:

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

clock_t bench(void(*func)())
{
    clock_t start = clock();
    func();
    clock_t stop = clock();
    return stop - start;
}

const int Count = 100000;

vector dv;
vector    iv;

FILE * outfile = 0;
ofstream * outstream = 0;

void printf_console()
{
    for(int i = 0; i < Count; ++i)
        printf("%d %lf ",iv[i],dv[i]);
}

void printf_file()
{
    for(int i = 0; i < Count; ++i)
        fprintf(outfile, "%d %lf ",iv[i],dv[i]);
}

void stream_console()
{
    for(int i = 0; i < Count; ++i)
        cout << iv[i] << " " << dv[i] << " ";
}

void stream_file()
{
    for(int i = 0; i < Count; ++i)
        *outstream << iv[i] << " " << dv[i] << " ";
}

int main(int argc, const char * argv[])
{
    for(int i = 0; i < Count; ++i)
    {
        dv.push_back(rand()/double(RAND_MAX));
        iv.push_back(rand());
    }

    outfile = fopen("test.dat","wt");
    outstream = new ofstream("test.stream");

    clock_t out_printf_console = bench(printf_console);
    clock_t out_printf_file    = bench(printf_file);
    clock_t out_cout_sync      = bench(stream_console);
    clock_t out_stream_file    = bench(stream_file);
    ios::sync_with_stdio(false);
    clock_t out_cout_async     = bench(stream_console);
    ios::sync_with_stdio(true);
    clock_t out_cout_rsync     = bench(stream_console);


    cerr << "\n\n";
    cerr << "printf       console: " << setw(10) << out_printf_console << endl;
    cerr << "printf       file   : " << setw(10) << out_printf_file    << endl;
    cerr << "stream sync  console: " << setw(10) << out_cout_sync      << endl;
    cerr << "stream async console: " << setw(10) << out_cout_async     << endl;
    cerr << "stream rsync console: " << setw(10) << out_cout_rsync     << endl;
    cerr << "stream       file   : " << setw(10) << out_stream_file    << endl;

    delete outstream;
    fclose(outfile);
}


А вот результаты:

                    Open Watcom:    VC++ 2015:
printf       console:      16739         21806
printf       file   :         62            69
stream sync  console:      16723         87678
stream async console:      16754         86899
stream rsync console:      16692         87254
stream       file   :        141           150


P.S. Удивляет что в общем случае VC++ бьет Open Watcom, а здесь - капитально ему
проигрывает, в особенности при потоковом выводе в консоль.
    


Ответы

Ответ 1



@Harry, если интересны другие результаты. Windows 7 MinGW g++ 3.4.5 printf console: 4.43 printf file : 0.081 stream sync console: 18.262 stream async console: 1.093 stream rsync console: 1.176 stream file : 0.318 и в виртуалке VirtualBox на том же компе Linux avp-ubu1 3.13.0-85-generic #129-Ubuntu SMP Thu Mar 17 20:50:15 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux g++.real (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4 printf console: 0.11216 printf file : 0.072135 stream sync console: 0.152673 stream async console: 0.141306 stream rsync console: 0.141552 stream file : 0.070493 кстати о нем: avp@avp-ubu1:hashcode$ grep CPU /proc/cpuinfo model name : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz model name : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz model name : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz model name : Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz avp@avp-ubu1:hashcode$ Время в секундах, поскольку глядя на сырую разницу clocks я заподозрил, что значение CLOCKS_PER_SEC в этих системах разное, короче вывод делается так: cerr << "printf console: " << setw(10) << (out_printf_console / (double)CLOCKS_PER_SEC) << endl; (остальные аналогично). P.S. разброс значений времени при разных запусках (для интереса я запускал раз пять) наблюдается, но похоже не больше 10%.

Ответ 2



Первое. С таким подходом к измерению времени можно намерять такие интересные вещи, как погоду на Марсе, или влажность пяток певицы Монеточки. Современная многозадачная система может внезапно захотеть в фоновом режиме перекинуть пару-тройку страниц с диска в RAM - вот вам и разброс времени. Современный CPU может решить, что ему скучно работать на одной частоте, и культурненько ее снизить. Или поднять. Вон какое количество копий поломано об одно только измерение времени. Попробуйте повторить тесты из известной публикации, тогда ценность будет выше.

Ответ 3



Разброс, возможно, обусловлен реализацией библиотеки. Конечно (ИМХО) более объективный результат - не одиночный вызов, а прогон серии. В качестве эксперимента можно попробовать stl извне, типа STLPORT или EASTL.

Комментариев нет:

Отправить комментарий