c - 64 位段基础的上下文切换的性能影响

标签 c linux performance x86-64 cpu-registers

我对 arch_prctl(2) 的手册页中的措辞感到困惑.具体来说,它指出:

Context switches for 64-bit segment bases are rather expensive. It may be a faster alternative to set a 32-bit base using a segment selector by setting up an LDT with modify_ldt(2) or using the set_thread_area(2) system call in kernel 2.5 or later. arch_prctl() is only needed when you want to set bases that are larger than 4GB. Memory in the first 2GB of address space can be allocated by using mmap(2) with the MAP_32BIT flag.

这是否意味着使用此系统调用的进程的上下文切换将受到性能损失或具体含义是什么?

查看 Linux 内核的源代码后,似乎对于 <4 GiB 的地址使用 LDT,而 >4 GiB 地址使用特定于模型的寄存器。

来自 do_arch_prctl :

case ARCH_SET_FS:
        /* handle small bases via the GDT because that's faster to
           switch. */
        if (addr <= 0xffffffff) {
                set_32bit_tls(task, FS_TLS, addr);
                if (doit) {
                        load_TLS(&task->thread, cpu);
                        loadsegment(fs, FS_TLS_SEL);
                }
                task->thread.fsindex = FS_TLS_SEL;
                task->thread.fs = 0;
        } else {
                task->thread.fsindex = 0;
                task->thread.fs = addr;
                if (doit) {
                        /* set the selector to 0 to not confuse
                           __switch_to */
                        loadsegment(fs, 0);
                        ret = wrmsrl_safe(MSR_FS_BASE, addr);
                }
        }
        put_cpu();
        break;

使用 GDT 如何比写入寄存器更快?另外,我假设更新 FS 和 GS 的代价仅在进程之间切换时支付,这意味着当没有其他进程计划运行时通过系统调用进入内核不会产生额外成本?

最佳答案

哇,这是在 12 月提出的问题,却没有人回答?其中一些您可能已经知道,如果是这样,我深表歉意。

只是因为做wrmsr的步骤比较慢。在任务切换时只加载段寄存器更容易和更快。

在非常现代的 Intel 处理器上,添加“rdfsbase”、“wrfsbase”、“rdgsbase”和“wrgsbase”指令允许直接访问 FS 和 GS 的基址寄存器,难度比以前小得多。事实上,如果内核愿意,可以允许它们从用户模式使用。您可能想要检查现代 Linux 内核是否利用 wrfsbase 来无需分配低于 4 GB 的 TLS 区域。

我不知道它在 Linux 上如何,但是从 Windows 7 开始的 Windows NT 将用户模式线程调度作为应用程序开发人员的可选功能。与在 Linux 和 Mac OS X 中一样,Windows 使用段寄存器的基地址(x86-64 Windows 中的 GS)在 x86 上实现线程本地存储。此功能类似于纤程,不同之处在于程序可以以内核也能识别的方式将自己的线程上下文切换到另一个线程上下文。

Windows 中的用户模式调度是通过为每个可调度线程创建一个 LDT 来实现的,其中的段指向 TLS block (在 Windows 中称为“线程环境 block ”或 TEB)。除了上下文切换之外,用户模式还可以通过重新加载 GS 库来切换线程。这要求 TEB 低于 2^32,如 Linux 的 arch_prctl's performance note - 否则,用户模式调度将需要在每次切换到不同线程时调用 NT 内核以执行 wrmsr,从而打败整点用户模式调度。

在 Windows 8.1 中,添加了对 wrgsbase 的支持,并且还为用户模式启用了它。 8.1 中的用户模式调度使用 wrgsbase 而不是 GS 段重新加载和 LDT(如果 CPU 有的话)。

关于c - 64 位段基础的上下文切换的性能影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14665805/

相关文章:

c++ - Linux 新手 : C++ opening and closing usb port issues

performance - 端到端测试大数据管道的工具?

android - 为什么在我的设置中使用多个项目为 android 开发速度很慢?

c - 如何知道/更改 fuse readdir 函数中的缓冲区大小?

c - Win32 消息循环 : Quitting after window closes with GetMessage(&msg, NULL、0、0)?

c - 为什么 `p()` 和 `(*p)()` 都有效?

linux - 将查找命令作为别名

linux - 杀死一个java僵尸进程

performance - 在 R 中合并/连接 data.frames 的最快方法是什么?

c - char*str= {"foo",...} 和 char str[][5]= {"foo",...} 数组定义有什么区别?