标签: x86-64

上下文切换对64位段基的性能影响

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

64位段基的上下文切换相当昂贵. 通过在内核2.5或更高版本中使用modify_ldt(2)或使用set_thread_area(2)系统调用设置LDT,使用段选择器设置32位基址可能是更快的替代方法.只有当您想要设置大于4GB的基数时,才需要arch_prctl().可以使用带有MAP_32BIT标志的mmap(2)来分配前2GB地址空间中的内存.

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

查看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);
                } …
Run Code Online (Sandbox Code Playgroud)

c linux performance x86-64 cpu-registers

22
推荐指数
1
解决办法
1565
查看次数

为什么这个函数将RAX作为第一个操作推送到堆栈?

在下面的C++源代码的汇编中.为什么RAX被推入堆栈?

正如我从ABI理解的那样,RAX可以包含来自调用函数的任何内容.但是我们将它保存在这里,然后将堆栈移回8个字节.所以堆栈上的RAX,我认为只与std::__throw_bad_function_call()操作相关......?

代码:-

#include <functional> 

void f(std::function<void()> a) 
{
  a(); 
}
Run Code Online (Sandbox Code Playgroud)

gcc.godbolt.org使用Clang 3.7.1 -O3 输出:

f(std::function<void ()>):                  # @f(std::function<void ()>)
        push    rax
        cmp     qword ptr [rdi + 16], 0
        je      .LBB0_1
        add     rsp, 8
        jmp     qword ptr [rdi + 24]    # TAILCALL
.LBB0_1:
        call    std::__throw_bad_function_call()
Run Code Online (Sandbox Code Playgroud)

我确定原因很明显,但我很难弄清楚.

这是一个没有std::function<void()>包装器的尾部调用,用于比较:

void g(void(*a)())
{
  a(); 
}
Run Code Online (Sandbox Code Playgroud)

琐碎的:

g(void (*)()):             # @g(void (*)())
        jmp     rdi        # TAILCALL
Run Code Online (Sandbox Code Playgroud)

c++ x86 assembly x86-64 abi

22
推荐指数
3
解决办法
2098
查看次数

由运行时常量值重复整数除

在我的程序中的某个时刻,我计算整数除数d.从那时起d,这将是不变的.

稍后在代码中我将除以它d几次 - 执行整数除法,因为值d不是编译时已知常量.

鉴于与其他类型的整数运算相比,整数除法是一个相对较慢的过程,我想优化它.我可以存储一些替代格式d,以便分割过程执行得更快吗?也许是某种形式的倒数?

我不需要d其他任何东西的价值.

d是任何64位整数,但通常很适合32位.

c++ optimization assembly x86-64

22
推荐指数
2
解决办法
1316
查看次数

NUnit在Windows 7/64上"丢失"了GPSVC.DLL

我最近从Vista/32升级到Win7/64.在我的旧机器上,一切正常.

不幸的是,在我的新机器上,NUnit不会加载我的单元测试,错误消息"System.IO.FileNotFoundException:无法加载文件或程序集'UnitTest'或其依赖项之一.系统无法找到指定的文件".(实际上,我必须完成我所有解决方案的项目,并将它们设置为32位才能实现这一目标.)

所以我加载了Dependency Walker,它告诉我我错过了IESHIMS.DLL.我在我的机器上发现了两个,所以我从Internet Explorer目录中复制了32位版本,DW停止抱怨该文件.

但是,它也缺少GPSVC.DLL.我在C:\ Windows\System32中只发现了一个这样的副本,但当我将其复制到我的单元测试目录中时,DW抱怨它是64位,而NUnit仍然无法运行.它现在还将SYSNTFY.DLL添加到缺少的列表中.我只有其中一个,那也是64位.NUnit仍然报告错误.

那么我应该废弃这个64位操作系统并回到原来的32位,还是我错过了一些明显的东西?

.net dll dependencies x86-64 32bit-64bit

