-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathmain.c
executable file
·222 lines (187 loc) · 5.79 KB
/
main.c
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
#include <stdlib.h>
#include <stdio.h>
#include "clock.h"
// 测试用的全局内存区域
double data[MAXELEMS];
// 内存测试区域从 2 KB 开始,最大到 64 MB
#define MINBYTES (1 << 11) // 2 KB
#define MAXBYTES (1 << 26) // 64 MB
// 循环步长从1 到 64 字节
#define MAXSTRIDE 64
#define MAXELEMS MAXBYTES/sizeof(double)
void init_data(double *data, int n);
void run_delay_testing();
double get_seque_access_result(int size, int stride, int type);
double get_random_access_result(int size, int type);
void seque_access(int elems, int stride);
void random_access(int* random_index_arr, int count);
void create_rand_array(int max, int count, int* pArr);
int main()
{
init_data(data, MAXELEMS);
printf("Delay (ns)\n");
run_delay_testing();
printf("\n\n");
exit(0);
}
// init_data 初始化要访问的内存数据
void init_data(double *data, int n)
{
int i;
for (i = 0; i < n; i++)
{
data[i] = i;
}
}
// 运行内存访问延时测试
void run_delay_testing(){
int size; // 测试内存区域大小
int stride; // 内存区域访问循环步长
// 打印内存区域大小头信息
printf("\t");
for (size = MINBYTES; size <= MAXBYTES; size <<= 1) {
if (size > (1 << 20)){
printf("%dm\t", size / (1 << 20));
}else{
printf("%dk\t", size / 1024);
}
}
printf("\n");
// 多次实验,进行内存顺序访问延时评估
// 外层循环控制步长依次从 1 到 64,目的是不同的顺序步长的访问效果差异
// 内存循环控制数据大小依次从 2KB 开始到 64MB,目的是要保证数据大小依次超过 L1、L2、L3
for (stride = 1; stride <= MAXSTRIDE; stride=stride*2) {
printf("s%d\t", stride);
for (size = MINBYTES; size <= MAXBYTES; size <<= 1) {
printf("%.2f\t", get_seque_access_result(size, stride, 1));
}
printf("\n");
}
// 多次实验,进行内存随机访问延时评估
printf("random\t");
for (size = MINBYTES; size <= MAXBYTES; size <<= 1) {
printf("%.2f\t", get_random_access_result(size,1));
}
printf("\n");
}
// get_seque_access_result 测试存储访问延迟(L1/L2/L3,内存)
// 参数说明
// - size: 要测试的数据大小
// - stride: 步长
// - type: 0 获取带宽测试结果
// - 1 获取延时测试结果,单位是 CPU 周期数
double get_seque_access_result(int size, int stride, int type)
{
int i;
long int operations;
long int total_accessed_bytes;
long int used_nanoseconds;
int samples = 1000;
int elems = size / sizeof(double);
//循环测试 1000 次,以最大程度减少实验计算结果误差
start_timer();
for(i=0; i<samples; i++){
seque_access(elems, stride);
}
used_nanoseconds = get_timer();
if(0==used_nanoseconds){
return 0;
}
//本次实验所进行的总存储读取次数
operations = (long int)samples * (long int)elems / stride;
//本次实验所读取的总存储读取大小
total_accessed_bytes = operations * sizeof(double);
double result = 0;
// 获取带宽结果
if(0==type){
/* width = size(M)/ time(s)
= (total_accessed_bytes / 1000000) / (used_nanoseconds / 1000000000)
= total_accessed_bytes*1000/used_nanoseconds;
*/
result = total_accessed_bytes * 1000 / used_nanoseconds;
// 获取延迟测试结果
}else if(1==type){
result = (double)used_nanoseconds/operations;
}
return result;
}
// 内存按照一定的步长进行顺序访问
void seque_access(int elems, int stride) /* The test function */
{
int i;
double result = 0.0;
volatile double sink;
for (i = 0; i < elems; i += stride) {
result += data[i];
}
//这一行是为了避免编译器把循环给优化掉了
sink = result;
}
// get_random_access_result 对存储进行随机访问测试(L1/L2/L3,内存)
// 参数说明
// - size: 要测试的数据大小
// - type: 0 获取带宽测试结果
// - 1 获取延时测试结果,单位是 CPU 周期数
double get_random_access_result(int size, int type)
{
int i;
int *p;
long int operations;
long int total_accessed_bytes;
long int used_nanoseconds;
int samples = 300;
int elems = size / sizeof(double);
int access_count = elems;
//在实验开始前,提前要随机访问的数组下标准备好
int* random_access_arr = malloc(access_count*sizeof(int));
for(i=0,p=random_access_arr; i<access_count; i++,p++){
*p = 0;
}
create_rand_array(elems, access_count, random_access_arr);
//开始进行随机访问测试,运行 300 次,以降低实验误差
start_timer();
for(i=0; i<samples; i++){
random_access(random_access_arr, access_count);
}
used_nanoseconds = get_timer();
//本次实验所进行的总存储读取次数
operations = (long int)samples * (long int)access_count;
//本次实验所读取的总存储读取大小
total_accessed_bytes = operations * sizeof(double);
double result = 0;;
// 获取带宽结果
if(0==type){
/* width = size(M)/ time(s)
= (total_accessed_bytes / 1000000) / (used_nanoseconds / 1000000000)
= total_accessed_bytes*1000/used_nanoseconds;
*/
result = total_accessed_bytes * 1000 / used_nanoseconds;
// 获取延时结果
}else if(1==type){
result = used_nanoseconds/operations*2.4;
}
return result;
}
// 提前把要进行随机访问的数组下标准备好,用于随机访问测试
void create_rand_array(int max, int count, int* pArr)
{
int i;
for (i = 0; i < count; i ++,pArr++) {
int rd = rand();
int randRet = (long int)rd * max / RAND_MAX;
*pArr = randRet;
}
return;
}
// random_access 按照指定的随机下标对数据进行随机访问
void random_access(int* random_index_arr, int count) /* The test function */
{
int i;
double result = 0.0;
volatile double sink;
for (i = 0; i < count; i++) {
result += data[*(random_index_arr+i)];
}
//这一行是为了避免编译器把循环给优化掉了
sink = result;
}