在为ARM7编译的C代码中,使用全局变量是增加还是降低性能?

时间:2014-05-23 17:04:35

标签: c performance embedded arm global-variables

在为ARM7嵌入式平台编译时,在C代码中使用大量全局变量是否会降低或提高性能?

代码库由多个C源代码文件组成,这些文件使用extern关键字引用彼此的全局变量。来自不同源代码文件的不同函数指的是不同的全局变量。一些变量是数组。

我正在使用的编译器是IAR的EW ARM kickstart版本(32kb)。

4 个答案:

答案 0 :(得分:1)

好吧,使用全局变量不会直接影响CPU性能。堆栈分配通常分别在函数入口/出口处单个加或减。

但是,堆栈的大小非常有限。在堆上使用动态分配通常是解决方案。在嵌入式系统中,这可能是一个问题,因为分配或释放动态内存可能需要多长时间。

如果分配和释放堆是系统的问题,全局变量可以缓解分配/自由执行时间的问题。

我不建议将此作为您的第一个解决方案 - 特别是如果此应用涉及线程。可能很难追踪哪些线程/函数正在修改全局变量,从而导致未来的麻烦。 static变量在技术上与全局变量(“全局和静态数据”)位于同一位置,因此您可能需要首先考虑此选项。

答案 1 :(得分:1)

你可能担心某些事情对你来说并不是真正的问题......

从理论或挑剔的角度来看,访问全局变量需要某种重定向(如PIC的GOT),因此它们较慢可以访问。

当您在本地范围内访问变量时,您隐式使用本地引用(如堆栈指针或放置在寄存器中的值),因此访问它们更快

例如:

extern int x;

int foo(int a, int b, int c, int d, int e) {
  return x + b + e;
}

compiles to

foo(int, int, int, int, int):
    movw    r3, #:lower16:x
    movt    r3, #:upper16:x
    ldr r0, [r3, #0]
    ldr r3, [sp, #0]
    adds    r0, r1, r0
    adds    r0, r0, r3
    bx  lr

与访问br1)相比,您可以看到访问eldr r3, [sp, #0])或xmovw r3, #:lower16:x; movt r3, #:upper16:x; ldr r0, [r3, #0])所需的指示较少

答案 2 :(得分:0)

任何性能优势或其他方面完全取决于访问模式和使用情况,因此无法在不查看代码的情况下在个别情况下进行说明。无论使用全局变量,代码都可能是高效的或低效的。

如果通过使数据为全局,您可以避免对访问器函数的函数调用,并且此类访问是频繁的,那么避免函数调用开销可能具有可测量的性能优势。但仅仅是全局本身并没有任何优势 - 它关于访问方法和生成的指令数量(或等待状态,如果内存访问比处理器慢 - 例如片外存储器 - 但是适用于任何数据,全球或其他)。

以您描述的方式使用全局变量通常表示设计不佳和/或开发人员缺乏经验,并且可能存在代码区域对性能的影响远大于仅仅是数据访问的位置。

最终,使用全球数据来获得一些感知到的性能优势是错误的。在大多数情况下,性能应该是实现所需的实时截止日期或数据吞吐量,而不是尽可能快地;如果您的处理器最终空闲时间达到90%,那么您所获得的就是更多时间无所事事。

我怀疑你的代码库更多地使用全局数据,而不是设计或工艺设计,而是更多任何故意的性能问题。具有显式内联或编译器优化的访问函数的封装静态数据可能具有类似的性能,同时更易于维护且更易于调试 - 这些优势可能远远超过性能问题。问问自己,最好是节省一毫秒的CPU时间或一个月的开发时间,或者更糟糕的是产品召回和客户流失,因为您的产品在现场出现故障。

答案 3 :(得分:-1)

static变量相比,这将始终降低性能并增加程序大小。您的问题没有具体询问您要比较的 。我可以看到各种替代方案,

  1. 与静态变量对比。
  2. 与值传递的参数相对应。
  3. 与传递的数组或结构指针中的值相对应。
  4. ARM blog给出了如何将常量加载到arm寄存器的细节。必须始终执行此步骤以获取全局变量的地址。编译器不会知道事先有多远。如果您将 gcc -lto一起使用或使用整个程序之类的内容,则可以执行更好的优化。基本上,这些会将全局转换为静态

    这里编译器可以使用全局基地的地址保存寄存器,然后使用偏移量加载不同的变量;例如ldr rN, [rX, #offset]。也就是说,如果你很幸运。

    RISC CPU的设计,如ARM,支持处理所有内存访问的加载/存储单元。通常,加载/存储指令具有[register + offset]形式。此外,所有RISC寄存器都是近似对称的。这意味着任何寄存器都可用于此偏移访问。通常,如果您将struct或数组指针作为参数传递,那么它就变成了同样的东西。即,ldr rN, [rX, #offset]

    现在,该参数的优点是最终,您的例程可以通过传递不同的指针来支持多个数组结构。此外,它还可以将通用数据组合在一起,从而为缓存带来好处。

    我认为全局变量对ARM有害。您应该只使用全局指针,其中您的代码需要 singleton 。或者你有某种同步记忆。即,全局变量应仅用于全局功能而不用于数据。

    通过堆栈传递所有值显然是无效的,并且错过了内存引用或指针的值。