title: Performance implications of context switches for 64-bit segment bases
body: <p>I'm confused by the wording in the manual page for <a href="http://www.kernel.org/doc/man-pages/online/pages/man2/arch_prctl.2.html" rel="noreferrer"><code>arch_prctl(2)</code></a>. Specifically, it states:</p>
  
  <blockquote>
    <p><strong>Context switches for 64-bit segment bases are rather expensive.</strong>  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.</p>
  </blockquote>
  
  <p>Does this mean that context switches for a process that uses this system call will receive a performance penalty or what are the exact implications?</p>
  
  <p>After looking through the source of the Linux kernel, it appears that for addresses that are &lt;4 GiB use the LDT, while >4 GiB addresses use a model-specific register.</p>
  
  <p>From <a href="http://lxr.free-electrons.com/source/arch/x86/kernel/process_64.c?a=microblaze#L446" rel="noreferrer"><code>do_arch_prctl</code></a>:</p>
  
  <pre><code>case ARCH_SET_FS:
          /* handle small bases via the GDT because that's faster to
             switch. */
          if (addr &lt;= 0xffffffff) {
                  set_32bit_tls(task, FS_TLS, addr);
                  if (doit) {
                          load_TLS(&amp;task-&gt;thread, cpu);
                          loadsegment(fs, FS_TLS_SEL);
                  }
                  task-&gt;thread.fsindex = FS_TLS_SEL;
                  task-&gt;thread.fs = 0;
          } else {
                  task-&gt;thread.fsindex = 0;
                  task-&gt;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;
  </code></pre>
  
  <p>How can using the GDT be faster than writing to a register? Also, I assume the price of updating FS and GS is only paid when switching between processes, meaning there's no additional cost for entering the kernel via a system call when no other process is scheduled to run?</p>