Я заметил, что когда я смотрю на вывод /proc/diskstats
существует несоответствие между общим временем, затраченным на чтение, общим временем, затраченным на запись, и общим временем выполнения операций ввода-вывода. Например, я видел запись в /proc/diskstats
это было:
$ cat /proc/diskstats
...
8 0 sda 944150584 590524 235547588959 780672196 833280352 534699043 322507689696 3472000824 1 812190100 4246357772
...
Согласно документации на https://www.kernel.org/doc/Documentation/iostats.txt,
Поле 4 - количество миллисекунд, потраченных на чтение. Это общее количество миллисекунд, потраченных на все чтения (измеряется от __make_request () до end_that_request_last ()).
Поле 8 - количество миллисекунд, затраченных на запись. Это общее количество миллисекунд, затраченных на все операции записи (измеряется от __make_request () до end_that_request_last ()).
Поле 10 - количество миллисекунд, затраченных на выполнение операций ввода-вывода. Это поле увеличивается, пока поле 9 не равно нулю.
Следовательно, я ожидал, что десятое поле будет суммой четвертого и восьми полей, поскольку я ожидал бы, что общее время ввода-вывода будет суммой времени, затраченного на чтение, и времени, затраченного на запись. Однако я никогда не замечал, что это так, и, более того, я всегда наблюдал, что сумма четвертого и восьмого полей больше десятого (например, в строке выше (780672196 + 3472000824 - 812190100 = Мне было интересно, может ли кто-нибудь объяснить, почему эти числа разные, кажется, что десятое поле пытается уловить что-то отличное от суммы четвертого и восьмого полей.
Я не смотрел исходный код, но похоже, что разница связана с двумя разными режимами учета.
Поля # 4 и # 8 суммируют время. каждый запрос принять для завершения. Это означает, что каждый из параллельных запросов по-прежнему способствует увеличению счетчика.
Поле # 10 учитывает только фактическое время, в течение которого очередь и диски были заняты, поэтому они учитывают параллельные запросы как один.
Приведу практический пример. На /boot
перегородка, я dd
файл размером ~ 4 МБ. Взгляните на статистику:
[root@localhost boot]# cat /proc/diskstats | grep sda1
8 1 sda1 46256 0 255703 19332 2063 0 4162 538 0 11207 19862
[root@localhost boot]# dd if=initramfs-0-rescue-7dc32e3935ba4ce1ae50a0a8170e4480.img of=/dev/null
84099+1 records in
84099+1 records out
43058701 bytes (43 MB) copied, 0.347783 s, 124 MB/s
[root@localhost boot]# cat /proc/diskstats | grep sda1
8 1 sda1 46342 0 339807 23011 2063 0 4162 538 0 11551 23540
[root@localhost boot]#
Для чтения файла требуется ~ 0,35 с, или ~ 350 мс. Однако счетчики №4 и №10 реагируют по-разному: первое увеличение примерно на 4000, а второе только примерно на 350. Легко увидеть, какие из них имеют «правильное» значение: это поле №10, как мы знаем по dd
что вся операция заняла около 350 мс, и поле № 10 увеличилось на ту же величину.
Итак, почему поле №4 так увеличилось и что на самом деле измеряет?
Во-первых, давайте разберемся, что происходит на уровне запроса. dd
по умолчанию использует запросы 512 Б, но кэш страниц Linux работает с детализацией 4 КБ, поэтому следует ожидать около 1000 запросов по 4 КБ. Эти 1000 запросов помещаются в очередь и выдаются один за другим (для простоты представим, что NCQ не существует) и отправляются на диск. Поскольку механические диски неплохо справляются с последовательным чтением, они обычно используют политику упреждающего чтения, то есть: они читают больше данных, чем требуется. Это означает, что после завершения первого запроса 4K все остальные последующие запросы будут обработаны в очень короткое время.
Давайте посчитаем с диким упрощением:
Общее время запросов по полю # 4: 1000 запросов в очереди * 4 мс каждый == 4000 мс. И это примерно значение, на которое увеличилось поле №4 ...
Нижняя граница:
Чтобы провести одобрительный параллелизм: думаю о многоядерном процессоре. Два процесса могут одновременно работать с ЦП, выполняясь по 60 секунд каждый. Общее используемое время ЦП составляет 120 с (60 с * 2), но реальное прошедшее время остается на уровне 60 с, поскольку два процесса выполняются одновременно.