performance - 为什么远指针很慢?

标签 performance cpu-architecture dos x86-16 memory-segmentation

我最近一直在 16 位 DOS 上编程一些东西来娱乐。我看到很多人提到远指针比近指针慢并且要避免它们。

为什么?

从装配的角度来看,这是有道理的。涉及一些额外的指令。您必须存储段寄存器的旧值,将新段存储到寄存器中,然后将其移到 CS 或 DS 中(立即模式存储在 8086 中不是有效的操作码)。然后您可以在该部分中执行您需要执行的任何操作。之后,您必须恢复旧值。

听起来很多,但实际上这并没有消耗很多周期。我想如果您使用的每个指针都在不同的段中,这可能会加起来,但数据通常是分组的。因此,除非你到处弹跳(由于其他原因而速度很慢),否则处罚应该不会那么严重。如果您必须使用 DRAM,那么这应该会主导成本,对吗?

我觉得这个故事还有更多内容,但我很难找到它。希望 8086 向导能记住这些东西。

澄清一下:我对实际的 16 位处理器感兴趣,例如实模式下的 8086 和 80286。

最佳答案

Why are far pointers slow?

段寄存器加载对于核心前端来说过于复杂,无法转换为微操作。相反,它们是由存储在小型 ROM 中的微操作“模拟”的。这从一些分支开始(它是哪种 CPU 模式?),通常这些分支无法从 CPU 的分支预测中受益,从而导致延迟。

为了避免段寄存器负载(例如,当多次使用相同的远指针时),软件倾向于使用更多的段寄存器(例如倾向于使用 ESFSGS);这会为指令添加更多前缀(段覆盖前缀)。这些额外的前缀也会减慢指令解码速度。

I guess if every pointer you were using were in a different segment this could add up, but data is usually grouped.

编译器没那么聪明。如果一小段代码使用 4 个远指针,而这些指针恰好都使用同一段,则编译器不会知道它们都在同一段中,并且无论如何都会执行昂贵的段寄存器加载。要解决这个问题,您可以将数据描述为结构(例如,1 个指向具有 4 个字段的结构的指针,而不是 4 个不同的指针);但这要求程序员以不同的方式编写软件。

举个例子;如果你执行类似“int foo(void) { int a; return bar(&a); }”的操作,那么 ss 可能会在堆栈上传递,然后被调用者 (bar code>) 会将其加载到另一个段寄存器中,因为 bar() 必须假设指针可以指向任何地方。

另一个问题是有时数据大于段(例如 100000 字节的数组不适合 64 KiB 段);因此,某人(程序员或编译器)必须计算并加载不同的段才能访问(部分)相同的数据。所有指针算术可能都需要考虑到这一点(例如,看起来很简单的 pointer++; 可能会变得更像 offset++; segment += (offset >> 4); offset &= 0x000F; 导致段寄存器加载)。

If you have to hit DRAM, that should dominate the cost, right?

对于实模式;您的 RAM 限制为大约 640 KiB,并且 CPU 中的缓存通常要大得多,因此您可以预期每次内存访问都会命中缓存。在某些情况下(例如,每个核心具有 1 MiB L2 缓存的级联湖 CPU),您甚至不会使用 L3 缓存(全部是 L2 命中)。

您还可以预期段寄存器加载比缓存命中更昂贵。

Hoping an 8086 wizard is hanging around who remembers this stuff.

当人们说“分段很糟糕,应该避免”时,他们想到的并不是已经过时 40 年的 CPU (8086),而是本世纪相关的 CPU。他们中的一些人可能不仅仅考虑性能(特别是对于汇编语言程序员来说,分段是一种烦恼/额外的负担)。

关于performance - 为什么远指针很慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73146953/

相关文章:

ruby-on-rails - Puma 可以同时缓冲多少个请求?

javascript - AngularJS 和效率(或 : storing values for multiple uses)

cpu-architecture - 微码术语 : are there names for different "styles" of microcode?

string - 如何在 .COM 可执行文件中以相反顺序打印字符串?

assembly - 如何在屏幕上显示一个数字并使用 DOS x86 程序集休眠一秒钟?

c# - 为什么 64 位比 32 位更快?

php - 在 Apache (EC2) 上文件上传速度比用户的网络上传速度慢

exception - RISC-V SYSTEM 指令如何实现为陷阱?

cpu - POWER8 架构 'flat' 虚拟地址空间

DOS 的 GCC 交叉编译器在 C 中产生简单的 "Hello world!"链接器错误