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

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

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

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

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

  1. 与静态变量相对应。
  2. 与值一起传递的参数。
  3. 与传递的数组或结构指针中的值相对应。

ARM博客提供了有关如何将常量加载到arm寄存器的详细信息。 必须始终执行此步骤以获取全局变量的地址。 编译器不会知道事先有多远。 如果将gcc-lto使用或使用类似整个程序的东西,则可以执行更好的优化。 基本上,这些将把全球转变为静态

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

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

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

我认为全局变量对ARM有害。 你应该只使用全局指针 ,你的代码需要一个单例 。 或者你有某种同步记忆。 即,全局变量应仅用于全局function而不用于数据。

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

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

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

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

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

你可能担心一些对你来说不是真正问题的事情……

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

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

例如:

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

编译成

 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] )。

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

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

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

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

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