c - 使用 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] == '"''
为真。
解决方案
如果您真的想优化您的代码,请使用笔和纸并创建一个布尔逻辑表并用您自己的想法优化它的代数。之后重新创建您的代码,并请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)
一般来说,如果你想要快速的代码,只使用if
和else
使用简单的布尔比较参数。
编辑:
代码示例 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 次。
推荐阅读
- python - 使用斜杠命令更改 Slack 机器人名称/图像?
- javascript - 如何在 Node.js 中将数据从一种方法传输到另一种方法?
- php - 有重定向时浏览器是否设置 cookie?
- vb.net - InvalidOperationException 未处理 3
- java - IN Intent 发送信息并使用 FLAG_ACTIVITY_CLEAR_TOP
- aurelia - Aurelia 应用程序未使用 au run cli 命令启动
- java - 将项目与 gradle 文件同步时出现问题
- mysql - 如何停止 mysql 移动 MySQL 数据库数据?
- django - 无法在 Django Rest 框架 JSON API 示例项目中创建多态项目实例
- python - 在 lmplot 中使用色调、行或列时保留标记大小