Как вывести как можно быстрее фиксированный буфер? - PullRequest
0 голосов
/ 28 марта 2019

Пример кода:

#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <pthread.h>

int
main (int argc, char **argv)
{

  unsigned char buffer[128];
  char buf[0x4000];
  setvbuf (stdout, buf, _IOFBF, 0x4000);
  fork ();
  fork ();

  pthread_t this_thread = pthread_self ();

  struct sched_param params;

  params.sched_priority = sched_get_priority_max (SCHED_RR);

  pthread_setschedparam (this_thread, SCHED_RR, &params);


  while (1)
    {
      fwrite (&buffer, 128, 1, stdout);
    }
}

Эта программа открывает 4 потока и выводит на стандартный вывод содержимое "буфера", который составляет 128 байтов или 16 длинных целых на 64-битном процессоре.

Если я запусту:

. / Writetest | pv -ptebaSs 800G> / dev / null

Я получаю скорость около 7,5 ГБ / с.

Кстати, это та же скорость, которую я получаю, если сделаю:

$ mkfifo out
$ dd if=/dev/zero bs=16384 >out &
$ dd if=/dev/zero bs=16384 >out &
$ dd if=/dev/zero bs=16384 >out &
$ dd if=/dev/zero bs=16384 >out &
pv <out -ptebaSs 800G >/dev/null

Есть ли способ сделать это быстрее? Заметка. буфер в реальной программе не заполнен нулями.

Мне интересно понять, сколько данных может выдать одна программа (многопоточная или многопроцессорная)

Похоже, 4 человека не поняли этот простой вопрос. Я даже выделил жирным шрифтом причину вопроса.

Ответы [ 3 ]

1 голос
/ 28 марта 2019

Сначала вам нужно определить свой фактор, ограничивающий скорость.Это может быть скорость процессора / памяти, задержка процессора / системного вызова, конвейерная реализация, реализация stdio.Возможно, есть и другие, но это хорошее начало:

  1. процессор / память - проверьте, насколько быстро вы можете записать кучу нулей.

  2. cpu / syscall - протестируйте, записав 1 байт в / dev / null, сколько времени занимает простая запись в вашей системе

  3. конвейерная реализация - вы вроде какэто, но вы можете попробовать изменить емкость канала (fcntl (2) F_GETPIPE_SZ. F_SETPIPE_SZ, если вы используете Linux).

  4. реализация stdio - замените fwite / setbuf на write.Я бы посоветовал выровнять размер записи с пропускной способностью канала / num-процессами, что может дать хороший результат, но вам, вероятно, следует изучить более широко.

Попробуйте все вышеперечисленное с несколькими процессами,хотя вам может потребоваться увеличить значения memcpy, чтобы получить значимые результаты.

С этими числами вы сможете рассчитать максимальную пропускную способность.Пожалуйста, сообщите, я уверен, что более чем несколько человек заинтересованы.

0 голосов
/ 31 марта 2019

Что ж, похоже, что приоритеты linux-планировщика и ввода-вывода сыграли большую роль в замедлении.

Кроме того, в игру вступили меры по снижению уязвимости процессора и призраков.

После дальнейшей оптимизации, чтобы добиться более высокой скорости, мне пришлось настроить следующие вещи:

1) program nice level (nice -n -20)
2) program ionice level (ionice -c 1 -n 7)
3) pipe size increased 8 times.
4) disable cpu mitigations by adding "pti=off spectre_v2=off l1tf=off" in kernel command line
5) tuning the linux scheduler

echo -n -1 >/proc/sys/kernel/sched_rt_runtime_us
echo -n -1 >/proc/sys/kernel/sched_rt_period_us
echo -n -1 >/proc/sys/kernel/sched_rr_timeslice_ms
echo -n 0 >/proc/sys/kernel/sched_tunable_scaling

Теперь программа выводит (на одном компьютере) 8,00 ГБ / с!

Если у вас есть другие идеи, вы можете внести свой вклад.

0 голосов
/ 28 марта 2019

Что ваша программа делает:

  1. Звонки fwrite. Это просто копирует данные из buffer в buf.
  2. Как только buf заполняется, он вызывает write.

Чтобы ускорить его, избегайте этой копии на шаге 1 и fwrite и используйте системный вызов write напрямую. E.g.:

char buf[0x4000];
for(;;)
    write(STDOUT_FILENO, buf, sizeof buf); // Implement error handling.

Вы также можете увеличить buf, чтобы свести к минимуму количество системных вызовов (Снижение риска для призраков сделало системные вызовы более дорогими). ​​

...