OpenBSD 比 Linux 快 10 倍?

以下是一些基准测试结果,由 Jann Horn 提供。在 Linux 上运行时,速度出人意料地慢。

OpenBSD 运行得如此之快,我不得不稍微修改程序以进行自我测量,因为 time 工具缺乏足够的精度来记录非零值。

它所做的只是创建一个额外的线程,然后两个现有线程各创建 256 个套接字。这有什么难的?

#include 
#include 
#include 
#include 
#include <sys/time.h>
#include <sys/socket.h>

static void open_sockets(void) {
    for (int i=0; i<256; i++) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) err(1, "socket"); } } static void *thread_fn(void *dummy) { open_sockets(); return NULL; } int main(int argc) { struct timeval one, two; gettimeofday(&one, NULL); if (argc > 1)
        dup2(0, 666);
    pthread_t thread;
    if (pthread_create(&thread, NULL, thread_fn, NULL))
        errx(1, "pthread_create");
    open_sockets();
    if (pthread_join(thread, NULL))
        errx(1, "pthread_join");
    gettimeofday(&two, NULL);
    timersub(&two, &one, &one);
    printf("elapsed: %lld.%06lds\n", one.tv_sec, one.tv_usec);
    return 0;
}

在 Linux 上,我得到的结果大致如下:

元素周期表
tedu@penguin:~$ ./a.out 
elapsed: 0.017770s
tedu@penguin:~$ ./a.out 
elapsed: 0.026309s
tedu@penguin:~$ ./a.out 
elapsed: 0.018414s

在 OpenBSD 上,结果如下,呜呜:

ox$ ./a.out                                                                               
a.out: a.out: socketsocket: : Too many open files
Too many open files
ox$ ulimit -n 1024
ox$ ./a.out                                                                               
elapsed: 0.006096s
ox$ ./a.out  
elapsed: 0.002508s
ox$ ./a.out  
elapsed: 0.002326s

这些并非完全相同的机器,但大致可比。

代码中有一丝线索(与网络代码无关,如果你是这么猜的),更多解释在链接的帖子中,值得一读并思考。我真想看看在哪个系统和基准测试中 Linux 表现更优。

说实话,我只是觉得有点好笑。通常是那些奇怪的基准测试显示 OpenBSD 慢 10 倍,所以这个结果肯定会收录到我的收藏中。

本文文字及图片出自 is OpenBSD 10x faster than Linux?

