Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
实时编程C的性能困境_C_Performance - Fatal编程技术网

实时编程C的性能困境

实时编程C的性能困境,c,performance,C,Performance,我正在开发一个以ASM为主的嵌入式体系结构。为了提高可读性和模块性,我想用C重构大部分遗留ASM代码 因此,我仍然对一些小细节感到困惑,这些细节导致我的希望破灭。真正的问题要比下面的例子复杂得多,但我想将此作为讨论的切入点与大家分享 我的目标是找到一个最佳的解决办法 下面是原始示例(不要担心代码的作用。我随机编写此示例只是为了说明我想讨论的问题) 坏消息是: void example_a(int foo, int bar) { write(foo); write(bar + (fo

我正在开发一个以ASM为主的嵌入式体系结构。为了提高可读性和模块性,我想用C重构大部分遗留ASM代码

因此,我仍然对一些小细节感到困惑,这些细节导致我的希望破灭。真正的问题要比下面的例子复杂得多,但我想将此作为讨论的切入点与大家分享

我的目标是找到一个最佳的解决办法

下面是原始示例(不要担心代码的作用。我随机编写此示例只是为了说明我想讨论的问题)

坏消息是:

void example_a(int foo, int bar) {
   write(foo); 
   write(bar + (foo >> 1));
}

丑陋的C代码仍然比汇编程序可读性强得多。此外,您可能会获得一些意外的免费优化

编译器无法进一步查看正在处理的文件。当一个函数被标记为
extern
时,它将不可避免地导致性能问题。原因是编译器不能对外部声明做出任何假设

假与假。你试过“全程序优化”了吗?内联函数的优点,无需组织到头中。并不是说把东西放在标题里一定难看,如果你组织标题的话

在VisualDSP++编译器中,这是通过
-ipa
开关启用的

ccts编译器具有一种称为过程间分析(IPA)的功能,这是一种 允许编译器跨翻译单元进行优化的机制 而不是仅仅在一个翻译单元内。这一能力有效地发挥了作用 允许编译器查看最终链接中使用的所有源文件 并在优化时利用这些信息

所有-ipa优化都在初始链接之后调用,因此 一个称为预链接器的特殊程序重新调用编译器执行 新的优化


我习惯于在需求非常紧张的性能关键型核心/内核类型领域工作,通常在接受优化器和标准库性能时会受益匪浅(例如:不要对
malloc
或自动生成的矢量化的速度太过兴奋)

然而,我从未有过如此紧迫的需求,以至于指令的数量或将更多参数推送到堆栈的速度成为一个相当大的问题。如果这确实是目标系统的一个主要问题,并且性能测试失败了,那么需要注意的一点是,在微观粒度级别上建模的性能测试通常会让您着迷于最小的微观效率

微效率性能测试 我们犯了一个错误,在我以前的工作场所编写了各种表面微观级别的测试,我们在那里进行测试,只是简单地计时一些基本的事情,比如从文件中读取一个32位浮点。与此同时,我们进行了优化,大大加快了与读取和解析整个文件内容相关的广泛的、真实的测试用例,而与此同时,一些uber微测试由于一些未知的原因实际上变得更慢(它们甚至没有被直接修改,但对它们周围的代码的更改可能会产生一些与动态因素(如缓存、分页等)相关的间接影响,或者仅仅是优化器如何处理这些代码)

因此,当你使用更高级的语言而不是汇编语言时,微观世界可能会变得更混乱。微小事物的性能可能会在你脚下发生一些变化,但你必须问问自己,什么更重要:从文件中读取一个32位浮点数的性能会略有下降,或者进行实际操作时读取整个文件的速度要快得多。在更高级别上对性能测试和分析会话进行建模将为您提供空间,让您有选择地、有成效地优化真正重要的部分。您有很多方法可以剥猫皮

在一个被重复执行一百万次的超粒度操作上运行探查器,你就已经将自己退回到了一个程序集类型的微角落,因为所有的事情都在执行这样的微级别测试,这仅仅取决于你是如何剖析代码的。所以你真的想缩小一点,在一个更粗糙的级别上进行测试你可以像一个训练有素的狙击手一样,磨练每一个精心挑选的部件的微观效率,把领导者派到效率低下的背后,而不是试图成为英雄,干掉每一个可能成为性能障碍的微不足道的步兵

优化链接器 您的一个误解是,只有编译器可以充当优化器。链接器可以在将对象文件链接到一起时执行各种优化,包括内联代码。因此,很少(如果有的话)需要将所有内容作为优化塞进单个对象文件中。我会尝试更多地了解链接器的设置如果你不这么认为

界面设计 撇开这些不谈,一个可维护的大规模代码库的关键在于接口(即头文件)而不是实现(源文件).如果你有一辆引擎时速达到1000英里的汽车,你可能会在引擎盖下窥视,发现几乎没有喷火恶魔在周围跳舞,让这种情况发生。也许恶魔之间有一个协议,可以达到这样的速度。但你不必向驾驶汽车的人透露这一事实。你仍然可以给出答案他们有一套很好的直观,安全的控制来驱动野兽

因此,您可能有一个系统,使未线性函数调用“昂贵”,但相对于什么昂贵?如果您正在调用一个对一百万个元素进行排序的函数,那么将一些小参数(如指针和整数)推送到堆栈的相对成本应该是绝对微不足道的,无论您使用的是哪种硬件。Insi在函数中,您可以执行各种探查器
void do_something(int *a, int *b) {
    int tmp = *b;
    *b = *a + *b;
    *b = tmp + *a;
}

void compute_sum(int *sum, int foo, int bar) {
    int tmp;
    for(tmp = 1; tmp < 3; tmp++)
        sum += *foo * sum + *bar * sum;
}

void a_function(int *sum, int *foo, int *bar) {
    compute_sum(sum, foo, bar);
    do_something(foo, bar);
}
int foo;
int bar;
int half_foo;

void example_a() {
   write(foo); 
   write(half_foo + bar);
}
void example_a(int foo, int bar) {
   write(foo); 
   write(bar + (foo >> 1));
}