2010年11月12日星期五

简单的优化处理

下面的代码中的几个combine完成的功能都是相同的,都是将data_t内的全部数据求和。但是从函数1到函数6应用了不同的系统优化,当然这是C语言级别的优化。
现在CPU都是支持流水线操作的,我们怎么让我们的代码多多符合CPU的流水操作,并行执行,这是对代码性能的提高是很多有帮助的。仿存操作、函数调用、跳转指令、寄存器溢出,CPU的这些特性如果使用不当,很有可能会造成我们的程序性能低下,形成瓶颈,当然我们现在写的程序都比较的小,我们不能很确切的体会到这种性能上的差异。
下面的程序虽然是我写的,但是我也有很多的不明白的地方,比如combine2比combine1少了很多对vec_length(v)函数的调用,安常理来说combine2的速度应该比combine1快,但是在我的机器上却不是,很不解。我通过反汇编看到编译器将combine1和combine2的函数调用全部优化(通过O2优化)为直接的内存访问,但是不明白为什么combine2却比combine1多个1个跳转操作指令和几个访存操作,我不知道gcc编译器为什么会产生这样的代码。
现在的编译器虽然已经够聪明,但是编译器的更迭却没有跟上处理器的更新速度,所以很多地方的优化还是要程序员人为的来进行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
 
 
typedef int data_t;
 
#define IDENT 0
#define  OPER +
 
typedef struct {
    int len;
    data_t *data;
} vec_rec, *vec_ptr;
 
vec_ptr
new_vec(int len)
{
    vec_ptr result = (vec_ptr)malloc(sizeof(vec_rec));
 
    if (!result) {
 return NULL;
    }
    result->len = len;
 
    /* 对输入参数的判断 */
    if (len > 0) {
 data_t *data = (data_t *)calloc(len, sizeof(data_t));
 if (!data) {
     free((void *)result);
     return NULL;
 }
 
 result->data = data;
    } else {
 result->data = NULL;
    }
 
    return result;
}
int
get_vec_element(vec_ptr v, int index, data_t *dest)
{
    if (index < 0 || index >= v->len) {
 return -1;
    }
 
    *dest = v->data[index];
 
    return 0;
}
 
int
vec_length(vec_ptr v)
{
    return v->len;
}
 
/* 给结构体data赋值,随即数 */
int
vec_set_data(vec_ptr v)
{
    int i;
    /* 其实这里应该用断言判断v的invariant属性 */
    assert(v != NULL);
 
    srand(time(NULL));
 
    for (i = 0; i < v->len; i++) {
 v->data[i] = rand() % 1000;
    }
 
    return 1;
}
 
/* 只用于int型,验证程序是否正确 */
void
vec_set_print(vec_ptr v)
{
    int i;
    assert(v != NULL);
 
    for (i = 0; i < v->len; i++) {
 printf("%d ", v->data[i]);
    }
 
    printf("\n");
}
 
data_t *
get_vec_start(vec_ptr v)
{
    return v->data;
}
 
/* 使用setitimer计时,精确到微秒 */
void
comput_time(vec_ptr vec, const char *str, void(*func)(vec_ptr, data_t*))
{
    struct itimerval begin, end;
    data_t result;
    long int t;
 
    begin.it_interval.tv_sec  = 0;
    begin.it_interval.tv_usec = 0;
    begin.it_value.tv_sec = 2;
    begin.it_value.tv_usec = 999999;
 
    if (setitimer(ITIMER_REAL, &begin, NULL) != 0) {
 printf("setitimer error!\n");
 return;
    }
 
    func(vec, &result);
 
    if (getitimer(ITIMER_REAL, &end) != 0) {
 printf("getitimer error!\n");
 return;
    }
 
    t = (begin.it_value.tv_sec - end.it_value.tv_sec) * 1000000 + \
 begin.it_value.tv_usec - end.it_value.tv_usec;
 
    printf("%s result:%d\n", str, result);
    printf("%s time:%ld\n", str, t * 2000);
    /* 转换成周期数CPE,一个周期为0.5纳秒 */
}
 
/* gcc -O2下,系统将vec_length直接优化为内存操作了,没有函数调用 */
 
void
combine1(vec_ptr v, data_t *dest)
{
    int i;
    data_t val = 0;
 
    *dest = IDENT;
    for(i = 0; i < vec_length(v); i++) {
 get_vec_element(v, i, &val);
 *dest = *dest OPER val;
    }
}
 
void
combine2(vec_ptr v, data_t *dest)
{
    int i;
    data_t val = 0;
    int length = vec_length(v);
 
    *dest = IDENT;
    for (i = 0; i < length; i++) {
 get_vec_element(v, i, &val);
 *dest = *dest OPER val;
    }
}
 
void
combine3_1(vec_ptr v, data_t *dest)
{
    int i;
    data_t *data = get_vec_start(v);
 
    *dest = IDENT;
    for (i = 0; i < vec_length(v); i++) {
 *dest = *dest OPER data[i];
    }
}
 
void
combine3_2(vec_ptr v, data_t *dest)
{
    int i;
    int length = vec_length(v);
    data_t *data = get_vec_start(v);
 
    *dest = IDENT;
    for (i = 0; i < length; i++) {
 *dest = *dest OPER data[i];
    }
}
 
void
combine4_1(vec_ptr v, data_t *dest)
{
    int i;
    data_t x = IDENT;
    data_t *data = get_vec_start(v);
 
    for (i = 0; i < vec_length(v); i++) {
 x = x OPER data[i];
    }
 
    *dest = x;
}
 
void
combine4_2(vec_ptr v, data_t *dest)
{
    int i;
    int length = vec_length(v);
    data_t *data = get_vec_start(v);
    data_t x = IDENT;
 
    for (i = 0; i < length; i++) {
 x = x OPER data[i];
    }
 
    *dest = x;
}
 
void
combine5(vec_ptr v, data_t *dest)
{
    int length = vec_length(v);
    int limit = length - 2;
    data_t *data = get_vec_start(v);
 
    data_t x = IDENT;
    int i;
 
    for (i = 0; i < limit; i+=3) {
 x = x OPER data[i] OPER data[i+1] OPER data[i+2];
    }
 
    for (; i < length; i++) {
 x = x OPER data[i];
    }
 
    *dest = x;
}
 
int
main(void)
{
    vec_ptr vec;
 
    vec = new_vec(10000);
    if (vec == NULL) {
 return -1;
    }
 
    vec_set_data(vec);
 
    //vec_set_print(vec);
 
 
    comput_time(vec, "combine1", combine1);
 
    comput_time(vec, "combine2", combine2);
 
    comput_time(vec, "combine3_1", combine3_1);
 
    comput_time(vec, "combine3_2", combine3_2);
 
    comput_time(vec, "combine4_1", combine4_1);
 
    comput_time(vec, "combine4_2", combine4_2);
 
 
    comput_time(vec, "combine5", combine5);
 
    return 0;
}
执行结果:
zst@IMZST:~/book_code/CSAPP$ ./a
combine1 result:5024359
combine1 time:40000
combine2 result:5024359
combine2 time:46000
combine3_1 result:5024359
combine3_1 time:36000
combine3_2 result:5024359
combine3_2 time:26000
combine4_1 result:5024359
combine4_1 time:28000
combine4_2 result:5024359
combine4_2 time:30000
combine5 result:5024359
combine5 time:20000

没有评论:

发表评论