Читает из файлов в файловой системе Linux на твердотельных накопителях NVMe значительно быстрее при загрузке, кратной 128 КиБ?

Я вижу странную аномалию производительности при попытке прочитать большой файл (~20 ГБ), находящийся в файловой системе ext4, поддерживаемой SSM NVMe, на RedHat Linux. В моем упрощенном эксперименте (весь код ниже) я просто пытаюсь прочитать 10 000 000 000 (10 миллиардов) байтов из этого файла выше. Мое чтение может начинаться с любого смещения (так, чтобы по крайней мере 10 миллиардов байтов были доступны после этого), и я читаю 1 МБ за раз. Это начальное смещение настраивается в моей программе с помощью параметра командной строки. Вот что я вижу: - когда мое начальное смещение, если 0 или выровнено по 128 КиБ (т.е. кратно 131072 байтам), считывание завершается примерно за 3,663 секунды. - при других произвольных начальных смещениях считывание занимает от 6,8 до 7,9 секунд; т.е. примерно в два раза выровненные старты. [Некоторые примеры проб / наблюдений со временем приведены ниже]

Мои вопросы:- 1. Это ожидаемое поведение в стандартных файловых системах? 2. Я не смог найти какой-либо настроенный параметр, который указывает мне на это 128 КиБ. Итак, я надеюсь, что кто-то может указать мне, где искать дальше.

== исходный код моего эксперимента ==

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>
#include <iostream>
#define __min(a,b) ((a) < (b) ? (a) : (b))

int main(int argc, char **argv)
{
  char* buffer = NULL;

  if (argc < 4) {
    std::cout << "usage: app  <filename-to-read-in-mem> <offset> <nr_bytes_to_read>\n";
    std::cout << "sysconf(_SC_PAGE_SIZE): " << sysconf(_SC_PAGE_SIZE) << std::endl;
    return 1;
  }

  off_t offset = atoll(argv[2]);
  ssize_t nr_bytes_to_read = atoll(argv[3]);

  int fd = open(argv[1], O_RDONLY);
  assert(fd > 0);

  assert(lseek(fd, offset, SEEK_SET) == offset);
  assert(posix_fadvise(fd, offset, 0, POSIX_FADV_SEQUENTIAL) == 0);

  size_t chunksize = 1024*1024; //1 MiB
  int rv = posix_memalign((void **) &buffer, 4096 /*sysconf(_SC_PAGE_SIZE)*/, chunksize);
  assert(rv == 0 && buffer != NULL);

  size_t yet_to_read = nr_bytes_to_read;
  size_t readsize = chunksize;
  ssize_t rc = 0;
  size_t total_bytes_read = 0;
  while (yet_to_read > 0) {
    readsize = __min(yet_to_read, chunksize); //adjust for the last read
    rc = read(fd, buffer, readsize);
    assert(rc >= 0); //Not handling for EINTR for the experiment.
    yet_to_read -= rc;
    total_bytes_read += rc;
    if (rc == 0) break;
    //Do something with the buffer and then move on to the next chunk.
  }

  std::cout << "Read " << total_bytes_read << " at offset " << offset << std::endl;
  free(buffer);
  close(fd);
  return 0;
}

== конец исходного кода ==

== пробные прогоны ==

[root@ninja save]# pwd
/ninjalocal2/gautam/save
[root@ninja save]# ls -la parcel.0001
-rw-r--r-- 1 root root 21434411376 Nov  1 10:50 parcel.0001
[root@ninja save]# df -Th .
Filesystem                          Type  Size  Used Avail Use% Mounted on
/dev/mapper/rhel_ninja2-ninjalocal2 ext4  1.8T  245G  1.5T  15% /ninjalocal2
[root@ninja save]#

[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 0 10000000000
Read 10000000000 at offset 0

real    0m3.664s
user    0m0.002s
sys     0m1.762s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 4096 10000000000
Read 10000000000 at offset 4096

real    0m7.964s
user    0m0.000s
sys     0m1.890s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 8192 10000000000
Read 10000000000 at offset 8192

real    0m7.939s
user    0m0.002s
sys     0m1.861s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 65536 10000000000
Read 10000000000 at offset 65536

real    0m6.818s
user    0m0.001s
sys     0m1.907s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 131072 10000000000
Read 10000000000 at offset 131072

real    0m3.662s
user    0m0.004s
sys     0m1.716s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 131072 10000000000
Read 10000000000 at offset 131072

real    0m3.664s
user    0m0.001s
sys     0m1.735s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 13107200 10000000000
Read 10000000000 at offset 13107200

real    0m3.663s
user    0m0.001s
sys     0m1.729s

[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 131072000 10000000000
Read 10000000000 at offset 131072000

real    0m3.663s
user    0m0.002s
sys     0m1.719s
[root@ninja save]# sync; echo 3 > /proc/sys/vm/drop_caches; time ./stackru.bin ./parcel.0001 324567890 10000000000
Read 10000000000 at offset 324567890

real    0m7.432s
user    0m0.003s
sys     0m1.944s

== конец пробных прогонов ======

0 ответов

Другие вопросы по тегам