-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdmult.c
More file actions
360 lines (315 loc) · 8.41 KB
/
Copy pathdmult.c
File metadata and controls
360 lines (315 loc) · 8.41 KB
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
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
/* Benchmark multiplication of set of numbers */
#include <stdio.h>
#include <stdlib.h>
#include "clock.h"
/* List of numbers */
typedef struct ELE *list_ptr;
typedef struct ELE {
double val;
list_ptr next;
} list_ele;
/* The global data */
/* How many data sets ? */
#define TCNT 5
double *array_data[TCNT];
list_ptr list_data[TCNT];
/* Initialize data */
int global_cnt = 10000;
/* Correct answer */
double answer[TCNT];
void init(int cnt) {
/* Create data that is random sequence of +1 and -1 */
global_cnt = cnt;
int t;
for (t = 0; t < TCNT; t++) {
answer[t] = 1.0;
int i;
array_data[t] = calloc(cnt, sizeof(double));
list_ele *list_nodes = (list_ele *) calloc(cnt, sizeof(list_ele));
list_data[t] = NULL;
for (i = 0; i < cnt; i++) {
double val = random() & 0x1 ? -1.0 : 1.0;
array_data[t][i] = val;
list_ptr head = &list_nodes[i];
head->val = val;
head->next = list_data[t];
list_data[t] = head;
answer[t] *= val;
}
}
}
char list_prod_descr[] = "Traversing Singly-Linked List";
double list_prod(list_ptr ls)
{
double val = 1.0;
while (ls) {
val *= ls->val;
ls = ls->next;
}
return val;
}
double wrap_list_prod(int t)
{
return list_prod(list_data[t]);
}
char array_u1p1S_prod_descr[] = "Array. Unroll 1x. Parallel 1x, Standard associativity";
double array_u1p1S_prod(double *array, int cnt) {
int i;
double val = 1.0;
for (i = 0; i < cnt; i++) {
val *= array[i];
}
return val;
}
double wrap_array_u1p1S_prod(int t)
{
return array_u1p1S_prod(array_data[t], global_cnt);
}
char array_u5p5S_prod_descr[] = "Array. Unroll 5x. Parallel 5x, Standard associativity";
double array_u5p5S_prod(double *array, int cnt) {
int i;
double val0 = 1.0;
double val1 = 1.0;
double val2 = 1.0;
double val3 = 1.0;
double val4 = 1.0;
for (i = 0; i <= cnt-5; i+=5) {
val0 *= array[i];
val1 *= array[i+1];
val2 *= array[i+2];
val3 *= array[i+3];
val4 *= array[i+4];
}
for (; i < cnt; i++)
val0 *= array[i];
return val0 * val1 * val2 * val3 * val4;
}
double wrap_array_u5p5S_prod(int t)
{
return array_u5p5S_prod(array_data[t], global_cnt);
}
char array_u5p1S_prod_descr[] = "Array. Unroll 5x. Parallel 1x, Standard associativity";
double array_u5p1S_prod(double *array, int cnt) {
int i;
double val = 1.0;
for (i = 0; i <= cnt-5; i+=5) {
val = val * array[i] * array[i+1] * array[i+2] * array[i+3] * array[i+4];
}
for (; i < cnt; i++)
val *= array[i];
return val;
}
double wrap_array_u5p1S_prod(int t)
{
return array_u5p1S_prod(array_data[t], global_cnt);
}
char array_u5p1A_prod_descr[] = "Array. Unroll 5x. Parallel 1x, Modified associativity";
double array_u5p1A_prod(double *array, int cnt) {
int i;
double val = 1.0;
for (i = 0; i <= cnt-5; i+=5) {
val = val * ((array[i] * array[i+1]) * (array[i+2] * array[i+3] * array[i+4]));
}
for (; i < cnt; i++)
val *= array[i];
return val;
}
double wrap_array_u5p1A_prod(int t)
{
return array_u5p1A_prod(array_data[t], global_cnt);
}
#define VSIZE 2
typedef double vec_t __attribute__ ((vector_size(16)));
typedef union {
vec_t v;
double d[VSIZE];
} pack_t;
#define ALIGN (VSIZE*sizeof(double))
#define ALIGN_INIT 1
char sse_u1p1_prod_descr[] = "2x SSE. Unroll 1x. Parallel 1x.";
double sse_u1p1_prod(double *array, int cnt)
{
pack_t xfer;
vec_t accum;
double result = 1.0;
double *data = array;
/* Initialize accumulators */
int i;
for (i = 0; i < VSIZE; i++)
xfer.d[i] = 1.0;
accum = xfer.v;
/* Single step until meet alignment requirements */
while (((long) data) % ALIGN && cnt) {
result = result * *data++;
cnt--;
}
/* Parallel accumulation with SSE */
while (cnt >= VSIZE) {
vec_t chunk = *((vec_t *) data);
accum = accum * chunk;
data += VSIZE;
cnt -= VSIZE;
}
/* Single step until end */
while (cnt) {
result = result * *data++;
cnt--;
}
xfer.v = accum;
for (i = 0; i < VSIZE; i++)
result = result * xfer.d[i];
return result;
}
double wrap_sse_u1p1_prod(int t)
{
return sse_u1p1_prod(array_data[t], global_cnt);
}
char sse_u5p5_prod_descr[] = "2x SSE. Unroll 5x. Parallel 5x.";
double sse_u5p5_prod(double *array, int cnt)
{
pack_t xfer;
vec_t accum0, accum1, accum2, accum3, accum4;
double result = 1.0;
double *data = array;
/* Initialize accumulators */
int i;
for (i = 0; i < VSIZE; i++)
xfer.d[i] = 1.0;
accum0 = accum1 = accum2 = accum3 = accum4 = xfer.v;
/* Single step until meet alignment requirements */
while (((long) data) % ALIGN && cnt) {
result = result * *data++;
cnt--;
}
/* Parallel accumulation with SSE */
while (cnt >= VSIZE*5) {
vec_t chunk0 = *((vec_t *) data);
accum0 *= chunk0;
vec_t chunk1 = *((vec_t *) (data+VSIZE));
accum1 *= chunk1;
vec_t chunk2 = *((vec_t *) (data+2*VSIZE));
accum2 *= chunk2;
vec_t chunk3 = *((vec_t *) (data+3*VSIZE));
accum3 *= chunk3;
vec_t chunk4 = *((vec_t *) (data+4*VSIZE));
accum4 *= chunk4;
data += 5*VSIZE;
cnt -= 5*VSIZE;
}
/* Single step until end */
while (cnt) {
result = result * *data++;
cnt--;
}
xfer.v = (accum0 * accum1) * (accum2 * accum3 * accum4);
for (i = 0; i < VSIZE; i++)
result = result * xfer.d[i];
return result;
}
double wrap_sse_u5p5_prod(int t)
{
return sse_u5p5_prod(array_data[t], global_cnt);
}
char sse_u8p8_prod_descr[] = "2x SSE. Unroll 8x. Parallel 8x.";
double sse_u8p8_prod(double *array, int cnt)
{
pack_t xfer;
vec_t accum0, accum1, accum2, accum3, accum4, accum5, accum6, accum7;
double result = 1.0;
double *data = array;
/* Initialize accumulators */
int i;
for (i = 0; i < VSIZE; i++)
xfer.d[i] = 1.0;
accum0 = accum1 = accum2 = accum3 = accum4 = accum5 = accum6 = accum7 = xfer.v;
/* Single step until meet alignment requirements */
while (((long) data) % ALIGN && cnt) {
result = result * *data++;
cnt--;
}
/* Parallel accumulation with SSE */
while (cnt >= VSIZE*8) {
vec_t chunk0 = *((vec_t *) data);
accum0 *= chunk0;
vec_t chunk1 = *((vec_t *) (data+VSIZE));
accum1 *= chunk1;
vec_t chunk2 = *((vec_t *) (data+2*VSIZE));
accum2 *= chunk2;
vec_t chunk3 = *((vec_t *) (data+3*VSIZE));
accum3 *= chunk3;
vec_t chunk4 = *((vec_t *) (data+4*VSIZE));
accum4 *= chunk4;
vec_t chunk5 = *((vec_t *) (data+5*VSIZE));
accum5 *= chunk5;
vec_t chunk6 = *((vec_t *) (data+6*VSIZE));
accum6 *= chunk6;
vec_t chunk7 = *((vec_t *) (data+7*VSIZE));
accum7 *= chunk7;
data += 8*VSIZE;
cnt -= 8*VSIZE;
}
/* Single step until end */
while (cnt) {
result = result * *data++;
cnt--;
}
xfer.v = ((accum0 * accum1) * (accum2 * accum3)) * ((accum4 * accum5) * (accum6 * accum7));
for (i = 0; i < VSIZE; i++)
result = result * xfer.d[i];
return result;
}
double wrap_sse_u8p8_prod(int t)
{
return sse_u8p8_prod(array_data[t], global_cnt);
}
typedef double (*dfun)(int);
void tester(dfun fun, char *name, char *descr) {
int t;
double cyc, nsecs, ghz;
for (t = TCNT-1; t >= 0; t--) {
double val = fun(t);
if (val != answer[t]) {
printf("Function '%s' Data Error. Test %d", name, t);
printf(", Expected %.1f. Got %.1f\n", answer[t], val);
}
}
/* Now do timing run with first data set */
start_counter();
fun(0);
cyc = get_counter();
ghz = mhz(0)/1000.0;
nsecs = cyc/ghz;
printf("Function '%s' (%s) %.0f cycles, %.0f nsecs, %.2f cycles/element\n",
name, descr, cyc, nsecs, cyc/global_cnt);
}
typedef struct {
dfun fun;
char *name;
char *descr;
} b_ele;
b_ele tests[] = {
{wrap_list_prod, "list", list_prod_descr},
{wrap_array_u1p1S_prod, "array_u1p1S", array_u1p1S_prod_descr},
{wrap_array_u5p5S_prod, "array_u5p5S", array_u5p5S_prod_descr},
{wrap_array_u5p1S_prod, "array_u5p1S", array_u5p1S_prod_descr},
{wrap_array_u5p1A_prod, "array_u5p1A", array_u5p1A_prod_descr},
{wrap_sse_u1p1_prod, "sse_u1p1", sse_u1p1_prod_descr},
{wrap_sse_u5p5_prod, "sse_u5p5", sse_u5p5_prod_descr},
{wrap_sse_u8p8_prod, "sse_u8p8", sse_u8p8_prod_descr},
{NULL, NULL, NULL}
};
void run(int cnt) {
init(cnt);
printf("Count = %d, Ghz = %.2f\n", cnt, mhz(0)/1000.0);
int i;
for (i = 0; tests[i].fun != NULL; i++) {
tester(tests[i].fun, tests[i].name, tests[i].descr);
}
}
int main(int argc, char *argv[]) {
int cnt = 20000;
if (argc > 1)
cnt = atoi(argv[1]);
run(cnt);
return 0;
}