相关疑难解决方法(0)

当base + offset与基数不同时,是否存在惩罚?

这三个片段的执行时间:

pageboundary: dq (pageboundary + 8)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx - 8]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

还有这个:

pageboundary: dq (pageboundary - 8)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx + 8]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

还有这个:

pageboundary: dq (pageboundary - 4096)
...

    mov rdx, [rel pageboundary]
.loop:
    mov rdx, [rdx + 4096]
    sub ecx, 1
    jnz .loop
Run Code Online (Sandbox Code Playgroud)

对于第一个片段,在4770K上,每次迭代大约5个周期,对于第二个片段,每次迭代大约9个周期,然后是第三个片段的5个周期.它们都访问完全相同的地址,这是4K对齐的.在第二个片段中,只有地址计算跨越页面边界:rdx并且rdx + 8不属于同一页面,负载仍然是对齐的.如果偏移量很大,则会再次回到5个周期.

这种效果一般如何起作用?


通过ALU指令从加载路由结果,如下所示:

.loop:
    mov rdx, …
Run Code Online (Sandbox Code Playgroud)

performance x86 assembly micro-optimization

11
推荐指数
1
解决办法
456
查看次数

如何避免在64位指针上浪费内存

我希望就如何处理我即将进行的设计提出一些高级建议.

解决我的问题的直接方法将导致数以百万计的指针.在64位系统上,这些可能是64位指针.但就我的应用程序而言,我认为我不需要超过32位的地址空间.我仍然希望系统能够利用64位处理器算法(假设这是我在64位系统上运行得到的).

进一步背景

我正在实现一个树状数据结构,其中每个"节点"包含一个8字节的有效负载,但也需要指向四个相邻节点(父节点,左子节点,中间子节点,右子节点)的指针.在使用64位指针的64位系统上,这相当于32字节,仅用于将8字节有效负载链接到树中 - "链接开销"为400%.

数据结构将包含数百万个这样的节点,但我的应用程序除此之外不需要太多内存,因此所有这些64位指针看起来都很浪费.该怎么办?有没有办法在64位系统上使用32位指针?

我考虑过了

  1. 将有效载荷存储在数组中,使得索引暗示(并暗示)"树地址",并且可以使用该索引上的简单算术计算给定索引的邻居.不幸的是,这需要我根据树的最大深度调整数组的大小,这是我事先不知道的,并且由于较低级别中的空节点元素,它可能会产生更大的内存开销,因为不是树的所有分支走到同样的深度.

  2. 将节点存储在一个足够大的数组中以保存所有节点,然后使用索引而不是指针链接邻居.AFAIK这里的主要缺点是每个节点都需要数组的基地址才能找到它的邻居.所以他们要么需要存储它(一百万次),要么需要传递每个函数调用.我不喜欢这个.

  3. 假设所有这些指针中最重要的32位为零,如果不是则抛出异常,并且仅存储最低有效32位.因此可以根据需要重建所需的指针.该系统可能使用超过4GB,但该过程永远不会.我只是假设指针偏离了进程基地址,并且不知道这对于通用平台(Windows,Linux,OSX)有多安全(如果有的话).

  4. 存储64位和64位指针之间的差异this,假设这个差异将在int32_t(并且如果不是)的范围内.然后任何节点都可以通过添加该偏移来找到它的邻居this.

有什么建议?关于最后一个想法(我目前认为这是我最好的候选人),我可以假设在一个使用少于2GB的进程中,动态分配的对象将彼此相差2 GB以内吗?或者根本不是吗?

c++ pointers memory-management cross-platform 32bit-64bit

6
推荐指数
1
解决办法
696
查看次数

有什么方法可以使用 MOV 在 32 位 x86 中移动 2 个字节而不会导致模式切换或 CPU 停顿?

如果我想将 2 个无符号字节从内存移动到 32 位寄存器中,我可以用MOV指令而不用模式切换来做到这一点吗?

我注意到您可以使用MOVSEMOVZE说明来做到这一点。例如,通过MOVSE编码0F B7将 16 位移动到 32 位寄存器。不过,它是一个 3 周期指令。

或者,我想我可以将 4 个字节移动到寄存器中,然后以某种方式仅 CMP 中的两个。

在 32 位 x86 上检索和比较 16 位数据的最快策略是什么?请注意,我主要进行 32 位操作,因此我无法切换到 16 位模式并留在那里。


仅供初学者参考:这里的问题是 32 位 Intel x86 处理器可以处理MOV8 位数据和 16 位 OR 32 位数据,具体取决于它们所处的模式。这种模式称为“D 位”设置。您可以使用特殊前缀 0x66 和 0x67 来使用非默认模式。例如,如果您处于 32 位模式,并且您使用 0x66 作为指令前缀,这将导致操作数被视为 16 位。唯一的问题是这样做会导致性能下降。

performance x86 assembly intel

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