Я на несколько лет отстал, но:
В 'Edit 4/5/6' оригинального поста вы используете конструкцию:
$ /usr/bin/time cat big_file | program_to_benchmark
Thisневерен в нескольких отношениях:
Вы на самом деле определяете время выполнения `cat`, а не своего теста.Использование ЦП 'user' и 'sys', отображаемое `time`, относится к` cat`, а не к вашей тестовой программе.Хуже того, «реальное» время также не обязательно точное.В зависимости от реализации `cat` и конвейеров в вашей локальной ОС, вполне возможно, что` cat` записывает последний гигантский буфер и завершает работу задолго до того, как процесс чтения завершит свою работу.
Использование `cat` является ненужным и фактически контрпродуктивным;вы добавляете движущиеся части.Если вы работали в достаточно старой системе (т. Е. С одним ЦП и - в некоторых поколениях компьютеров - вводом-выводом быстрее, чем ЦП) - сам факт запуска `cat` может существенно повлиять на результаты.Вы также подвержены любой буферизации ввода и вывода и другой обработке, которую может выполнять `cat`.(Если бы я был Рэндалом Шварцем, это, вероятно, принесло бы вам 'Бесполезное использование кошки' .
Лучшая конструкция была бы:
$ /usr/bin/time program_to_benchmark < big_file
В этом выражении это shell , который открывает big_file, передавая его вашей программе (ну, на самом деле, `time`, которая затем выполняет вашу программу как подпроцесс) в качестве уже открытого дескриптора файла.На 100% чтение файла лежит исключительно ответственность за программу, которую вы пытаетесь сравнить. Это дает вам реальное представление о ее производительности без ложных осложнений.
Я упомяну два возможных, но на самом деле неправильно ".исправления », которые также могут быть рассмотрены (но я« нумерую »их по-разному, поскольку это не те вещи, которые были ошибочны в исходном посте):
A. Вы можете« исправить »это, синхронизируя только вашу программу:
$ cat big_file | /usr/bin/time program_to_benchmark
B или по времени всего конвейера:
$ /usr/bin/time sh -c 'cat big_file | program_to_benchmark'
Это неправильно по тем же причинам, что и # 2: они по-прежнему используют `cat` без необходимости. Я упоминаю ихдлянесколько причин:
они более «естественны» для людей, которым не совсем удобны средства перенаправления ввода / вывода оболочки POSIX
могут быть случаи, когда для `cat` требуется (например, для чтения файла требуется какая-то привилегия для доступа, и вы не хотите предоставлять эту привилегию программе для сравнения: `sudo cat / dev / sda |/ usr / bin / time my_compression_test --no-output`)
на практике , на современных машинах добавленный `cat` в конвейере, вероятно, имеетникаких реальных последствий
Но я говорю это последнее с некоторым колебанием.Если мы рассмотрим последний результат в «Edit 5» -
$ /usr/bin/time cat temp_big_file | wc -l
0.01user 1.34system 0:01.83elapsed 74%CPU ...
- это говорит о том, что `cat` потребляла 74% процессора во время теста;и действительно, 1,34 / 1,83 составляет примерно 74%.Возможно, выполнение:
$ /usr/bin/time wc -l < temp_big_file
заняло бы только оставшиеся 49 секунд!Вероятно, нет: `cat` здесь должен был платить за системные вызовы read () (или эквивалентные), которые передавали файл с 'диска' (фактически буферный кэш), а также за канал, записывающий их для доставки их в` wc`.Правильный тест все равно должен был бы выполнять эти вызовы read ();только вызовы write-to-pipe и read-from-pipe были бы сохранены, и они должны быть довольно дешевыми.
Тем не менее, я предсказываю, что вы сможете измерить разницу между `cat file |wc -l` и `wc -l
На самом деле я провел несколько быстрых тестов с мусорным файлом объемом 1,5 гигабайта в системе Linux 3.13 (Ubuntu 14.04), получив эти результаты (этина самом деле результаты «лучший из 3», конечно же, после заполнения кеша:
$ time wc -l < /tmp/junk
real 0.280s user 0.156s sys 0.124s (total cpu 0.280s)
$ time cat /tmp/junk | wc -l
real 0.407s user 0.157s sys 0.618s (total cpu 0.775s)
$ time sh -c 'cat /tmp/junk | wc -l'
real 0.411s user 0.118s sys 0.660s (total cpu 0.778s)
Обратите внимание, что результаты двух конвейеров утверждают, что они заняли больше процессорного времени (пользователь + sys), чем в реальном времени. Это потому, что я использую встроенную в оболочку команду 'time', которая осведомлена о конвейере; и я нахожусь на многоядерной машине, где отдельные процессы в конвейере могут использовать отдельные ядра, накапливая процессорное время быстрее, чем в реальном времени. Используя / usr / bin / time, я вижу меньше процессорного времени, чем в реальном времени, показывая, что он может рассчитывать только один элемент конвейера, переданный ему в его командной строке. Кроме того, вывод оболочки дает миллисекунды, в то время как / usr / bin / time дает только сотни секунд.
Таким образом, на уровне эффективности `wc -l`,` cat` имеет огромное значение: 409/283 = 1.453 или 45.3% больше в реальном времени, и 775/280 = 2.768, или колоссальные 177% больше используемого процессора ! На моей случайной тестовой коробке "это было там в то время".
Я должен добавить, что между этими стилями тестирования есть по крайней мере еще одно существенное различие, и я не могу сказать, является ли это преимуществом или недостатком; Вы должны решить это самостоятельно:
Когда вы запускаете `cat big_file | / usr / bin / time my_program`, ваша программа получает входные данные из конвейера точно в темпе, который посылает `cat`, и кусками не больше, чем записывает` cat`.
Когда вы запускаете `/ usr / bin / time my_program или во многих случаях библиотеки ввода / вывода языка, на котором она была написана, - может выполнять различные действия при представлении файлового дескриптора, ссылающегося на обычный файл. Он может использовать mmap (2) для отображения входного файла в его адресное пространство вместо использования явных системных вызовов read (2). Эти различия могут оказать гораздо большее влияние на результаты теста, чем небольшая стоимость запуска двоичного файла `cat`.
Конечно, это интересный результат теста, если одна и та же программа работает в разных случаях значительно по-разному. Это показывает, что программа или ее библиотеки ввода-вывода делают что-то интересное, например, используя mmap (). Так что на практике было бы неплохо выполнить тесты в обоих направлениях; возможно, нужно просто не учитывать результат `cat`, чтобы" простить "стоимость запуска самого` cat`.