【问题标题】:Using internal static variables to increase performance?使用内部静态变量来提高性能?
【发布时间】:2009-09-29 11:24:22
【问题描述】:

我有一个函数需要相当多的内部临时存储来进行计算(一些矩阵运算),我知道这个函数会被频繁调用(比如在整个程序运行时每毫秒)。我的直觉告诉我,最好将这些临时变量声明为静态的,这样每次调用函数时一次又一次地创建它们不需要太多的管理工作。无论如何,每次调用函数时我都必须初始化它们,因此出于功能目的不需要让它们保持活动状态。我知道将它们设为静态会破坏线程安全,但这不是问题。

由于知识通常比任何直觉都好,我想知道处理这种情况的“正确”方法是什么。

void frequentlyCalledFunction(void)
{
    double matrix1[10][10];
    double matrix2[10][10];
    /* do something with the matrices ... */
}

void frequentlyCalledFunction(void)
{
    static double matrix1[10][10];
    static double matrix2[10][10];
    /* do something with the matrices ... */
}

【问题讨论】:

    标签: c


    【解决方案1】:

    没有区别。 “创建”未初始化的数组不需要任何代码。

    在静态数组的情况下,内存是保留的并且一直可用。在自动数组的情况下,它在堆栈上,“创建”它所需要的只是移动堆栈指针,这无论如何都会在进入函数时发生。

    (有一天你会尝试在多线程程序中使用该函数,而静态版本会偶尔出现间歇性故障,导致你喝酒和吸毒。这不值得冒险。)

    【讨论】:

    • 创建局部变量可能没有开销,但它们必须相对于堆栈或基指针进行访问,因此可能会对性能产生可衡量的影响
    • @Christoph:有趣的一点。我想知道它是否对现代处理器有影响?我敢打赌它不会,但我不是组装向导。 :-)
    • 我正在尝试考虑一个可能会出现问题的平台。鉴于它将从给定的堆栈帧中修复,它不应该引起问题。例如,在 mips 上,您可以执行 LD r1, frame_offset(stack_frame_base) 所以它是免费的。 mov eax, [esp + frame_offset] 也是免费的...
    • 还请注意,即使在静态变量的情况下,由于将发生指针/数组索引操作,各种数组访问也可能需要通过寄存器间接进行。所以这里的静态变量甚至没有真正的理论优势。
    【解决方案2】:

    我肯定会先用最简单、最易读的方式来写它。每毫秒一次听起来像一个非常很少运行函数来进行微优化。

    一旦你得到它的工作,基准测试。确定性能是否足够好。如果不是,请再次优化和基准测试。 不要在没有非常可靠的数字来支持您的决定的情况下将干净的代码扭曲变形。

    【讨论】:

      【解决方案3】:

      像往常一样,您应该首先进行分析。局部变量可能只会导致堆栈指针减少一点,这不应该有任何性能损失。

      【讨论】:

        【解决方案4】:

        您正在尝试在没有基准测试的情况下进行微优化,这通常被认为是一件坏事。您应该始终进行基准测试。否则,您如何确定任何优化尝试都有效?

        这样做您不太可能获得任何好处,代码的可读性和可维护性应该是第一位的。

        【讨论】:

          【解决方案5】:

          分配堆栈变量与分配堆变量不同,只是堆栈指针向下移动到足以分配函数所需的所有内存。在堆栈帧中分配一个或一百个变量没有开销。即使有零个变量(记录返回的位置等),调用函数时堆栈指针也已经被移动。

          【讨论】:

            【解决方案6】:

            知道的唯一方法是尝试并测试它。不过,这不太可能产生太大影响。

            【讨论】:

              【解决方案7】:

              在 SPARC 上,尤其是在 64 位模式下,静态情况较慢。访问全局变量(静态是,它只是限于函数范围的名称)需要使用 3 个寄存器的 5 条指令,在您的情况下,只有 10 条指令才能获取数组的地址。正如已经指出的那样,非静态版本没有开销,因为无论如何都会构建帧,如果堆栈指针增长 16 字节或 200 没有区别。 但是如果你初始化你的数组要小心,这可能会产生一个隐藏的 memset,这可能会很昂贵。

              void frequentlyCalledFunction(void)
              {
                double matrix1[10][10]={0.0};
                double matrix2[10][10]={0.0};
                /* do something with the matrices ... */
              }
              

              可能会进行 1 或 2 次 memcpy 或 memset 调用来初始化数组。

              【讨论】:

                【解决方案8】:

                为具有自动存储持续时间的变量保留空间意味着只需减少堆栈指针,因此只要这些不是唯一的局部变量,就没有开销。

                可能会损害性能的是堆栈分配的变量必须相对于堆栈或基指针进行寻址,因此使用static 可能会稍微提高性能。

                与往常一样,对代码进行基准测试以确保。

                【讨论】:

                  猜你喜欢
                  • 2012-05-18
                  • 1970-01-01
                  • 2018-01-20
                  • 2011-08-19
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-09-01
                  相关资源
                  最近更新 更多