21
推荐指数
1
解决办法
4万
查看次数

优化x64汇编程序MUL循环

我正在编写需要快速乘以大数的数学代码.它分解为整数数组与单个整数的乘法.在C++中,这看起来像这样(在unsigned上):

void muladd(unsigned* r, const unsigned* a, unsigned len, unsigned b) {
   unsigned __int64 of = 0;  // overflow
   unsigned i = 0;  // loop variable
   while (i < len) {
      of += (unsigned __int64)a[i] * b + r[i];
      r[i] = (unsigned)of;
      of >>= 32;
      ++i;
   }
   r[i] = (unsigned)of;  // save overflow
}
Run Code Online (Sandbox Code Playgroud)

我手动展开了这个循环,将其转换为64位并处理.asm编译器输出以进一步优化它.主.asm循环现在看起来像这样:

mov   rax, rdi                             ; rdi = b
mul   QWORD PTR [rbx+r10*8-64]             ; rdx:rax = a[i] * b; r10 = i
mov   rsi, QWORD PTR [r14+r10*8-64] …
Run Code Online (Sandbox Code Playgroud)

optimization assembly x86-64 multiplication gmp

21
推荐指数
1
解决办法
2318
查看次数

共享库是否使用与应用程序相同的堆?

假设我在Linux中有一个使用共享库(.so文件)的应用程序.我的问题是这些库中的代码是否会在与主应用程序相同的堆中分配内存,还是使用自己的堆?

例如,.so文件调用中的某些函数malloc是否会使用与应用程序相同的堆管理器或另一个?此外,那些共享内存中的全局数据如何呢?它在哪里?我知道它的应用程序位于bss和数据段中,但不知道它们对于那些共享对象文件的位置.

c linux gcc x86-64

21
推荐指数
2
解决办法
8409
查看次数

开头的双下划线的含义

在标准库(glibc)中,我看到使用前导双下划线定义的函数,例如__mmapin sys/mman.h.什么目的?我们怎样才能调用一个mmap似乎没有在任何地方声明的函数.我的意思是我们包括sys/mman.h,但sys/mman.h没有声明mmap,它只声明__mmap.

c linux gcc glibc x86-64

21
推荐指数
3
解决办法
1万
查看次数

英特尔是什么意思"退休"?

在" 英特尔手册"中,提到了许多性能事件,这些事件的描述类似于"错误预测的分支指令已退役".retired在这种情况下究竟意味着什么?

请注意,我已经查看了英特尔的性能分析指南,其中指出"退役"具有非常精确的含义(第8页),参考第7页的图表,但我认为我缺乏背景知识来准确理解什么是意思是Retirement / Writeback.这个过程究竟是什么?它涉及什么?

performance x86 x86-64 intel

21
推荐指数
1
解决办法
6858
查看次数

为什么新的展示位置比直接作业更快?

我最近发现使用placement new比执行16个赋值更快:
考虑以下代码段(c ++ 11):

class Matrix
{
public:
    double data[16];

    Matrix() : data{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 }
    {
    };

    void Identity1()
    {
        new (this) Matrix();
    };

    void Identity2()
    {
        data[0]  = 1.0; data[1]  = 0.0; data[2]  = 0.0; data[3]  = 0.0;
        data[4]  = 0.0; data[5]  = 1.0; data[6]  = 0.0; data[7]  = 0.0;
        data[8]  = 0.0; data[9]  = 0.0; data[10] = 1.0; data[11] = 0.0;
        data[12] …
Run Code Online (Sandbox Code Playgroud)

c++ performance gcc x86-64 c++11

21
推荐指数
1
解决办法
655
查看次数

x86-64 Linux中不再允许32位绝对地址?

64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.

这种变化的后果是必须重新编译旧库并破坏传统汇编代码.

现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?

linux gcc x86-64 linker-errors relocation

21
推荐指数
1
解决办法
5787
查看次数