【问题标题】:Manual optimization in the past (C Language) [closed]过去的手动优化(C 语言)[关闭]
【发布时间】:2023-03-10 00:29:01
【问题描述】:

早在 70 年代 C 刚开始的时候,我猜编译器级别的优化并没有像现代编译器(clang、gcc 等)那样先进,而且计算机本身在硬件方面是有限的,这是普遍的偏好吗?源代码级别的可读性优化?

例子:

int arrayOfItems[30]; // Global variable

int GetItemAt(int index)
{
    return globalArrayOfThings[index];
}

int main()
{
    // Code
    // ... arrayOfItems intialized somewhere
    // More code

    GetSomethingByItem(GetItemAt(4)); // Get at index 4

    return 0;
}

现在可以优化为:

int arrayOfItems[30]; // Global variable

int main()
{
    // Code
    // ... arrayOfItems intialized somewhere
    // More code

    GetSomethingByItem(arrayOfItems[4]); // Get at index 4

    return 0;
}

完全省略函数GetItemAt,从而通过直接从其地址访问值而不是进入函数、创建堆栈帧、访问值来节省时间并将结果推送到某个寄存器。人们过去更喜欢将第二个“优化”版本直接写入源代码还是使用第一个版本以便代码更具可读性?

我知道在这个例子中你可以使用处理器来“模仿”这种优化(例如#define GetItemAt(x) arrayOfItems[x]),但你明白我的意思。

另外,也许这个确切的优化功能从一开始就存在,如果是这样,我应该找到另一个例子,欢迎提出建议。

TL;DR -

  • 过去是否普遍倾向于源代码级别的优化而不是可读性?

额外问题:

  • 是否包含优化以使源代码更具可读性?

【问题讨论】:

  • 不清楚你在问什么。如果它是“在某一时刻是否存在没有进行此优化的编译器?”,那么答案是“是的,可能。”。
  • @OliverCharlesworth 我编辑了我的问题,现在应该更清楚了。
  • 您似乎在“可读性”的标题下混杂了很多东西,例如模块化、易于代码重用、可测试性、封装性、可维护性、可移植性等。总是在需要时进行优化,并且在知道需要时进行优化,否则人们只会坚持使用汇编。
  • 在某些情况下,例如,独立的x++;++x; 更受青睐(反之亦然),因为一个比另一个更快。为了提高性能,经常将数组索引转换为指针索引。上世纪 70 年代的 C 编程课很可能已经包含了几个小时来讨论这个主题。但请记住,除了没有优化编译器之外,那个时代的 CPU 比现代 CPU 慢了大约 1000 倍。
  • @Kevin - 那些忽视历史的人注定要重蹈覆辙。

标签: c optimization history


【解决方案1】:

我认为很多开发人员都更喜欢优化而不是可读性,但有时可能会争辩说有些优化会损害可读性但对性能来说是必要的。 Duff's Device 之类的东西(循环展开优化)

来自

do {               /* count > 0 assumed */
  *to = *from++;   /* "to" pointer is NOT incremented, see explanation below */
} while(--count > 0);

register n = (count + 7) / 8;
switch(count % 8) {
case 0: do {    *to = *from++;
case 7:     *to = *from++;
case 6:     *to = *from++;
case 5:     *to = *from++;
case 4:     *to = *from++;
case 3:     *to = *from++;
case 2:     *to = *from++;
case 1:     *to = *from++;
    } while(--n > 0);
}

当然,事实证明编译器变得更聪明了,据 LKML 报道,removing Duff 的设备提高了性能并减少了内存使用量。来自链接的维基百科,

为了实现内存到内存的复制(这不是 Duff 设备的原始用途,尽管可以按照以下部分所述对其进行修改以用于此目的),标准 C 库提供了函数 memcpy;它的性能不会比这段代码的内存到内存复制版本差,并且可能包含特定于架构的优化,这将使其显着更快

来自 LKML(2000 年)

... X 服务器中的这种效果。 事实证明,有了分支预测和 CPU 的相对速度 与过去十年的内存变化相比,循环展开几乎是 无意义。事实上,通过消除 Duff's Device 的所有实例 XFree86 4.0 服务器,服务器的大小缩小了 0.5 兆字节,并且启动速度更快,因为消除了所有 多余的代码意味着 X 服务器没有破坏缓存 线一样多。

至于只提高可读性的优化,它要求你的代码首先是不可读的。那么任何使它更具可读性的东西似乎都符合条件。最后,记住premature optimization is the root of all evil

【讨论】:

  • 另一个损害可读性的例子是使用类似函数的宏而不是普通函数。我记得在 GNU MP 库中调试这些多行宏扩展是一场噩梦。
猜你喜欢
  • 2010-09-07
  • 2014-01-19
  • 1970-01-01
  • 2016-08-04
  • 2022-06-10
  • 1970-01-01
  • 2012-03-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多