- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个用 C 实现的数据结构项目,它为其他程序导出各种 API。最近想对grofile的Hot函数做一些优化。这是供您引用的项目。
https://github.com/Incarnation-p-lee/libds有一个热门函数binary_search_tree_node_insert,如下:
/*
* RETURN the pointer of inserted node of the binary search tree
* If root is NULL or node is NULL, RETURN NULL.
*/
struct binary_search_tree *
binary_search_tree_node_insert(struct binary_search_tree *root,
struct binary_search_tree *node)
{
register struct binary_search_tree **iter;
if (!node || !root) {
pr_log_warn("Attempt to access NULL pointer.\n");
} else {
iter = &root;
while (*iter) {
if (node->chain.nice == (*iter)->chain.nice) {
if (*iter == node) {
pr_log_info("Insert node exist, nothing will be done.\n");
} else {
doubly_linked_list_merge((*iter)->chain.link, node->chain.link);
}
return *iter;
#ifndef OPT_HOT
} else if (node->chain.nice > (*iter)->chain.nice) {
iter = &(*iter)->right;
} else if (node->chain.nice < (*iter)->chain.nice) {
iter = &(*iter)->left;
#else
} else {
binary_search_tree_insert_path_go_through(node, iter);
#endif
}
}
return *iter = node;
}
return NULL;
}
我想优化两个 else-if 部分,因为它是一半到一半的分支,这可能会对管道产生很大影响。所以我写了一个宏 binary_search_tree_insert_path_go_through 来替换这两个分支。实现如下:
/*
* 1. node->nice => rbx, *iter => rcx.
* 2. compare rbx, and 0x8(rcx).
* 3. update iter.
*/
#define binary_search_tree_insert_path_go_through(node, iter) \
asm volatile ( \
"mov $0x18, %%rax\n\t" \
"mov $0x20, %%rdx\n\t" \
"mov 0x8(%1), %%rbx\n\t" \
"mov (%0), %%rcx\n\t" \
"cmp 0x8(%%rcx), %%rbx\n\t" \
"cmovg %%rdx, %%rax\n\t" \
"lea (%%rcx, %%rax), %0\n\t" \
:"+r"(iter) \
:"r"(node) \
:"rax", "rbx", "rcx", "rdx")
但是这个功能的单元测试关于这个变化下降了大约6-8%。从objdump代码(右手优化代码)来看,指令少,我很难理解为什么优化前要花更多时间。
还有一些细节供大家引用:
struct collision_chain {
struct doubly_linked_list *link;
sint64 nice;
};
/*
* binary search tree
*/
struct binary_search_tree {
struct collision_chain chain;
sint32 height; /* reserved for avl */
/* root node has height 0, NULL node has height -1 */
union {
struct binary_search_tree *left;
struct avl_tree *avl_left; /* reserved for avl */
struct splay_tree *splay_left; /* reserved for splay */
};
union {
struct binary_search_tree *right;
struct avl_tree *avl_right; /* reserved for avl */
struct splay_tree *splay_right; /* reserved for splay */
};
};
struct doubly_linked_list {
uint32 sid;
void *val;
struct doubly_linked_list *next;
struct doubly_linked_list *previous;
};
它运行在 virtual-box 上,2 核 i5-3xxM,cpuinfo 如下:
processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 58
model name : Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz
stepping : 9
microcode : 0x19
cpu MHz : 2568.658
cache size : 6144 KB
physical id : 0
siblings : 2
core id : 0
cpu cores : 2
apicid : 0
initial apicid : 0
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl pni ssse3 lahf_lm
bogomips : 5137.31
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
processor : 1
vendor_id : GenuineIntel
cpu family : 6
model : 58
model name : Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz
stepping : 9
microcode : 0x19
cpu MHz : 2568.658
cache size : 6144 KB
physical id : 0
siblings : 2
core id : 1
cpu cores : 2
apicid : 1
initial apicid : 1
fpu : yes
fpu_exception : yes
cpuid level : 5
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl pni ssse3 lahf_lm
bogomips : 5137.31
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:
最佳答案
我不知道现代处理器是否相同,但是 Linus really didn't like the CMOV instruction back in '07 .
由于您正在进行微观优化,因此请将相等性检查移至最后一个位置。它几乎总是错误的,但您在每次迭代中都做到了。
此外,我会尝试不使用指针到指针模式。由于指针别名问题,间接往往会使优化器阻塞。相反,使用带有两个指针的英寸蠕虫模式:
void insert(NODE *x, NODE **root) {
NODE *trail = NULL;
NODE *lead = *root;
while (lead) {
trail = lead;
if (x->key < lead->key)
lead = lead->left;
else if (x->key > lead->key)
lead = lead->right;
else return; // do nothing;
}
// lead has found null, so insert
if (trail)
// redo the last key comparison
if (x->key < trail->key)
trail->left = x;
else
trail->right = x;
else
*root = x;
}
在我的 MacBook 上,这会编译为以下 64 位代码,其中循环仅包含 10 条指令。很难从您帖子中的微小列表中分辨出来,但看起来它要长得多:
pushq %rbp
movq %rsp, %rbp
movq (%rsi), %rdx
testq %rdx, %rdx
je LBB0_11
movl 16(%rdi), %ecx
LBB0_2:
movq %rdx, %rax # dx=lead, ax=trail
cmpl 16(%rax), %ecx # comparison with key
jge LBB0_4 # first branch
movq %rax, %rdx # go left (redundant because offset(left)==0!)
jmp LBB0_6
LBB0_4:
jle LBB0_12 # second branch
leaq 8(%rax), %rdx # go right
LBB0_6:
movq (%rdx), %rdx # move lead down the tree
testq %rdx, %rdx # test for null
jne LBB0_2 # loop if not
testq %rax, %rax # insertion logic
je LBB0_11
movl 16(%rdi), %ecx
cmpl 16(%rax), %ecx
jge LBB0_10
movq %rdi, (%rax)
popq %rbp
retq
LBB0_11:
movq %rdi, (%rsi)
LBB0_12: # return for equal keys
popq %rbp
retq
LBB0_10:
movq %rdi, 8(%rax)
popq %rbp
retq
如果比较代价高昂(你没有显示“好”是什么),你也可以尝试存储跟踪比较的二进制结果,以便最终检查使用它而不是重做比较。
关于c - while循环中的分支优化,为什么更少的指令花费更多的运行时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31084363/
我一直在使用 less 进行前端开发,但最近几天我遇到了这个错误。 我正在使用 PhpStorm 的观察器将 less 文件编译为 css 文件。但是当我编辑 less 文件时,编译器将这一行添加到
我在互联网上搜索Erlang的流程模型并找到了一些图表 slides 3-4在乔·阿姆斯特朗的一次演讲中。它们显示了 Erlang、java 和 C# 之间进程创建和消息传递时间之间的许多差异。谁能告
我怎样才能用更少的钱创建这个类? .class { display: none; } a:hover .class { display: block; } 最佳答案 像这样? .cla
全部,我有一些代码在 less 中做一个循环。但是如果我把px改成'%',less就不能编译less文件。我该怎么做呢?谢谢。 @iterations: 100; // helper class, w
According to the docs如果我做类似的事情: .child, .sibling { .parent & { color: black; } &
这是一个现有的通用 css 规则(原始文件): .caption-top { color: red; } 这是示意图,因为在现实生活中,我需要根据上下文将 .caption-top 选择器变成其他
所以问题是我想连接到msaccess 数据库,每次打开它时都有密码。 如果我直接打开 Access 文件,密码就有效。 如果我删除密码,我可以建立连接,这意味着如果不涉及密码,我的代码可以工作 密码是
news.less 看起来像这样; @import: "libs/base.less" base.less 看起来像这样; @import "colors.less"; @
当我在这里使用 WINLess 编译这段代码时出现错误: .icon-text-shadow (@icon-text-shadow: 0.0625rem 0.0625rem rgba(132, 108
我正在处理大型矩阵,例如 Movielens 20m dataset .我重组了在线文件,使其与页面上提到的尺寸(138000 x 27000)相匹配,因为原始文件包含的索引更大(138000 x 1
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是 Android 新手,刚来这里。 我只知道 Bitmap 逐像素存储图像并且不进行任何压缩。 Drawable和Bitmap一样吗? 或者 同样的图片文件,Drawable 比 Bitmap 占
我是一名前端开发人员,最近考虑使用 SASS 或 LESS 进行 CSS 开发。 不过,我不使用 Ruby,也不想依赖于使用 JavaScript 的用户。有没有人对使用 PHP 项目使用 SASS
我需要将日历添加到表单中。 我想安装这个项目: https://github.com/vitalets/bootstrap-datepicker 但据说: 某些样式需要 Bootstrap 的下拉组件
如果您运行如下代码: length(unique(runif(10000000))) length(unique(rnorm(10000000))) 你会看到只有大约 99.8% 的 runif 值是
我正在这样做Question首先使用 PriorityQueue 解决了这个问题:- public ArrayList solve(int A, int B, int C, int D) {
基本上就是标题所说的。我知道如果我只有一个字母,我可以使用 char 作为类型,但我需要 2 个字母的数据类型,例如“XY”。有没有比字符串使用更少存储空间(位)或更小的东西?或者多个字母通常只是保存
我有两个表,用户表和程序表。现在我只有 5-10 个计划和数以万计的用户,他们可以注册任何一个计划(也可以注册多个计划)。因此,在多对多关系的情况下,我正在考虑创建一个单独的表,例如 link_use
我们有一个基于 LESS 的样式表,我们希望为其生成多种颜色变化。我们已经定义了一个包含颜色变化(现在为 blue.less)的包含文件,并希望生成和使用该包含文件的绿色和红色变化。 我们想要做的是通
我想知道我是否可以改进我的 LESS-Snippet。我有很多带有颜色名称的变量/我自己的颜色标题和相关的前景和背景颜色。我根据我的颜色定义类名称。 @logocolorgreen: #40FF01;
我是一名优秀的程序员,十分优秀!