代码之家  ›  专栏  ›  技术社区  ›  Zibri

如何输出尽可能快的固定缓冲区?

  •  -2
  • Zibri  · 技术社区  · 6 年前

    示例代码:

    #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个线程,在标准输出端输出64位cpu上128字节或16个长整数的“缓冲区”内容。

    如果我接着跑:

    我的速度是7.5gb/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个人不明白这个简单的问题。 我甚至大胆地提出了这个问题的原因。

    0 回复  |  直到 6 年前
        1
  •  1
  •   mevets    6 年前

    首先你需要确定你的利率限制因素。它可以是cpu/内存速度、cpu/系统调用延迟、管道实现、stdio实现。可能还有更多,但这是一个良好的开端:

    1. cpu/内存——测试一堆0的存储速度。

    2. 管道实现——您可以这样做,但是您可以尝试改变管道容量(fcntl(2)F_GETPIPE_SZ)。F_SETPIPE_SZ,如果您在linux上)。

    3. stdio实现——用write替换fwite/setbuf。我建议将您的写大小与管道容量/num进程对齐可能会产生一个好的结果,但您可能应该进行更广泛的调查。

    使用这些数字,您应该能够计算出最大吞吐量。请回电,我相信有不止几个人感兴趣。

        2
  •  1
  •   Zibri    6 年前

    看来linux调度器和IO优先级在减缓中起了很大作用。

    此外,spectre和其他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
    

    如果你有其他想法,欢迎你贡献。

        3
  •  -1
  •   Maxim Egorushkin    6 年前

    1. 电话 fwrite . 只是从 buffer buf
    2. 一次 缓冲器 填满它调用 write .

    要加快速度,请在步骤1中避免复制 使用

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

    你也可以 更大以最小化系统调用的数量(幽灵缓解使系统调用更昂贵)。