共有 160 条讨论

  1. 不确定这是否相关,但当我进行类似的微基准测试时,测量时间间隔小于1秒,我会使用__rdtsc()编译器内置函数而非标准库函数。

    在所有现代处理器上,该指令通过一个计数器测量墙钟时间,该计数器以CPU的基础频率递增,不受动态频率调节影响。

    除了高精度外,这种时间测量方法的优势在于成本极低,比操作系统内核调用快几个数量级。

      1. 我认为大多数当前系统具有不变的 tsc,我快速浏览了你的文章,看到一个偏移量(但并不完全惊讶),但速率看起来相同。

        你可以将读取 tsc 的线程绑定到特定 CPU,不过在 OpenBSD 中无法绑定线程 :p

        1. 但为了明确起见(供他人参考),你不需要这样做,因为使用RDTSC/RDTSCP正是gettimeofday和clock_gettime当前的工作方式,即使在OpenBSD上也是如此。在TSC实用且可靠的情况下,优化已经存在。

          OpenBSD实际上只是最近才实现了这一优化。尽管大多数TSC是恒定的,但它们仍需在核心间进行校准,且存在其他细节问题(如休眠状态?),这使得可靠实现变得相当麻烦,而OpenBSD的人力资源不如Linux丰富。对于试图手动实现这一功能的人来说,这些非显而易见的问题可能相关,除非他们能依赖特定硬件的行为。

          1. 出于好奇,跨核心训练是否会产生残余偏移?如果是,该偏移是否具有非确定性?

            1. 我本人也感到好奇,查阅了一些资料。但目前仍无法自信地回答这个问题,也不想冒然发表可能误导性的言论,因此提供以下代码和相关线索:

              1. 据称OpenBSD已放弃修复TSC不同步的问题。See https://github.com/openbsd/src/commit/78156938567f79506a923c

              2. 相关 OpenBSD 内核代码:https://github.com/openbsd/src/blob/master/sys/arch/amd64/am

              1. 相关 Linux 内核代码:https://github.com/torvalds/linux/blob/master/arch/x86/kerne…,https://github.com/torvalds/linux/blob/master/arch/x86/kerne

              2. Linux 内核文档(过时?):https://www.kernel.org/doc/Documentation/virtual/kvm/timekee

              3. 详细的 SUSE 博客文章,包含大量链接:https://www.suse.com/c/cpu-isolation-nohz_full-troubleshooti

              6. Linux补丁(未提交?)用于尝试直接同步TSCs:https://lkml.rescloud.iu.edu/2208.1/00313.html

      2. 即使API已修复,针对损坏API的巧妙变通方案仍长期存在。人们仍然避免使用flock(2)之类的功能,因为过去NFS在文件锁定方面处理不当。如今,CLOCK_MONOTONIC_RAW在vDSO下运行良好。

        1. 遗憾的是,GPFS 仍不支持 flock(2),因此我仍避免使用它。

            1. 它不支持,至少在我有权访问的版本中,因为它在该集群上是这样配置的。

              我使用的是Linux而非AIX。

              fcntl(2)锁支持(只要它们不是OFD),但flock(2)锁在节点间无法工作。

      3. 这是很久以前的事(大约2009年10月左右),但我遇到一个特别有趣的性能问题,部分与RDTSC相关。在研究生课程项目中,我正在测量在多核处理器上运行多线程 Python 代码时 Python GIL 的影响。我原本预计随着线程/核心数量的增加,开销/锁竞争会变得更糟,但性能却以一种我未曾预料的方式急剧下降。这对课程项目来说是个不错的结果,让演示文稿变得有趣得多。

        问题最终在于,我的多线程代码在单核运行时会将该核心的CPU使用率锁定在100%,这符合预期。但当在4个核心上运行时,每个核心的CPU使用率仅为25%。这导致时钟调节器将核心频率从约2GHz降至900MHz,使得执行速度甚至比预期中的锁竞争问题更糟。这是一个有趣的谜题,值得深入研究一段时间。

      4. 如果你使用的是比奔腾4更新的处理器,频率将保持恒定。

        我不确定当核心分配到不同数量时,具体细节是怎样的。

      5. TSC(时钟周期调整)与核心消耗的周期有关,而非实际时间。因此在微基准测试中,这实际上是有意义的,因为在微基准测试中,你通常更关心 CPU 基准测试而非网络基准测试。

      6. 你需要将 TSC 与固定的 CPU 速度(例如 1000MHz)进行基准测试,这样才能获得可靠的比较。

    1. 这并未考虑笔记本电脑的频率调节、上下文切换、核心迁移、系统调用所花费的时间(如果你不想计算它)等因素。在 Linux 上,你可以让内核暴露真实(非“参考”)周期计数器,通过 __rdpmc() 函数(无需系统调用)访问它,并将校正偏移量存储在内存映射页面中。参见 perf_event_open() 手册页中 cap_user_rdpmc 下的示例代码[1],并特别注意其中的 rdpmc(idx-1) 中的 -1(我绝对没有在这上面浪费一个小时)。

      若要在 Windows 上实现,虽然理论上可行,但必须在不同线程中异步执行,并且需要自行计算偏移量[2])。

      或者,仅限于 AMD 处理器,从 Zen 2 开始,你可以通过 __aperf() 或 __rdpru(__RDPRU_APERF) 或根据你的编译器使用手动内联汇编来获取真实周期计数。(AMD 的官方文档会警告你不要对 APERF / MPERF 之外的任何内容赋予意义,但在其他地方的说明暗示 MPERF 必须是参考周期计数,而 APERF 必须是实际周期计数。)这确实麻烦少一些,但根据我的经验,Linux 上的 cap_user_rdpmc 方法要安静得多。

      [1] https://man7.org/linux/man-pages/man2/perf_event_open.2.html

      [2] https://www.computerenhance.com/p/halloween-spooktacular-day

      1. > 没有考虑笔记本电脑的频率调节

        你确定吗?

        > 系统调用所花费的时间(如果你不想计算它)

        系统调用所花费的时间是原帖作者主要测量目标。

        > 周期计数器

        虽然从技术上讲很有趣,但大多数时候我进行微基准测试时只关心墙钟时间。与搜索引擎和ChatGPT中看到的内容相反,RDTSC指令不是周期计数器,而是高分辨率墙钟计时器。该指令在20年前用于计数CPU周期,现在不再这样做了。

        1. >> 它不考虑笔记本电脑的频率调节

          > 你确定吗?

          > […] RDTSC指令不是周期计数器,而是高精度墙钟计时器 […]

          所以我们在这里达成一致:使用RDTSC不是在计数周期,而是在计数秒数。(这就是我所说的“不考虑频率缩放”的意思。)我猜这样做有正当理由,但我发现为墙钟测量设置实验环境极其困难:根据窗口是否打开、空调是否开启,或基准测试可执行文件重建所需时间的不同,会导致 10–20% 的差异,这实在令人头疼。在微基准测试中,我认为这使得RDTSC成为错误的工具,即使从技术上讲,它在付出足够努力后是可以使用的。在其他情况下,它可能是你唯一可用的工具,那么当然,你可以使用它。

          > 系统调用所花费的时间是原帖作者主要测量目标。

          我的意思是,当然,当我只讨论Linux和Windows时,我没有涵盖TFA的使用场景,但如果你想在Linux上包含系统调用时间,那也只是一个标志的距离。(有一个关于共享资源的注意事项——当然,你仍然没有计算kswapd或中断处理程序中的时间。)

          1. 周期通常不是你试图通过这种方式测量的事物。你关心的是程序是否具有更高的延迟、更低的吞吐量,以及其他以墙钟时间为单位的指标。

            循环是衡量算法各部分并估算其开销(例如汇编指令的延迟和吞吐量表)的理想指标。当频率调整与执行的指令无关时,循环也是理想的衡量指标(因为此时可以完全预测哪个算法更快,而无需考虑测量噪声)。

            然而,我们所处的现实世界并非如此。指令会影响频率调整——有些影响是相对直接的(例如,在某些架构上切换到重度AVX512路径的成本),有些是间接但可预测的(在没有低温设备的情况下,从芯片上散热的物理限制),有些是间接但不可预测的(在笔记本电脑上,当你将设备从腿上移到其他地方时,散热效果会发生变化)。如果你只测量指令计数,就会忽略诸如“更快”的算法因过热而始终使CPU降频2倍的影响。

            RDTSC这类工具的较好应用场景是微基准测试大型算法的子组件。你假设没有全局状态会影响性能(例如不会溢出分支预测缓存),然后测量目的就是计算你所做更改的增量,仅测量与性能相关的部分以提高信噪比。

            在这种情况下,我从未遇到过你描述的方差问题。计算机运行速度很快。只需将数十亿次操作通过算法运行,并比较分布结果。其中一种可能在平均速度上更快,另一种可能在尾部延迟上更优。谁知道你会更倾向于哪一种,但至少你知道自己确实测量了正确的内容。

            话说回来,即使标准差达到80%也不算太糟。在$WORK,我们经常对整个应用程序进行基准测试,即使是那些可以进行微基准测试的更改。为什么?因为这样更简单。如果只是延长测试时间,方差就不再重要。

            在某些情况下,你的观点是合理的。例如,也许一个命令行工具需要花费O(1秒)的时间来完成大量工作。热节流在现实世界中不会发生,但持续测试会出现节流(以及不同的分支预测等),因此计数周期是衡量你真正关心的事情的合理代理。

            我不知道;这很复杂。

      2. 有趣的是,每个新增的“标准”或内置函数实际上都无法提供承诺的真实数值。

    2. 虽然__rdtsc()很快,但在多核基准测试时要小心,因为核心之间的TSC同步在所有硬件上都无法保证,尤其是较旧的系统。现代Intel/AMD处理器具有“不变TSC”,这有所帮助,但首先检查CPU标志是值得的。

      1. Rdtsc 速度尚可,但仍约为 10 纳秒。若需测量极短时间间隔(测量 10 秒或 100 秒并摊销误差),这一点需特别注意。

      2. 不变 TSC 技术已存在超过 15 年,可能更久。

    3. > 我使用 __rdtsc() 编译器内置函数

      在 ARM 上你怎么做?

      1. 只需通过vDSO使用gettimeofday/clock_gettime。

          struct timespec ts;
          clock_gettime(CLOCK_MONOTONIC, &ts);
        

        在arm64架构下,它直接使用cntvct_el0寄存器,但通过标准且易于使用的API实现,而非使用内联汇编。此外,由于它是 vDSO,因此避免了上下文切换。

    4. 我认为它(不一定)在核心之间同步。不过我可能错了。

    5. rdtsc 并非在所有平台上都可用,仅供参考。它通常被禁用,因为有一个 CPU 标志允许在用户空间使用它,而且众所周知它不够准确。

      1. 哪些平台禁用了用户空间的 rdtsc?你认为它有哪些准确性问题?

        1. rdtsc 指令的访问权限由一个权限位控制。有时用户空间可以访问,有时则不行。过去曾出现过相关问题,但我现在记不清具体是哪种情况了。

          它也不如高精度计时器(HPET)准确。我不确定当前哪些平台会限制或开放这些功能,但情况各不相同。

          1. 我个人并不了解有哪个平台会阻止 rdtsc,因此我很好奇哪些平台会这样做。

          2. > 它也不如高精度计时器(HPET)准确

            这一说法大约10年前就不成立了。

            1. 你说得对,我之前想的是中断精度而非默认APIC计时器。

              不过,我之前提到某些平台禁用该功能的历史事实仍然成立。

              1. 我认为你将此与内核对 TSC 的黑名单处理混淆了,如果 TSC 未在 CPU 之间同步,内核会将其用于计时;虽然有一个开关可以阻止用户空间访问 TSC,但我认为这仅用于调试目的(例如记录/重放)。

    6. 他们本可以直接使用`clock_gettime(CLOCK_MONOTONIC)`

  2. 更合适的标题:针对 Linux 设计的病理测试程序不会在 OpenBSD 上触发病理行为

      1. 仍应避免让HN帖子聚焦于OpenBSD是否“总体上”比Linux更快。我最近多次看到这种情况:有人用吸引眼球的标题发布帖子,但实际内容是更窄且更有趣的技术话题,结果评论区所有人都忽略内容,只争论标题。

        1. 据我所知,OpenBSD在架构上与Linux 2.2类似,即存在一个锁,防止(大部分)内核代码同时在多个(逻辑)CPU上运行。

          我们听说随着时间推移,一些内核系统调用已移出该锁,但任何需要核心内核功能的操作都必须等待内核从所有其他CPU中释放。

          在这种情况下,内核可能运行得更快,但在高负载系统中,它可能成为受限资源。

          然而,这种方法更安全。

          1. 是的,他们目前正在努力解锁大多数系统调用,但据我所知,他们仍落后于 FreeBSD 一段距离。

            1. FreeBSD早在几十年前就移除了他们的“锁定”机制。

              1. 我认为BSDi(90年代AT&T诉讼中的实体)完成了这项工作。

              2. 我认为这是 FreeBSD 5(2003 年),没错。

        2. > 这是我最近经常看到的情况……

          > ……在评论中,大家忽略内容,只争论标题。

          你一定是刚接触Hacker News吧……

          1. 其实最近有几个特别令人沮丧的例子恰好引起了我的注意。当然,这个问题一直存在。

        3. 我认为在撰写帖子时,不应该考虑Hacker News的受众

          1. 我之前工作的一家公司会撰写帖子,将其发布到Hacker News,然后在Slack中分享HN链接,并要求所有有账号的人为其点赞

            1. 我猜Hacker News的后端会检测到这样的“投票团伙”,他们经常一起投票。

  3. OpenBSD有很多优点,但“快速”并不是第一个想到的词。

    轻量级?是的。

    极简主义?绝对是。

    紧凑?当然。

    但快速?不。

    我会用 OpenBSD 托管数据库或文件服务器吗?绝对不会。

    启动时间似乎和 20 年前一样慢。他们还倡导各种牺牲速度的安全措施,这也没关系。

    但别假装它是什么它不是的东西。

    1. 我不同意你对极简主义的评价,开箱即用的OpenBSD通常包含一切,包括厨房水槽,我并不抱怨,这是良好、稳固且编写精良的软件。但我从未找到过一个基础Linux发行版能像基础OpenBSD安装那样功能齐全。

          C编译器
          Web服务器
          3个路由守护进程(bgpd、ospfd、ripd)
          邮件服务器(smtpd、spamd)
          声音服务器(sndiod)
          反向代理(relayd)
          2个桌面环境(fvwm、cwm)
          以及更多更多
      

      OpenBSD并非某种极简主义的高度专注型操作系统,我的意思是,它到底是用来做什么的?根据其包含的功能,它似乎是一个集桌面开发系统、路由器、办公网页服务器和邮件服务器于一体的系统?

      我个人非常喜欢它,每次完成全新安装后,我都觉得自己可以仅凭眼前已有的工具从头重建整个互联网。

      1. fvwm 和 cwm 是窗口管理器,绝对不是桌面环境。

        1. 它们主要是窗口管理器,这是它们的主要界面,但它们也能启动程序并显示状态,所以我认为它们是功能丰富的窗口管理器。由于它们通常是桌面上唯一的环境,因此它们也是轻量级的桌面环境。

          将 cwm 与 xfwm 进行比较。虽然 cwm 在外观上极度简洁,但它拥有足够的额外功能,可以作为独立的桌面环境使用,而 xfwm 则需要多个独立组件才能在桌面上正常运行。

    2. 我认为 OpenBSD 在过去 4 到 5 个版本中已经快了很多。遗憾的是,我们需要等待phoronix进行另一轮基准测试,因为每次进行基准测试时似乎都会出现问题。

      或许在某个阶段,它会变得足够快,某些应用程序可能会因不同原因选择使用它。

    3. OpenBSD的运行速度比20年前快得多,这得益于将锁定机制发送到/dev/null。

      1. 为原帖辩护,新内核会在每次启动时重新链接。这一负载是明显的。

        这是ASLR的强化版,它确实大大增加了内核攻击的复杂性,但这是计算和I/O负载,而我所知的任何Linux版本都不会施加这种负载。

        重新链接C库相较之下相对快速。

        1. _> 作为对原帖的辩护,新内核会在每次启动时重新链接。这种负载是明显的。

          我不能说我同意你认为负载显著的暗示。我的2020年低功耗移动版Ryzen在9秒内完成内核重新链接。耸肩。

          如果用户偏好,完全可以禁用开机时内核重新链接,转而接受每次有补丁时重新链接内核。

          1. 我理解你的顾虑,但有些人使用的是配置较低的设备。

            试试树莓派。

            1. 它们当然不算快,尤其是在基于 SD 卡的存储设备上运行时,这种存储设备在处理此类过程所需的密集型小随机写入时速度极其缓慢。但这并不能说明 OpenBSD 的问题,只是说明了这种硬件的局限性。毕竟,如果你在 Linux 下链接 Linux 内核,或在 FreeBSD 下链接 FreeBSD 内核,或启动 Chromium 并恢复数十个标签页等操作时,也会遇到同样的问题。

              1. 可调整大小的RAM磁盘可以解决I/O问题。

  4. 有趣。我尝试跟进链接中的讨论,唯一得到的结论是“与RCU相关”。简要解释是什么?

    1. 在Linux中,进程的文件描述符表(fdtable)初始大小至少为256个槽位。两个线程各自创建256个套接字,加上已存在的三个文件描述符(用于标准输入、标准输出和标准错误),总共使用512个文件描述符。当容量从256扩展到512时,fdtable需要在扩展到一半时进行扩展,而在从512扩展到1024时,又需要在接近结束时进行扩展。

      此操作由内核中的 expand_fdtable() 函数完成。该函数包含以下代码:

              if (atomic_read(&files->count) > 1)
                synchronize_rcu();
      

      files->count 字段是一个引用计数器。由于有两个线程共享一组打开的文件,该值为 2,因此在 fdtable 扩展过程中会在此处调用 synchronize_rcu()。这会等待 RCU 缓冲期完全结束,导致创建当前套接字时获取新文件描述符(fd)出现延迟。

      如果在创建新线程之前扩展 fdtable(测试程序可通过调用 dup(0, 666) 实现,前提是提供了命令行参数),则可避免调用 synchronize_rcu(),因为此时 files->count == 1。因此,如果执行此操作,后续创建所有套接字时将不会出现延迟,因为 fdtable 已具备足够容量。

      相比之下,OpenBSD 内核没有类似 RCU 的机制,而是仅在进程的文件描述符表被修改时使用 rwlock,从而避免了在 Linux 中可能观察到的扩展过程中的长时间延迟。

      1. 感谢您的解释。我通过启用 dup 调用确认了性能时序差异。

        我想我的问题是,为什么synchronize_rcu会花费数毫秒(20+)来运行。我原本预计这应该在极低的毫秒级别甚至更短。

        1. > 从正确的虚拟内存中分配内核对象会让这更容易。目前Linux直接从所有物理内存的线性映射中分配内核对象。

          我认为这是阅读完整线程的关键要点:这在一定程度上是对内核内存分配方法的基准测试,揭示了在仅 256 x 2 次分配时 FD 性能的意外差异。推测我们看到的是从实际场景中提炼出的测试案例,其中因某种原因追踪到了这种性能下降?

        2. 这就是它们的设计方式;它们旨在在某个时间点完成,但这个时间点并不近。有一种“加速RCU”,据我所知,它试图通过“催促”所有人尽快通过障碍,但我不知道这在这里是否合适。

      2. 首次阅读此代码时,这似乎是分配文件描述符(fd)与“安装”指向文件的指针之间分离的后果。分配 fd 本身已需要获取锁。因此,如果安装与分配同时进行,就无需使用 synchronize_rcu 来驱逐其他线程。锁本身会完成这一操作。

    2. 当两个线程顺序分配套接字时,它们会争夺锁。如果你通过先创建文件描述符 666 来预分配一个更大的表,锁竞争就会消失。

      1. 这是 Windows NT 始终令人感兴趣的一点,它拥有多级对象句柄表,且没有关于重复使用最低可用表索引的规则。在这种架构中,存在减少线程之间竞争的空间。

        尽管:

        1. 在应用程序模式代码中,语言运行时库使事情看起来像一个 POSIX API,并维护自己的表映射对象句柄到类似 POSIX 的文件描述符,其中存在对最低可用条目的旧竞争;以及

        1. 在实践中,对象句柄表似乎主要进行追加,因此多个打开对象的线程都竞争表的末尾。

        1. 最低编号复用也是一个健壮性问题。如果多线程程序发生未分配内存(UAF)或双重释放文件描述符,它们可能会触及其他程序部分拥有的文件描述符,导致各种数据损坏和内存安全问题。从一个大型域中分配编号(无论是随机分配还是从排列序列中分配)将大大降低这种概率,并导致及时错误。

          1. 我希望有一个不保证最低编号重用的替代 Unix ABI,正是出于这个原因。我想你可以(几乎)直接劫持 close 调用,并用 dup2 调用 /dev/null 或类似操作替换它(但这样会忽略 close 错误)。

            1. 这可以在用户空间通过 F_DUPFD 实现。但这很昂贵,因为内核表是为密集数据优化的,而非稀疏数据。

              Rust标准库在调试构建中检测到双重关闭时会终止程序;此时数据可能已损坏,但总比什么都不做强。

              1. > Rust标准库在调试构建中检测到双重关闭时会终止程序

                在EBADF上?不错。

      2. RCU 是一种非常明确的无锁同步策略。

      3. 这不是它变慢的原因。2×256 在 CPU 时间中并不是很多锁。

        1. 锁定的问题不在于锁定机制本身的开销,而在于必要的串行化。

          1. 再次强调,互斥锁竞争/串行化并非导致速度慢的原因。

  5. 不,通常 Linux 至少比 OpenBSD 快 3 倍,因为他们不太在意优化。

    1. OpenBSD 在某些特定领域确实要快得多。例如,从 `/dev/urandom` 生成随机数。当我还在大学的时候(大概是 2010 年左右),在我的 OpenBSD 笔记本电脑上读取 `/dev/urandom` 并通过以太网管道传输到朋友的 Linux 笔记本电脑上,比直接在他的电脑上运行 `cat /dev/urandom > /dev/sda` 更快。

      差距不仅是一点点,而是达到了 10MB/s 和 100MB/s 的差异。

      1. 我想你应该是想说 /dev/random,而不是 /dev/urandom。

        在 Linux 中,/dev/random 过去会因等待来自网络抖动、鼠标移动、键盘输入等随机性来源的熵而暂停。而 /dev/urandom 在 Linux 上一直很快。

        如今,Linux 的 /dev/random 主要在初始化后使用随机数生成器(RNG)。BSD 系统一直都是这样做的。在我的笔记本上,我能达到超过 500MB/s(内核 6.12)。

        据我所知,在现代 Linux 内核中,/dev/urandom 现已成为 /dev/random 的别名,以保持向后兼容性。

        1. 普通用户空间代码(不属于系统发行版本身)无需使用 /dev/random,而 getrandom(2) 在未设置 GRND_RANDOM 时可能是适用于所有场景的正确解决方案。

          Linux 和 BSD 均使用 CSPRNG 来满足 /dev/{urandom,random} 和 getrandom 的需求,并为未来保密性/防泄露保护,持续用哈希高熵事件更新熵池(从实际密码学角度而言,“种子化” CSPRNG 几乎无需重新密钥,但出于实际系统安全考虑仍需执行此操作)。

      2. OpenBSD 于 2012 年将 PRNG 切换为 arc4random(随后于 2014 年切换为 ChaCha20);根据您对时间的估算精度,这很可能就是原因。Linux 于 2016 年切换为 ChaCha20。

        相关地,去年我在研究PRNG时发现[0],我的Mac生成UUID的速度比Linux服务器快得多,即使考虑了架构和时钟速度差异。原来,glibc直到2.36版本才引入arc4random,而我当时使用的Debian版本并未包含2.36。相比之下,由于MacOS基于BSD,它早已支持该算法。

        [0]: https://gist.github.com/stephanGarland/f6b7a13585c0caf9eb64b

      3. 大约10年前,我的Linux虚拟机客人拒绝生成GPG密钥,GPG坚持需要那个愚蠢的阻塞式随机设备,而由于虚拟机客人无法获取任何“熵”,整个过程陷入僵局。作为 OpenBSD 用户,我自然感到愤怒。虽然存在许多合理的解决方案,但我并未采用任何一种。相反,我找到了 rngd 服务,该服务可从网络源接受“熵”,并用同一虚拟机主机上新创建的 OpenBSD 虚拟机中的 /dev/random 向其输入数据。主要是出于报复心理。“看这里,你这小混蛋,这就是生成随机数的方式”

      4. /dev/urandom 并不是一个很好的测试,我认为,仅仅是因为在安全性和速度之间存在合理的权衡。

        据我所知,BSD 可能在使用 31*last 或类似的算法。

        算法也可以自由更改。

        1. 嗯……这场讨论是关于 OpenBSD 的,因此这个反对意见显得格外有趣。OpenBSD 在所有情况下都以优先考虑正确的安全措施而闻名,这种声誉大多是实至名归的。

          但这也正是为什么随机数生成器(RNG)相关功能在OpenBSD中要快得多。在很长一段时间内,负责随机数生成的Linux开发者相信一些迷信而非实际的安全实践,选择了毫无根据的慢速系统而非经过充分研究的快速系统。Linux终于进入了现代时代,但在此之前,其随机数生成功能远不如由具备安全背景的人员开发的系统。

          1. OpenBSD并不比Linux在安全性上更具优势。或许20年前是这样。如今更准确的说法是,Linux和OpenBSD采取了不同的安全策略——两者存在实质性差异,但这些差异并非简单地沿着“好”到“坏”的单一维度分布。

            (我曾在 OpenBSD 安全审计的鼎盛时期,以边缘角色参与过 OpenBSD 安全工作。)

            1. 难道他们最近没有出现过一些令人尴尬的远程代码执行漏洞吗?这让人质疑关于“默认安装存在漏洞”的声明——即使是 Windows 如今也已不再默认暴露任何服务。

              最终,他们缺乏开发资源。

              这令人遗憾,因为这是一个高度集成的系统(与每个Linux发行版那拼凑的补丁被子形成鲜明对比)。但我怀疑正是项目领导层的问题让更多人望而却步。

              1. 我发现OpenBSD社区的态度有些傲慢,这可能只是巧合,我也不确定。我一直喜欢NetBSD,因为我从未遇到过类似的问题。

                1. 我的经验是,他们期望你阅读文档并提出有针对性的问题。大多数内容都可以在文档、README等文件中找到。

                  1. 是的,阅读文档就像阅读他们多年来过时的文章、教程、出版的书籍等,当他们决定在pf.conf中引入向后兼容性中断时,任何信任他们来构建一个无需现场访问即可升级的防火墙的人都会遇到问题。

                2. 我记得与一位OpenBSD开发者的讨论,他对于缺乏日志文件系统的回答是简单地使用UPS,就像任何普通计算机用户应该做的那样(虽然有一些业余操作系统支持日志文件系统,但由于OpenBSD的开发模式过于陈旧,开发者无法进行像新文件系统这样的重大工作)。

                  1. 他们可以很快将NetBSD的WAPBL移植过来。

    2. 他们更关心安全问题。在 Linux 中实现相同的缓解措施可能会让系统运行得更慢。

  6. 是的,我不得不修改你的网站才能让它可读。为什么人们要这样做?

    1. 在移动设备上看起来不错。高对比度,行长度适中。你遇到了什么问题?

      1. 页面左下角和右下角各有两个小工具,它们会不断向屏幕各处发射小点,追踪鼠标指针。在我屏幕的稳定状态下,大约有20个精灵在页面上不断移动。除了检查页面并删除小工具外,似乎没有明显的方法可以禁用它们。

        如果你希望我阅读你的网站,并且希望在网站上放置详细的技术信息,请不要添加此类没有关闭开关的功能。

        1. 奇怪的是,一旦我的鼠标指针被其中一颗子弹击中,射击者就会消失,直到我刷新页面。在射速增加的情况下,连续几秒钟不被击中实际上相当困难。我一开始甚至没有注意到它们,因为我的鼠标指针被前几颗子弹击中了。

          也许行为发生了变化。

        2. 非常令人沮丧,我用鼠标指针阅读,这使得阅读变得不可能。

        3. 这可能是最近作为玩笑添加的,但我不知道具体原因。

  7. 这算是个愚蠢的“基准测试”,但既然要走这条路:

    Linux:耗时:0.019895秒

    nanos(在上述Linux上运行):耗时:0.000886秒

  8. 所以……本质上是在测试文件描述符分配的开销

    1. 差不多。文件描述符表的大小,这与文件描述符本身略有不同(一旦达到ulimit限制,就没有必要将其扩大);而且仅在多线程程序中有效。

  9. 我无意中将手指放在屏幕上,触发了一个彩蛋,两个“炮台”开始发射方块。其他人也注意到这个彩蛋了吗?

    1. 我也看到了,而且是在非触摸屏的电脑上发生的。

    2. 我得说,这是我第一次对彩蛋感到不满,以至于无法继续阅读文章。

  10. 在我看来,更快意味着在相同图形设置下,同一款游戏能获得更高的帧率

    (我甚至不知道主流游戏是否能在BSD上运行)

    1. 这主要受限于GPU硬件,以及与主机平台 largely 独立的二进制代码包,对吧?

        1. 当人们声称这一点时,我感到很烦。这取决于游戏、发行版、Proton版本、桌面环境,以及其他许多我已经忘记的因素。

          此外,Linux上的延迟通常更差。我在Linux和Windows上玩了很多快速反应游戏,虽然帧率和帧时间通常在同一水平,但延迟要高得多。

          其他问题是,Proton 的兼容性参差不齐。Valve 声称已认证的一些游戏实际上运行不佳,模组可能存在问题,而且通常需要通过调整自定义启动选项才能让游戏正常运行。

          1. 许多游戏在我这里神秘地无法运行,几乎就像 Proton 在我的系统上存在普遍问题,而我无法找出原因。然而,过去我曾让一些专为Windows设计的游戏在WINE上运行得比在Windows上更好。其中一款游戏是《星际争霸2》刚发布时。在Windows上,它会在单人战役的一个电影/序列中卡住,这使得它在Windows上实际上无法玩,而经过一些尝试和错误后,我成功在GNU/Linux上让游戏完全正常运行,并完成了战役。

            这说明,使用Proton和不同硬件以及系统配置的体验因人而异,但游戏确实可以在WINE或Proton上运行得比其原生系统更好。

            1. 我认为,稳定性比任何理论上的帧率提升都更重要。

              对于那些无法在现代Windows上运行的游戏,通常有粉丝补丁/模组可以修复这些问题。

              对于现代游戏,经常会出现一些奇怪的帧率问题,这些问题在Windows上很少发生。当我玩多人在线、快速反应的游戏时,我不想让帧率随机下降。

              我从2019年开始在Linux上独家游戏,今年早些时候放弃了。我想玩《红色警戒2》,尝试弄清楚如何使用WINE和其他东西是一件令人头疼的事。在Windows上一切都很简单。

    1. 我正准备把Ian Betteridge指向原标题。(-:

  11. 更好的做法(抱歉)是增加负载而非修改测试。我很乐意听听他们为何认为这种方式能成为更好的基准测试。

    1. 在Linux上测量的现象是进程生命周期中的一次性事件。

  12. 我的猜测是这与文件描述符表中存在大量空闲条目有关(即dup2(0, 666)这行代码)。

    现在是时候阅读实际的讨论内容了。

    1. 我认为dup2是关键,但在示例案例中dup2路径并未被调用——它取决于传递参数,但测试运行只是./a.out。据我理解,问题在于文件描述符表的增长。dup2是一个变通方案,它预先分配一个更大的表(666 > 256 * 2)[1], 以避免多线程进程扩展表时出现的异常情况。从链接的 infosec.exchange 讨论中可以看出,Linux 使用的基于 RCU 的方法可能会导致一些显著的延迟,导致在像这样的简单情况下,与简单的互斥锁相比,性能要差得多[2].

      [1] 数值错误。更准确地说,由 dup2 建立的状态是 (667 > 256 * 2),或者更确切地说 (667 > 3 + 256 * 2)。

      [2] 可能是 OpenBSD 正在使用的方案。我怀疑他们是否已经引入并采纳了链接讨论中提到的 FreeBSD 方案,尽管 OpenBSD 在过去几年中一直在 MP 可扩展性方面取得显著进展。

  13. FreeBSD 中的情况如何?是否能达到相同的结果?

    1. FreeBSD 在内核中不使用 RCU,因此不太可能与 Linux 存在相同的 ~ 问题。任何简单的实现都能达到与 OpenBSD 相同的良好性能。

      FreeBSD 的等效实现位于此处(它在独占锁下完成所有操作):http://fxr.watson.org/fxr/source/kern/kern_descrip.c#L1882

      它不使用RCU,但会对自由列表中的旧版本fdtable进行一种定制的引用计数保留。

  14. “这要看情况”

    更快是相对的。你在做什么?是网络相关吗?如果是,那么BSD可能比Linux更快。如果是Linux优化过的场景?那可能是Linux。

    一个通用基准测试?谁知道呢,但这真的重要吗?

    归根结底,你应该测试自己的工作负载,但也要意识到,在这个时代,几乎从来不是操作系统是瓶颈。几乎总是远程网络调用。

    1. 这篇文章比标题稍有趣一些,而且篇幅不长。不妨读一读。

      1. 我读过这篇文章。它讨论了一个特定的使用场景,本身并不特别有趣。

  15. 基准测试软件的第一步是使用相同的硬件。

    作者未能完成第一步。

    此后的一切都是垃圾。

    1. 你明白那些懂得如何进行基准测试的人其实不需要遵循给非专家的经验法则,以免自掘坟墓,对吧?你也会因为拉力赛车手双脚踩在两个踏板上就否定他们吗?

      1. 我不知道你怎么样,但我做过不少基准测试和性能工程。

        在这个领域,你首先要明白的是,除非你比较的是相同配置的系统(苹果对苹果),并且使用相同的负载配置,否则你基本上就是在玩儿。

        我的意思是,玩耍和观察是可以的,但那只是玩耍。这不是什么值得认真对待的事情。

        1. 玩耍不是垃圾。很多性能工程就是不把自己当回事。署名:一位专业的性能工程师 🙂

  16. 资源配置是什么?与Linux资源配置相比如何?

    当前的默认设置在etc.amd64/login.conf中。https://cvsweb.openbsd.org/cgi-bin/cvsweb/checkout/src/etc…

    (附言:气泡效果很酷。对我来说非常分散注意力,因此我无法完整阅读这篇文章。)

    1. Linux版本本质上是在测量一个(令人惊讶的)睡眠状态;并非资源受限。

    1. 这非常分散注意力。我平时并不需要减少动作来解决问题,但这些小行星本身就几乎足够分散注意力,而它们导致我的Cursor消失,这确实是一个可访问性问题。直到现在我才意识到,我在阅读时实际上有多依赖鼠标Cursor,部分是因为它让我感到安心,部分是因为它是我眼睛在页面上扫描时的可控视觉锚点。

      我根本无法在该网站上阅读内容。我在阅读时会移动鼠标,并不一定在当前阅读的文字附近,因此当鼠标消失时会造成断断续续的干扰。此外,该“游戏”的视觉效果与我试图阅读的文本产生冲突,使得专注阅读变得极其困难。这两点结合起来,使该网站对我而言几乎无法阅读。

      我不明白为什么人们继续发布并为这个用户不友好的网站的文章点赞。

    2. 正是这样的网站让我对火狐的阅读模式感到无比感激。

    3. 我发现阅读起来极其困难,所以我最终应用了这些uBlock过滤规则以便阅读:

        flak.tedunangst.com##.bl.shooter<BR />  flak.tedunangst.com##.br.shooter<BR />  flak.tedunangst.com##div.bullet
      1. 描述的行为听起来比轻微的烦人要严重得多,即使在现代用户不友好的网站上,这种情况也不常见。

    4. 他以前有一个加载屏幕,如果你在浏览器中启用了JS,它什么也不做,但如果你禁用了JS,就没有加载屏幕(同样什么也不做)。我敢肯定这是故意让人烦躁的,不过这个比加载界面要好一些。

    5. 不,这是网站的错,因为它做了些愚蠢的可爱小把戏,让页面更难阅读。别在这里自责。

      1. 我真的不明白这个“一切都必须100%严肃”的观念。为什么这很愚蠢?

        1. HN的集体智慧谴责当今互联网缺乏人性与个性,但同时又要求每个网站必须100%纯文本,不允许使用JS或CSS,因为据称没人需要CSS,而如果你敢在布局上做任何“花哨”的尝试,就必须用<table>标签来实现。

          1. 这并非关乎“缺乏人性化”,而是违反了基本用户体验(UX)规则,例如在随机时间隐藏Cursor。这种行为令人反感。

        2. 我认为这类设计能让网络变得更有趣。

          但这次确实有些分散注意力。

  17. BSD用户似乎很喜欢测量和记录数据。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: