我正在使用两个版本的函数来过滤链表,一个接收谓词函数作为参数,另一个使用“宏模板”将谓词构建到函数中。我希望第一个运行得更慢,因为它在每次迭代时都会调用函数,但在我的盒子上它们的速度大致相同。有关为什么会发生这种情况的任何线索?任何帮助表示赞赏。
以下是代码:
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
struct list_t {
int val;
struct list_t *next;
};
typedef struct list_t list_t;
// Removes elements not matching the predicate.
// NOTE: This is not freeing the removed elements.
list_t *keep(int (*predfun)(int,int), int predarg, list_t *list) {
list_t *this, *prev;
for (this=list, prev=NULL; this; prev=this, this=this->next) {
if (!predfun(this->val, predarg)) {
if (!prev) {
list = this->next;
}
else {
prev->next = this->next;
}
}
}
return list;
}
int less(int a, int b) {
return a<b;
}
// A "template" macro for the keep function.
// The idea is to embed the predicate into the function, so that we
// don't have to make a function call on each iteration.
#define build_keep(test) { \
list_t *this, *prev; \
\
for (this=list, prev=NULL; this; prev=this, this=this->next) { \
if (!(test)) { \
if (!prev) { \
list = this->next; \
} \
else { \
prev->next = this->next; \
} \
} \
} \
return list; \
}
list_t *keep_less(int arg, list_t *list) {
build_keep(this->val < arg);
}
#define LEN 1000000
#define MOD 1024
// Creates a new list.
list_t *buildlist() {
int i;
list_t *list, *last, *t;
list=NULL, last=NULL;
srand(0); // Using always the same seed for the benchmark.
for (i=0; i<LEN; i++) {
if (!last) {
last = malloc(sizeof(list_t));
list = last;
}
else {
last->next = malloc(sizeof(list_t));
last = last->next;
}
last->val = rand() % MOD;
}
last->next = NULL;
return list;
}
int main() {
struct timeval t0, t1;
list_t *list, *t;
// With macro.
list = buildlist();
//for (t=list; t; t=t->next) printf("%d ", t->val); printf("\n");
gettimeofday(&t0, NULL);
keep_less(500, list);
gettimeofday(&t1, NULL);
printf("keep_less: %lf\n", (1000000 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec))/1000000.0);
//for (t=list; t; t=t->next) printf("%d ", t->val); printf("\n");
printf("\n");
// Without macro.
list = buildlist();
//for (t=list; t; t=t->next) printf("%d ", t->val); printf("\n");
gettimeofday(&t0, NULL);
keep(less, 500, list);
gettimeofday(&t1, NULL);
printf("keep: %lf\n", (1000000 * (t1.tv_sec - t0.tv_sec) + (t1.tv_usec - t0.tv_usec))/1000000.0);
//for (t=list; t; t=t->next) printf("%d ", t->val); printf("\n");
return 0;
}
这里的输出是:
keep_less: 0.181019
keep: 0.185590
答案 0 :(得分:0)
我不会说结果差不多 - 你确实看到4毫秒(~2%)的差异有利于立即版本。
这实际上相当实际 - 只需要保存一个函数调用就可以实现如此高的节省,因为你的测试函数起初做的很少。如果您对此优化有更多的期望,那么您可能偶然发现important lesson ...(就我个人而言,我必须每隔几周重新学习一次:])
答案 1 :(得分:0)
因为Ofek没有真正回答这个问题;-)这是为什么会发生这种情况?。显然,编译器在这里做得非常好。
inline
小功能(如
less
)进入来电者。less
都是常量,此处,在keep
被调用的地方。如果没有进行过度优化以对同一单元中不存在的代码产生类似的影响,我倾向于非常系统地使用inline
。这并不能保证函数将被内联,而只是允许在头文件中定义函数体。