如何尽可能快地输出固定缓冲区?
How to output as fast as possible a fixed buffer?
示例代码:
#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, ¶ms);
while (1)
{
fwrite (&buffer, 128, 1, stdout);
}
}
该程序打开 4 个线程并在 stdout 上输出 "buffer" 的内容,即 128 字节或 64 位 cpu 上的 16 个长整数 cpu。
如果我那么运行:
./writetest | pv -ptebaSs 800G >/dev/null
我的速度大约是 7.5 GB/s。
顺便说一句,这与我这样做时获得的速度相同:
$ 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 个人没看懂这个简单的问题。
我什至把问题的原因加粗了。
首先您需要确定您的速率限制因素。它可能是 cpu/memory 速度、cpu/system-call 延迟、管道实现、stdio 实现。可能还有更多,但这是一个好的开始:
cpu/memory -- 测试 memcpy 一堆零的速度。
cpu/syscall -- 测试,通过将 1 个字节写入 /dev/null,在您的系统上进行一次简单的写入需要多长时间
pipe 实现——你有点像这个,但你可以尝试改变管道容量( fcntl(2) F_GETPIPE_SZ。F_SETPIPE_SZ,如果你在linux).
stdio 实现——用 write 替换 fwite/setbuf。我建议将您的写入大小与管道对齐 capacity/num-processes 可能会产生良好的结果,但您可能应该进行更广泛的调查。
尝试使用多个进程执行上述所有操作,但您可能需要扩大 memcpy 进程以获得有意义的结果。
有了这些数字,您应该能够计算出您的最大吞吐量。请反馈,我相信肯定有不少人感兴趣。
你的程序做的是:
- 调用
fwrite
。这只是将数据从 buffer
复制到 buf
。
- 一旦
buf
填满,它就会调用 write
。
要加快速度,请避免在第 1 步和 fwrite
中进行复制,并直接使用 write
系统调用。例如:
char buf[0x4000];
for(;;)
write(STDOUT_FILENO, buf, sizeof buf); // Implement error handling.
您可能还想 buf
更大以最小化系统调用的数量(Spectre 缓解措施使系统调用更昂贵)。
好吧,似乎 linux 调度程序和 IO 优先级在减速中发挥了重要作用。
此外,幽灵和其他 cpu 漏洞缓解措施开始发挥作用。
进一步优化后,为了达到更快的速度,我不得不调整这个东西:
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 GB/sec!
如果您有其他想法,欢迎贡献。
示例代码:
#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, ¶ms);
while (1)
{
fwrite (&buffer, 128, 1, stdout);
}
}
该程序打开 4 个线程并在 stdout 上输出 "buffer" 的内容,即 128 字节或 64 位 cpu 上的 16 个长整数 cpu。
如果我那么运行:
./writetest | pv -ptebaSs 800G >/dev/null
我的速度大约是 7.5 GB/s。
顺便说一句,这与我这样做时获得的速度相同:
$ 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 个人没看懂这个简单的问题。 我什至把问题的原因加粗了。
首先您需要确定您的速率限制因素。它可能是 cpu/memory 速度、cpu/system-call 延迟、管道实现、stdio 实现。可能还有更多,但这是一个好的开始:
cpu/memory -- 测试 memcpy 一堆零的速度。
cpu/syscall -- 测试,通过将 1 个字节写入 /dev/null,在您的系统上进行一次简单的写入需要多长时间
pipe 实现——你有点像这个,但你可以尝试改变管道容量( fcntl(2) F_GETPIPE_SZ。F_SETPIPE_SZ,如果你在linux).
stdio 实现——用 write 替换 fwite/setbuf。我建议将您的写入大小与管道对齐 capacity/num-processes 可能会产生良好的结果,但您可能应该进行更广泛的调查。
尝试使用多个进程执行上述所有操作,但您可能需要扩大 memcpy 进程以获得有意义的结果。
有了这些数字,您应该能够计算出您的最大吞吐量。请反馈,我相信肯定有不少人感兴趣。
你的程序做的是:
- 调用
fwrite
。这只是将数据从buffer
复制到buf
。 - 一旦
buf
填满,它就会调用write
。
要加快速度,请避免在第 1 步和 fwrite
中进行复制,并直接使用 write
系统调用。例如:
char buf[0x4000];
for(;;)
write(STDOUT_FILENO, buf, sizeof buf); // Implement error handling.
您可能还想 buf
更大以最小化系统调用的数量(Spectre 缓解措施使系统调用更昂贵)。
好吧,似乎 linux 调度程序和 IO 优先级在减速中发挥了重要作用。
此外,幽灵和其他 cpu 漏洞缓解措施开始发挥作用。
进一步优化后,为了达到更快的速度,我不得不调整这个东西:
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 GB/sec!
如果您有其他想法,欢迎贡献。