首页 > 解决方案 > 使用 callgrind 或程序集修改优化嵌套 if 和 switch 语句

问题描述

考虑这段代码

| 34 static bool                                                                     
| 35 _valid_character(char *str, size_t *idx)                                        
| 36 {                                                                               
| 37   char c = str[*idx];                                                           
| 38                                                                                 
| 39   if (c != '\\' && c != '"') {                                                  
| 40     (*idx) += 1;                                                                
| 41     return true;                                                                
| 42   } else if (c == '"') {                                                        
| 43     return false;                                                               
| 44   } else {                                                                      
| 45     char b = str[(*idx) + 1];                                                   
| 46     switch (b) {                                                                
| 47       case '"':                                                                 
| 48       case '\\':                                                                
| 49       case '/':                                                                 
| 50       case 'b':                                                                 
| 51       case 'f':                                                                 
| 52       case 'n':                                                                 
| 53       case 'r':                                                                 
| 54       case 't':                                                                 
| 55         (*idx) += 2;                                                            
| 56         return true;                                                            
| 57       default:                                                                  
| 58         pprint_error("%s@%s:%d invalid escape sequnce \\%c%c (aborting)",       
| 59             __FILE_NAME__, __func__, __LINE__, c, b);                           
| 60         abort();                                                                
| 61     }                                                                           
| 62   }                                                                             
| 63 }  

这个函数是我的代码中意义完全减慢的根本原因。我曾尝试仅使用 if 语句并且仅使用 switch 语句,但这是我能想到的最佳优化,其中 callgrind 可实现最佳性能。这个函数约占运行时间的 25%,所以根据有问题的(抱歉)80/20 规则,让这个代码更快是我的最大利益。

下面是在此函数上使用 kcachegrind 可视化的 callgrind 输出。

在此处输入图像描述

似乎 callgrind 是说我的第一次跳跃是最差的跳跃,但我已经尝试了这个 if 语句的所有组合以尽量减少跳跃,并且每次第一次跳跃都是最差的跳跃。

这段代码是用 clang 编译的

clang ... -Weverything -Werror -Wpedantic -m64 -O0 -g

所以我的问题是优化这段代码和替代技术的最佳方法是什么,包括修改汇编来优化这段简单但致命的代码。

我想继续使用-O0,因为我发现它对调试和查找优化最有用。-O1,2,3,fast倾向于抽象到很远的地方,以便更好地理解正在发生的事情。

-- 编辑 1 要求提供示例输入。

char cstr[BUF] = "abcdefghijklmnopqrstuvwxyz\"randomgarbageafterthis";
size_t idx = 0;
while (_valid_character(cstr, &idx));

最后,输入只是一个字符串,并且会调用一个循环,直到结束"字符。结束的 idx 值保持cstr[idx] == '"''为真。

标签: coptimizationvalgrindcallgrind

解决方案


如果您真的想优化您的代码,请使用笔和纸并创建一个布尔逻辑表并用您自己的想法优化它的代数。之后重新创建您的代码,并请break;在您的switch语句中使用。

例如:

这是你的代码。

if (c != '\\' && c != '"')
{
    (*idx) += 1;
    return true;
}

这个比上面那个快。

if (c != '\\')
{
    if (c != '"')
    {
        (*idx) += 1;
        return true;
    }
}

if (c != '\\')而不是像使用注册的常量那样与一些字符进行比较。

register const char BACKSLASH = '\\';

并且还可以:

register char c = str[*idx];

加载到 CPU 寄存器中的常量和变量在比较时要快得多。

if (c != BACKSLASH)

一般来说,如果你想要快速的代码,只使用ifelse使用简单的布尔比较参数。

编辑:

代码示例 1:

if (c != '\\')
{
    if (c == '"')
    {
        return false;
    }
    else
    {
        (*idx) += 1;
        return true;
    }
}

相当于:

代码示例 2:

if (c != '\\')
{
    if (c != '"')
    {
        (*idx) += 1;
        return true;
    }
}
else if (c == '"')
{
    return false;
}

但是第一个代码示例只比较了 2 次,而第二个代码比较了 3 次。


推荐阅读