Comments 80
Я бы с удовольствием посмотрел сравнение std::ostringstream с snprintf для форматирования строк.
А не отпугивает от потоков, кхм, некоторая многословность?
vs
+ во времена g++ 3.3-4.0 в ostringstream была утечка памяти — с тех пор отношусь к ним с большой подозрительностью
printf("%.2f\n", count * 100.0 / total);
vs
std::cout << std::setprecision(2) << std::fixed << count * 100.0 / total << std::endl
+ во времена g++ 3.3-4.0 в ostringstream была утечка памяти — с тех пор отношусь к ним с большой подозрительностью
В общем-то можно убрать std:: повсюду (добавив директиву ранее). Станет чуть короче.
Но вот со скоростью… мда…
Мы тут как-то свой printf делали (чтоб кидать дампы в обработчиках сигнала — где нежелательно, чтобы вдруг где-то malloc() в недрах вдруг вызвался, потому что будет «ой, всё!»). Структура то элементарна — очень простой ДКА — и уже можно по крайней мере целые числа и строки выводить.
Но вот добрались до флотов — и чтоб не городить огород попробовали самый простой метод, что на поверхности: вместо флота 1.99 — выводить целое 199, нарисовав точку после единицы (ну т.е. умножаем флот на precision, и выводим уже int, только в вывод впихиваем точку). Вот его как раз из любопытства забенчили по сравнению со стандартным printf.
Так вот такой бенч:
(UItoA — это наша собственная очень простая реализация; не стал приводить. Но там в самом деле всё просто :) ).
А результат любопытный:
printf — 54.69c (при этом вывелось 3556.232422)
«целое с точкой» — 1.376с (при этом вывелось 3556.232421)
Разница — в 40 раз!
Т.е. если вдруг нужно выводить не хитрые флоты с огромными экспонентами, а вот такие, обычные, и причём нужно выводить много и быстро — свой «велосипед» рулит!
Но вот со скоростью… мда…
Мы тут как-то свой printf делали (чтоб кидать дампы в обработчиках сигнала — где нежелательно, чтобы вдруг где-то malloc() в недрах вдруг вызвался, потому что будет «ой, всё!»). Структура то элементарна — очень простой ДКА — и уже можно по крайней мере целые числа и строки выводить.
Но вот добрались до флотов — и чтоб не городить огород попробовали самый простой метод, что на поверхности: вместо флота 1.99 — выводить целое 199, нарисовав точку после единицы (ну т.е. умножаем флот на precision, и выводим уже int, только в вывод впихиваем точку). Вот его как раз из любопытства забенчили по сравнению со стандартным printf.
Так вот такой бенч:
#ifdef USE_SPRINTF
void outf ( char* out, float arg )
{
sprintf ( out, "%f", arg );
}
const char * sName = "Using sprintf res=%s\n";
#else
void outf ( char* out, float arg )
{
unsigned int x = arg;
arg -=x;
UItoA ( &out, x);
*out++='.';
x=arg*1000000;
UItoA ( &out, x);
*out++='\0';
}
const char * sName = "Using own UItoA res=%s\n";
#endif
int main(int argc, char *argv[])
{
float b;
b=3556.2323;
char cout[100];
int i;
for (i=0; i<100000000; ++i)
outf(cout,b);
printf (sName,cout);
return 0;
}
(UItoA — это наша собственная очень простая реализация; не стал приводить. Но там в самом деле всё просто :) ).
А результат любопытный:
printf — 54.69c (при этом вывелось 3556.232422)
«целое с точкой» — 1.376с (при этом вывелось 3556.232421)
Разница — в 40 раз!
Т.е. если вдруг нужно выводить не хитрые флоты с огромными экспонентами, а вот такие, обычные, и причём нужно выводить много и быстро — свой «велосипед» рулит!
Реализация-то проприетарная?)
Могу посоветовать библиотеку stringencoders, в которой есть функции для преобразования чисел в строки:
code.google.com/p/stringencoders/wiki/PerformanceNumToA
code.google.com/p/stringencoders/wiki/NumToA
Работает значительно быстрее printf-семейства и лицензия MIT (на функции преобразования чисел в строки).
code.google.com/p/stringencoders/wiki/PerformanceNumToA
code.google.com/p/stringencoders/wiki/NumToA
Работает значительно быстрее printf-семейства и лицензия MIT (на функции преобразования чисел в строки).
Почему же?
code.google.com/p/sphinxsearch/source/browse/trunk/src/sphinxutils.cpp#1698
Вот, пожалуйста :).
code.google.com/p/sphinxsearch/source/browse/trunk/src/sphinxutils.cpp#1698
Вот, пожалуйста :).
крутяк, а я то думаю, почему практически во всем коде по обработке данных в нашей лабе, юзают scanf для чтения, когда есть cin!
надо будет посмотреть как на кластере уменьшится время обработки данных (36гб .txt) если поменять всё на std::stoi
надо будет посмотреть как на кластере уменьшится время обработки данных (36гб .txt) если поменять всё на std::stoi
Не забудьте только выключить синхронизацию, если читаете из cin, иначе будет медленно. (Если читаете из файла, то отключать не нужно).
То есть при считывании из файла данная директива отключения синхронизации бесполезна и не даёт прироста скорости? Или же вообще вредна становится? Что произойдёт, если я всё же включу её перед считыванием данных из файла?
Синхронизация включена по умолчанию только на стандартных потоках: cin, cerr, cout, clog. На обычных файлах синхронизация и так должна быть выключена.
Что произойдёт, если я всё же включу её перед считыванием данных из файла?Простите — но с чем именно вы собрались синхронизировать файловый поток? Для синхронизации требуется два объекта. cin синхронизирован с stdin, cout — с stdout, а с чем будет синхронизирован созданный вами объект?
Так а где же бенчмарк способа «читать данные большими кусками и дальше работать в памяти»?
походу, это std::istringstream + время на считывание
Готово! Номер 8, новый чемпион.
А как насчёт аналогичной замены getchar_unlocked() в Си на свою реализацию :)?
Что-нибудь вроде такого (я особо не оптимизировал, сорри):
#include <stdio.h>
long read_batched(long *out)
{
char buf[20];
long c, x = 0, neg = 0;
char *res = fgets(buf, sizeof(buf), stdin);
if (res == NULL) return 0;
while ((c = *(res++)) != 0) {
if ('0' <= c && c <= '9') {
x = x*10 + c - '0';
} else if (c == '-') {
neg = 1;
} else {
break;
}
}
*out = neg ? -x : x;
return 1;
}
int main()
{
long x;
long max = -1;
while (read_batched(&x)) {
if (x > max) max = x;
}
printf("%ld\n", max);
return 0;
}
Или, лучше, вот такого:
#include <stdio.h>
#include <unistd.h>
int main()
{
long max = -1;
char buf[655360];
long c, x = 0, neg = 0, n, i;
while ((n = read(0, buf, sizeof(buf))) > 0) {
for (i = 0; i < n; i++) {
c = buf[i];
if ('0' <= c && c <= '9') {
x = (x<<1) + (x<<3) + c - '0';
} else if (c == '-') {
neg = 1;
} else { // newline
if (x > max) max = x;
x = 0;
neg = 0;
}
}
}
printf("%ld\n", max);
return 0;
}
Ваш код — хороший пример того, что некоторые «классические» ручные оптимизации устарели, и только мешают компиляторам.
В вашем коде строка
компилируется в 3 инструкции lea:
тогда как более наивное
всего в 2 таких же инструкции
Поиграться можно тут: gcc.godbolt.org
(Кстати, clang выдаёт второй вариант кода в обоих случаях)
В вашем коде строка
x = (x<<1) + (x<<3) + c - '0';
компилируется в 3 инструкции lea:
leaq 0(,%rbx,8), %rcx
leaq (%rcx,%rbx,2), %rcx
leaq -48(%rax,%rcx), %rbx
тогда как более наивное
x = x*10 + c - '0';
всего в 2 таких же инструкции
leaq (%rbx,%rbx,4), %rcx
leaq -48(%rax,%rcx,2), %rbx
Поиграться можно тут: gcc.godbolt.org
(Кстати, clang выдаёт второй вариант кода в обоих случаях)
Производительность, как и ожидалось, самая лучшая:
10M -> 0.16 с
100M -> 1.80 с
Только писать парсер чего-то более сложного — замучаться.
10M -> 0.16 с
100M -> 1.80 с
Только писать парсер чего-то более сложного — замучаться.
По-моему главная проблема iostreams не в скорости, а в очень спорном синтаксесе, который можно спутать с битовым сдвигом.
Спутать это может только тот, кто ни разу не работал с потоками. Все же обычно ввод-вывод используется как оператор (то есть результат операции никуда не сохраняется) — а битовый сдвиг используется внутри выражения.
Ну да, спутать конечно, врядли, я скорее про то, что это выглядит странно. Выводить и вводить данные уже определенным в языке оператором побитового сдвига. Притомерно так же, еслиб, например, у строк был переопределен оператор деления, для чего-нибудь.
А вас не смущает, что для строк переопределен оператор "+" — то есть математического суммирования? Думаю, что вы просто привыкли к этому и не задумываетесь. А вот в PHP, например (не к ночи будет помянут), насколько я помню, строки конкатенируются оператором "."…
Почему выбрали '<<' и '>>'? Я в головы авторам STL не заглядывал, но думаю, идеи такие:
Парсер C++ (в отличие от Perl, например), не дает возможности придумать какой-то свой, новый оператор. Применяется то, что есть.
Это с одной стороны. А с другой, сами операторы побитового сдвига применяются довольно редко, в основном только в контексте суровой целочисленной арифметики, которая очень редко соседствует в коде с работой ввода-вывода. Разумеется, я тут говорю о программах серьезных, а не о студенческих лабах. Кроме того, знак '<<' прямо просится, чтобы его прочесть как «пропихнуть влево» и даже человеку, незнакомому с возможностью переопределять операторы в C++, очень легко понять, что означает
Что касается оператора деления для строк — а что, я бы, например, не прочь был посмотреть на
Почему выбрали '<<' и '>>'? Я в головы авторам STL не заглядывал, но думаю, идеи такие:
Парсер C++ (в отличие от Perl, например), не дает возможности придумать какой-то свой, новый оператор. Применяется то, что есть.
Это с одной стороны. А с другой, сами операторы побитового сдвига применяются довольно редко, в основном только в контексте суровой целочисленной арифметики, которая очень редко соседствует в коде с работой ввода-вывода. Разумеется, я тут говорю о программах серьезных, а не о студенческих лабах. Кроме того, знак '<<' прямо просится, чтобы его прочесть как «пропихнуть влево» и даже человеку, незнакомому с возможностью переопределять операторы в C++, очень легко понять, что означает
cout << "Hello!"
.Что касается оператора деления для строк — а что, я бы, например, не прочь был посмотреть на
split
, который выглядит как stringList = "a,b,cc,ddd" / ','
. Почему нет? Мы же делим строку на части, так? Отличная метафора…Так дело решается наследованием и реализацией своего оператора. Если сами не хотите, могу сочинить пример)
Так Unix shell же, в нём запись в файл (поток) именно так и выглядит $ cmd >> file. Или это вам тоже кажется неудачным решением? Да и интуитивно это вполне понятно. Ведь оператор сдвига не просто так именно такой "<<" или ">>" воспринимается как перемещение чего-либо влево или вправо соответственно. Как уже говорилось выше, никто не считает, что "+" — неудачный оператор для конкетации строк, потому что он интуитивно понятен. Оператор >> в качестве оператора вывода тоже вполне понятен интуитивно и поэтому, как мне кажется, вполне удачен.
Можно было ещё читать с помощью getchar_unlocked в буфер типа char[12] (если в строке больше символов, это в int32 всё равно не влезет — игнорировать или сообщать об ошибке), а потом atoi сделать. Тогда можно не парсить цифры вручную, а скорость должна быть сравнимая с самым быстрым способом.
Ещё нужно помнить про локали. У сишной и плюсовой частей они рулятся независимо, но об этом часто забывают.
Например, выводим через cout. А читаем через sscanf.
В рантайме плюсовая библиотека при запуске выставит локаль в системную. А сишная часть останется в C.
И банальный код, который запишет в файл float-значение через cout, а потом попытается прочитать его через sscanf окажется зависимым от системной локали! (например, запишется число с разделителем-запятой. А при чтении будет ожидаться точка -> ошибка!)
Например, выводим через cout. А читаем через sscanf.
В рантайме плюсовая библиотека при запуске выставит локаль в системную. А сишная часть останется в C.
И банальный код, который запишет в файл float-значение через cout, а потом попытается прочитать его через sscanf окажется зависимым от системной локали! (например, запишется число с разделителем-запятой. А при чтении будет ожидаться точка -> ошибка!)
Интересно было бы с node.js сравнить, например.
Сравните! Я вот, например, взял и померил для Java (ради интереса). Использовал самый тупой способ — класс
И вот вывод ее:
Две с хвостиком секунды. Вполне достойно, как мне кажется. То есть с getchar не сравнить, но с iostream вполне конкурирует…
Scanner
, который является некоторым аналогом потока ввода из iostream. Получилась вот такая прога:package readnum;
import java.util.Scanner;
public class ReadNum {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int max = 0;
while (sc.hasNextInt()) {
int next = sc.nextInt();
if (next > max) {
max = next;
}
}
System.out.println("Max: " + max);
}
}
И вот вывод ее:
$ time java -cp bin readnum.ReadNum < data
Max: 999999
real 0m2.173s
user 0m0.031s
sys 0m0.015s
Две с хвостиком секунды. Вполне достойно, как мне кажется. То есть с getchar не сравнить, но с iostream вполне конкурирует…
Сколько у вас было значений на входе? (в посте — 10 миллионов)
Это потому, что я — дурень и читал целые числа. А они закончились на 1 миллионе (который в файле отображен как 1e+6)
Так что беру свои слова назад. У меня — кошмар по производительности:
Чтобы спасти положение, добавляем буфферизацию:
получаем копеечный прирост:
из чего делаем вывод — тормозит
И получаем отличный результат:
То есть те же 2 секунды, что и для iostream. Из чего делаем простой вывод: Java быстро читает и достойно парсит double. Но
Так что беру свои слова назад. У меня — кошмар по производительности:
package readnum;
import java.util.Scanner;
public class ReadNum {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
double max = 0;
while (sc.hasNextDouble()) {
double next = sc.nextDouble();
if (next > max) {
max = next;
}
}
sc.close();
System.out.println("Max: " + max);
}
}
$ time java -cp bin readnum.ReadNum < data
Max: 1.0E7
real 1m2.414s
user 0m0.015s
sys 0m0.031s
Чтобы спасти положение, добавляем буфферизацию:
package readnum;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
public class ReadNum {
public static void main(String[] args) {
Scanner sc = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
double max = 0;
while (sc.hasNextDouble()) {
double next = sc.nextDouble();
if (next > max) {
max = next;
}
}
sc.close();
System.out.println("Max: " + max);
}
}
получаем копеечный прирост:
$ time java -cp bin readnum.ReadNum < data
Max: 1.0E7
real 1m1.802s
user 0m0.015s
sys 0m0.015s
из чего делаем вывод — тормозит
Scanner
. Избавляемся от него:package readnum;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class ReadNum {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
double max = 0;
String line;
while ((line = br.readLine()) != null) {
double next = Double.parseDouble(line);
if (next > max) {
max = next;
}
}
br.close();
System.out.println("Max: " + max);
}
}
И получаем отличный результат:
$ time java -cp bin readnum.ReadNum < data
Max: 1.0E7
real 0m2.222s
user 0m0.000s
sys 0m0.047s
То есть те же 2 секунды, что и для iostream. Из чего делаем простой вывод: Java быстро читает и достойно парсит double. Но
Scanner
никуда не годится. Тормозит жутко. Если мне надо будет прочитать гигабайт чисел из потока ввода, воспользуюст вашим кодом с getchar и JNI. Слава богу, в реальности таких задач немного :)cin из третьего варианта с 100 миллионами справился за 11.97 секунды, а следующая строчка на Haskell — за 6.87. Вот так вот.
import qualified Data.ByteString.Lazy.Char8 as B
import Data.Maybe
import Data.List
main = B.interact $ B.pack . show . foldl' max 0 . map (fst . fromJust . B.readInt) . B.lines
А мне кажется, что не совсем корректно приводить сравнение на максимальной оптимизации компилятора -O3. Всё же по умолчанию у gcc используется оптимизация -O2 — как более безопасная.
У GCC в -O3 нет ничего «небезопасного». Это какой-то старый миф (возможно, в каких-то старых версиях было по-другому).
Другое дело, что, теоретически, оптимизации из O3 могут приводить в раздуванию кода или падению производительности, хотя я на практике такого не наблюдал.
Я сам всегда использую -O3.
-O3
Optimize yet more. -O3 turns on all optimizations specified by -O2 and also turns on the -finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-loop-distribute-patterns, -ftree-slp-vectorize, -fvect-cost-model, -ftree-partial-pre and -fipa-cp-clone options.
Другое дело, что, теоретически, оптимизации из O3 могут приводить в раздуванию кода или падению производительности, хотя я на практике такого не наблюдал.
Я сам всегда использую -O3.
К сожалению это не миф, так как ошибок неправильной работы программы на -O3 было значительное количество по сравнению с -O2…
Я лишь хотел сказать, что немного не верно сравнивать время и возможности работы ввода и вывода, когда компилятор ради увеличения времени компиляции сокращает и упрощает код, тем самым меняя изначальный контекст самого сравнения.
Я лишь хотел сказать, что немного не верно сравнивать время и возможности работы ввода и вывода, когда компилятор ради увеличения времени компиляции сокращает и упрощает код, тем самым меняя изначальный контекст самого сравнения.
Скорее всего, ошибки таки в самой программе, а не в оптимизациях компилятора.
Компилятор — такая же программа, написанная программистами, допускающими ошибки.
Поверьте, не всегда правильно работают даже компиляторы.
как пример
Поверьте, не всегда правильно работают даже компиляторы.
как пример
Скорее всего, там ошибки в оптимизациях программы, а не в оптимизациях компилятора.
Очень занимательная статья, спасибо.
Вопрос к измерениям: времена получены на единичном запуске или это среднее по какому-то значению?
Вопрос к измерениям: времена получены на единичном запуске или это среднее по какому-то значению?
* по количеству запусков, конечно.
Я усреднял по 3-5 запускам. Но поскольку не ставилось задачи измерить точно, а только качественно сравнить, я не заморачивался с процедурой измерения.
iostreams — это не часть STL, это часть стандартной библиотеки.
А с чем связана такая низкая производительность с clang?
А если попробовать mmap? Мне кажется это должно быть быстрее всего.
Забавно, что лично у меня на моем процессоре быстрее всего работает такая программа (файл test.c):
Если посмотреть на времена, то получается вот что:
Если компилировать с помощью gcc 4.9, то ваша программа становится чуточку быстрее, а моя — чуточку медленее:
#include <stdio.h>
#include <unistd.h>
int main()
{
long max = -1;
char buf[655361], *bufp;
long c, x = 0, n;
while ((n = read(0, buf, sizeof(buf) - 1)) > 0) {
buf[n] = 0;
bufp = buf;
while ((c = *(bufp++)) != 0) {
c -= '0';
if (c >= 0 && c <= 9) {
x = x*10 + c;
} else if (c == '\n' - '0') {
if (x > max) max = x;
x = 0;
}
}
}
printf("%ld\n", max);
return 0;
}
Если посмотреть на времена, то получается вот что:
$ clang -o merhalak -O3 merhalak.c
$ time ./merhalak <ololo.txt
warning: this program uses gets(), which is unsafe.
683641836811
real 0m1.166s
user 0m1.123s
sys 0m0.037s
$ clang -o test -O3 test.c
$ time ./test <ololo.txt
683641836811
real 0m0.145s
user 0m0.118s
sys 0m0.025s
Если компилировать с помощью gcc 4.9, то ваша программа становится чуточку быстрее, а моя — чуточку медленее:
$ gcc-4.9 -o merhalak -O3 merhalak.c && time ./merhalak <ololo.txt
warning: this program uses gets(), which is unsafe.
683641836811
real 0m1.140s
user 0m1.104s
sys 0m0.033s
$ gcc-4.9 -o test -O3 test.c && time ./test <ololo.txt
683641836811
real 0m0.166s
user 0m0.140s
sys 0m0.024s
Используйте fgets вместо get_s ;).
Про c++ и про c++11 в частности я ничего не знаю :). В любом случае, в clang поддержка C++ не очень хорошая
Про c++ и про c++11 в частности я ничего не знаю :). В любом случае, в clang поддержка C++ не очень хорошая
В стандарте безопасные функции (с окончанием _s ) описаны в приложении K как optional.
Так что википедия в данном случае неточна.
Так что википедия в данном случае неточна.
В clang поддержка C++ как раз считается одной из самых лучших. А с неподдержкой чего столкнулись вы столкнулись?
Я, к счастью, не пишу на C++, поэтому не сталкивался с тем, что в clang что-то не поддерживается. Но мое утверждение было основано на том, что поскольку clang спонсировался долгое время компанией Apple, то в первую очередь в clang развивалась поддержка C и Objective C, и во вторую очередь C++. Сейчас, возможно, ситуация меняется, но очень долгое время поддержка C++ в clang была не в приоритете.
threads.h в стандарте объявлен необязательным.
The headers <complex.h>, <stdatomic.h>, and <threads.h> are conditional features that implementations need not support; see 6.10.8.3.
Новые версии gcc и clang на Linux x86 поддерживают <threads.h> (ох уж этот хабрапарсер), хотя, вообще говоря, не обязательны для поддержки согласно стандарту. По очевидным причинам — в некоторых ОС потоков просто нет ) Так что уточните, пожалуйста платформу и ось
О, извините за невольное введение в заблуждение. Был невнимательным и подумал что речь идёт о C++. GCC до сих пор не поддерживает threading из c11, да и вообще много чего оттуда не поддерживает. Судя по всему, проблема не с компилятором а с библиотекой.
результаты на linux mint 17.2,
clang 3.5.0-4, x84_64.
вариант stoi не скомпилился
а мне было лень исправлять
g++ 4.8.2
clang 3.5.0-4, x84_64.
$ seq 1000000 | time testN
Скрытый текст
scanf
10000000
1.35user 0.06system 0:01.52elapsed 92%CPU (0avgtext+0avgdata 2724maxresident)k
0inputs+0outputs (0major+116minor)pagefaults 0swaps
iostream + nosync
10000000
1.47user 0.04system 0:01.59elapsed 95%CPU (0avgtext+0avgdata 2620maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream
10000000
4.27user 0.07system 0:04.40elapsed 98%CPU (0avgtext+0avgdata 2600maxresident)k
0inputs+0outputs (0major+112minor)pagefaults 0swaps
iostream + ss + nosync
10000000
6.73user 0.06system 0:06.86elapsed 99%CPU (0avgtext+0avgdata 2624maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream + ss
10000000
11.05user 0.13system 0:11.33elapsed 98%CPU (0avgtext+0avgdata 2572maxresident)k
0inputs+0outputs (0major+112minor)pagefaults 0swaps
iostream + ss2 + nosync
10000000
2.42user 0.03system 0:02.49elapsed 98%CPU (0avgtext+0avgdata 2620maxresident)k
0inputs+0outputs (0major+117minor)pagefaults 0swaps
iostream + ss2
10000000
5.51user 0.08system 0:05.62elapsed 99%CPU (0avgtext+0avgdata 2572maxresident)k
0inputs+0outputs (0major+110minor)pagefaults 0swaps
getchar + nosync
10000000
1.05user 0.09system 0:01.18elapsed 96%CPU (0avgtext+0avgdata 2592maxresident)k
0inputs+0outputs (0major+117minor)pagefaults 0swaps
getchar
10000000
1.09user 0.06system 0:01.23elapsed 93%CPU (0avgtext+0avgdata 2536maxresident)k
0inputs+0outputs (0major+111minor)pagefaults 0swaps
getchar unl + nosync
10000000
0.64user 0.08system 0:00.74elapsed 98%CPU (0avgtext+0avgdata 2588maxresident)k
0inputs+0outputs (0major+114minor)pagefaults 0swaps
getchar unl
10000000
0.70user 0.06system 0:00.87elapsed 87%CPU (0avgtext+0avgdata 2536maxresident)k
0inputs+0outputs (0major+111minor)pagefaults 0swaps
10000000
1.35user 0.06system 0:01.52elapsed 92%CPU (0avgtext+0avgdata 2724maxresident)k
0inputs+0outputs (0major+116minor)pagefaults 0swaps
iostream + nosync
10000000
1.47user 0.04system 0:01.59elapsed 95%CPU (0avgtext+0avgdata 2620maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream
10000000
4.27user 0.07system 0:04.40elapsed 98%CPU (0avgtext+0avgdata 2600maxresident)k
0inputs+0outputs (0major+112minor)pagefaults 0swaps
iostream + ss + nosync
10000000
6.73user 0.06system 0:06.86elapsed 99%CPU (0avgtext+0avgdata 2624maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream + ss
10000000
11.05user 0.13system 0:11.33elapsed 98%CPU (0avgtext+0avgdata 2572maxresident)k
0inputs+0outputs (0major+112minor)pagefaults 0swaps
iostream + ss2 + nosync
10000000
2.42user 0.03system 0:02.49elapsed 98%CPU (0avgtext+0avgdata 2620maxresident)k
0inputs+0outputs (0major+117minor)pagefaults 0swaps
iostream + ss2
10000000
5.51user 0.08system 0:05.62elapsed 99%CPU (0avgtext+0avgdata 2572maxresident)k
0inputs+0outputs (0major+110minor)pagefaults 0swaps
getchar + nosync
10000000
1.05user 0.09system 0:01.18elapsed 96%CPU (0avgtext+0avgdata 2592maxresident)k
0inputs+0outputs (0major+117minor)pagefaults 0swaps
getchar
10000000
1.09user 0.06system 0:01.23elapsed 93%CPU (0avgtext+0avgdata 2536maxresident)k
0inputs+0outputs (0major+111minor)pagefaults 0swaps
getchar unl + nosync
10000000
0.64user 0.08system 0:00.74elapsed 98%CPU (0avgtext+0avgdata 2588maxresident)k
0inputs+0outputs (0major+114minor)pagefaults 0swaps
getchar unl
10000000
0.70user 0.06system 0:00.87elapsed 87%CPU (0avgtext+0avgdata 2536maxresident)k
0inputs+0outputs (0major+111minor)pagefaults 0swaps
вариант stoi не скомпилился
iostreams_performance.cpp:146:22: error: no member named 'stoi' in namespace 'std'
int x = std::stoi(line);
а мне было лень исправлять
g++ 4.8.2
Скрытый текст
scanf
10000000
1.35user 0.06system 0:01.48elapsed 95%CPU (0avgtext+0avgdata 2664maxresident)k
168inputs+0outputs (1major+112minor)pagefaults 0swaps
iostream + nosync
10000000
1.47user 0.05system 0:01.58elapsed 96%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
iostream
10000000
4.30user 0.07system 0:04.41elapsed 99%CPU (0avgtext+0avgdata 2540maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
iostream + ss + nosync
10000000
6.89user 0.07system 0:07.03elapsed 98%CPU (0avgtext+0avgdata 2564maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream + ss
10000000
10.72user 0.09system 0:10.89elapsed 99%CPU (0avgtext+0avgdata 2544maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
iostream + ss2 + nosync
10000000
2.21user 0.04system 0:02.30elapsed 97%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+120minor)pagefaults 0swaps
iostream + ss2
10000000
5.37user 0.08system 0:05.50elapsed 99%CPU (0avgtext+0avgdata 2616maxresident)k
0inputs+0outputs (0major+115minor)pagefaults 0swaps
getchar + nosync
10000000
1.00user 0.06system 0:01.18elapsed 90%CPU (0avgtext+0avgdata 2640maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
getchar
10000000
0.94user 0.10system 0:01.15elapsed 90%CPU (0avgtext+0avgdata 2608maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
getchar unl + nosync
10000000
0.58user 0.08system 0:00.78elapsed 85%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+120minor)pagefaults 0swaps
getchar unl
10000000
0.58user 0.03system 0:00.64elapsed 97%CPU (0avgtext+0avgdata 2472maxresident)k
0inputs+0outputs (0major+109minor)pagefaults 0swaps
stoi + nosync
10000000
1.14user 0.02system 0:01.25elapsed 93%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
stoi
10000000
4.09user 0.05system 0:04.25elapsed 97%CPU (0avgtext+0avgdata 2544maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
10000000
1.35user 0.06system 0:01.48elapsed 95%CPU (0avgtext+0avgdata 2664maxresident)k
168inputs+0outputs (1major+112minor)pagefaults 0swaps
iostream + nosync
10000000
1.47user 0.05system 0:01.58elapsed 96%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
iostream
10000000
4.30user 0.07system 0:04.41elapsed 99%CPU (0avgtext+0avgdata 2540maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
iostream + ss + nosync
10000000
6.89user 0.07system 0:07.03elapsed 98%CPU (0avgtext+0avgdata 2564maxresident)k
0inputs+0outputs (0major+119minor)pagefaults 0swaps
iostream + ss
10000000
10.72user 0.09system 0:10.89elapsed 99%CPU (0avgtext+0avgdata 2544maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
iostream + ss2 + nosync
10000000
2.21user 0.04system 0:02.30elapsed 97%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+120minor)pagefaults 0swaps
iostream + ss2
10000000
5.37user 0.08system 0:05.50elapsed 99%CPU (0avgtext+0avgdata 2616maxresident)k
0inputs+0outputs (0major+115minor)pagefaults 0swaps
getchar + nosync
10000000
1.00user 0.06system 0:01.18elapsed 90%CPU (0avgtext+0avgdata 2640maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
getchar
10000000
0.94user 0.10system 0:01.15elapsed 90%CPU (0avgtext+0avgdata 2608maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
getchar unl + nosync
10000000
0.58user 0.08system 0:00.78elapsed 85%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+120minor)pagefaults 0swaps
getchar unl
10000000
0.58user 0.03system 0:00.64elapsed 97%CPU (0avgtext+0avgdata 2472maxresident)k
0inputs+0outputs (0major+109minor)pagefaults 0swaps
stoi + nosync
10000000
1.14user 0.02system 0:01.25elapsed 93%CPU (0avgtext+0avgdata 2636maxresident)k
0inputs+0outputs (0major+122minor)pagefaults 0swaps
stoi
10000000
4.09user 0.05system 0:04.25elapsed 97%CPU (0avgtext+0avgdata 2544maxresident)k
0inputs+0outputs (0major+113minor)pagefaults 0swaps
У меня с помощью getline
+std::stod
получается парсить в 2 раза быстрее, чем с помощью boost::spirit::qi
… Конфигурация: MinGW 8.1 64 bit, C++17, boost 1.76. Файл содержит 2 миллиона триста тысяч строк, размер его — 365 мегабайт.
Sign up to leave a comment.
Насколько медленны iostreams?