Почему fseeko() работает быстрее с большими файлами, чем с маленькими?

Я получаю здесь некоторые странные результаты производительности, и я надеюсь, что кто-то на stackoverflow.com может пролить свет на это!

Моей целью была программа, которую я мог бы использовать для проверки того, были ли большие запросы дороже, чем маленькие...

Во-первых, я создал два файла с помощью dd'ing /dev/zero для разделения файлов... Один размером 1 МБ, другой 9,8 ГБ... Затем я написал этот код:

#define _LARGE_FILE_API
#define _FILE_OFFSET_BITS 64

#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

int main( int argc, char* argv[] )
{
  struct stat64 fileInfo;
  stat64( argv[1], &fileInfo );

  FILE* inFile = fopen( argv[1], "r" );

  for( int i = 0; i < 1000000; i++ )
    {
      double seekFrac = ((double)(random() % 100)) / ((double)100);

      unsigned long long seekOffset = (unsigned long long)(seekFrac * fileInfo.st_size);

      fseeko( inFile, seekOffset, SEEK_SET );
    }

    fclose( inFile );
}

По сути, этот код выполняет один миллион случайных поисков по всему диапазону файла. Когда я запускаю это вовремя, я получаю такие результаты для smallfile:

[developer@stinger ~]# time ./seeker ./smallfile

real    0m1.863s
user    0m0.504s
sys  0m1.358s

Когда я запускаю его с файлом размером 9,8 гигабайта, я получаю такие результаты:

[developer@stinger ~]# time ./seeker ./bigfile

real    0m0.670s
user    0m0.337s
sys  0m0.333s

Я запускал каждый файл пару десятков раз, и результаты совпадают. Поиск в большом файле более чем в два раза быстрее поиска в маленьком файле. Почему?


person dicroce    schedule 16.07.2010    source источник
comment
Ваши запросы распределены очень редко: все они представляют собой целое процентное значение (0-99) от размера файла. Попробуйте уменьшить интервал примерно до 0,1%, затем до 0,01% и т. д. и посмотрите, заметите ли вы какую-либо разницу.   -  person casablanca    schedule 16.07.2010


Ответы (2)


Вы не измеряете производительность диска, вы измеряете, сколько времени требуется fseek для установки указателя и возврата.

Я рекомендую вам прочитать файл из места, которое вы ищете, если вы хотите проверить реальный ввод-вывод.

person Carl Smotricz    schedule 16.07.2010
comment
Вау... Хорошо, я добавил вызов getc() после поиска для чтения одного символа. Теперь поиск в большом файле обходится чуть дороже, чем поиск в маленьком файле. Есть ли какая-то оптимизация, при которой несколько последовательных поисков суммируются и фактически выполняются перед следующим вводом-выводом? Ух ты... - person dicroce; 16.07.2010
comment
seek() — это просто намек на операционную систему, которую вы планируете читать откуда-то в будущем. ОС имеет сложный механизм планирования для перемещения головок дисков таким образом, чтобы минимизировать общее время в пути для всех пользователей. Поскольку ваши чтения чередуются со всеми остальными, нет смысла искать до последнего момента, когда ОС (не ваша программа, ОС!) будет выполнять чтение. Таким образом, ОС запоминает вашу позицию поиска, но не предпринимает никаких действий до тех пор, пока не прочитает данные физически. - person Carl Smotricz; 16.07.2010

Я бы предположил, что это связано с реализацией fseeko.

На справочной странице fseek указано, что он просто «устанавливает индикатор позиции файла для указанного потока». Поскольку установка целого числа не должна зависеть от размера файла, возможно, существует «оптимизация», которая будет выполнять автоматическое чтение (и кэшировать полученную информацию) после fseek для небольших файлов, а не для больших файлов.

person advait    schedule 16.07.2010