├── Android.mk
├── Changes.txt
├── Generate_Graphs
├── Gnuplot.txt
├── README.md
├── client_list
├── fileop.c
├── gengnuplot.sh
├── gnu3d.dem
├── gnuplot.dem
├── gnuplotps.dem
├── iozone.c
├── iozone_visualizer.pl
├── libasync.c
├── libbif.c
├── makefile
├── pit_server.c
├── read_telemetry
├── report.pl
├── spec.in
└── write_telemetry
/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH:= $(call my-dir)
2 | include $(CLEAR_VARS)
3 |
4 | LOCAL_CFLAGS:= -O3 -Dunix -DHAVE_ANSIC_C -DHAVE_PREAD -DNAME='"linux-arm"' -DLINUX_ARM -Dlinux -lrt -lpthread
5 |
6 | LOCAL_SRC_FILES:= iozone.c libbif.c
7 |
8 | LOCAL_MODULE:= iozone
9 |
10 | # ignore warning that cause compile failed on Android M
11 | LOCAL_CFLAGS +=-Wno-unused-parameter -Wno-empty-body -Wno-sign-compare -Wno-format -Wno-error=implicit-function-declaration
12 |
13 | include $(BUILD_EXECUTABLE)
14 |
15 |
--------------------------------------------------------------------------------
/Generate_Graphs:
--------------------------------------------------------------------------------
1 | #
2 | # This script will create the Iozone graphs using
3 | # gnuplot.
4 | #
5 | #
6 | #
7 | # ------------------------------------------------
8 | # YOU MUST PROVIDE A FILE NAME FOR IT TO PROCESS.
9 | # This filename is the name of the file where you
10 | # sent Iozone's output.
11 | # ------------------------------------------------
12 |
13 | # Generate data base for all of the operation types.
14 |
15 | ./gengnuplot.sh $1 write
16 | ./gengnuplot.sh $1 rewrite
17 | ./gengnuplot.sh $1 read
18 | ./gengnuplot.sh $1 reread
19 | ./gengnuplot.sh $1 randread
20 | ./gengnuplot.sh $1 randwrite
21 | ./gengnuplot.sh $1 bkwdread
22 | ./gengnuplot.sh $1 recrewrite
23 | ./gengnuplot.sh $1 strideread
24 | ./gengnuplot.sh $1 fwrite
25 | ./gengnuplot.sh $1 frewrite
26 | ./gengnuplot.sh $1 fread
27 | ./gengnuplot.sh $1 freread
28 |
29 | # Produce graphs and postscript results.
30 | gnuplot gnu3d.dem
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Gnuplot.txt:
--------------------------------------------------------------------------------
1 | The script Generate_Graphs will create the 3D surface plots
2 | and display them. It will also produce postscript outputs
3 | for each test and leave them in their respective sub-directory.
4 |
5 | It processes the output from an Iozone run. The output from
6 | Iozone that it is expecting is the text output from
7 | the iozone default behavior. (iozone -a, or iozone -az)
8 |
9 | How to produce graphs:
10 |
11 | Generate_Graphs iozone.out
12 |
13 | The gen_graphs script will:
14 | 1. Create the databases for each type of operation
15 | and then processes them with Gnuplot.
16 | 2. It will display each result on the X11 screen, and
17 | also save a copy in postscript in the test sub-directory.
18 |
19 |
20 | Thanks to Yves Rougy for providing the nifty scripts to help
21 | with the plots.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | iozone4Android
2 | ==============
3 |
4 | porting iozone to android
5 |
6 | usage:
7 | cd android/
8 | source ./build/envsetup.sh
9 | lunch xx
10 | cd android/external/
11 | git clone https://github.com/royzhao/iozone4Android.git
12 | cd iozone4Android
13 | mm
14 |
--------------------------------------------------------------------------------
/client_list:
--------------------------------------------------------------------------------
1 | #
2 | # Lines that start with # in column 0 are comments.
3 | #
4 | # There are now two formats supported.
5 | # Format: 3 fields, space delimited.
6 | # Format: 4 fields, space delimited.
7 | #
8 | # Format: 3 fields, space delimited.
9 | # client_name working_dir_on_client path_to_iozone_on_client
10 | # Format: 4 fields, space delimited.
11 | # client_name working_dir_on_client path_to_iozone_on_client path_to_testfile
12 | #
13 | # Example: With two clients (format 3 fields)
14 | #
15 | # client1 /home/user/tmp /home/user/tmp/iozone
16 | # client2 /home/user/tmp /home/user/tmp/iozone
17 | #
18 | #
19 | # Example: With two copies of Iozone on each of the two clients
20 | # (format 3 fields)
21 | #
22 | # client1 /home/user/tmp /home/user/tmp/iozone
23 | # client1 /home/user/tmp /home/user/tmp/iozone
24 | # client2 /home/user/tmp /home/user/tmp/iozone
25 | # client2 /home/user/tmp /home/user/tmp/iozone
26 | #
27 | # Example: With two clients (format 4 fields)
28 | # client1 /home/user/tmp /home/user/tmp/iozone /tmp/foo1
29 | # client2 /home/user/tmp /home/user/tmp/iozone /tmp/foo2
30 | #
31 | # Example: With two copies of Iozone on each of the two clients
32 | # (format 4 fields)
33 | # client1 /home/user/tmp /home/user/tmp/iozone /tmp/foo1
34 | # client1 /home/user/tmp /home/user/tmp/iozone /tmp/foo2
35 | # client2 /home/user/tmp /home/user/tmp/iozone /tmp/foo3
36 | # client2 /home/user/tmp /home/user/tmp/iozone /tmp/foo4
37 |
--------------------------------------------------------------------------------
/fileop.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Author: Don Capps
3 | * 3/13/2006
4 | *
5 | * Author: Don Capps (capps@iozone.org)
6 | * 7417 Crenshaw
7 | * Plano, TX 75025
8 | *
9 | * Copyright 2006, 2007, 2008, 2009 Don Capps.
10 | *
11 | * License to freely use and distribute this software is hereby granted
12 | * by the author, subject to the condition that this copyright notice
13 | * remains intact. The author retains the exclusive right to publish
14 | * derivative works based on this work, including, but not limited to,
15 | * revised versions of this work",
16 | *
17 | *
18 | fileop [-f X ]|[-l # -u #] [-s Y] [-e] [-b] [-w] [-d
] [-t] [-v] [-h]
19 | -f # Force factor. X^3 files will be created and removed.
20 | -l # Lower limit on the value of the Force factor.
21 | -u # Upper limit on the value of the Force factor.
22 | -s # Optional. Sets filesize for the create/write. May use suffix 'K' or 'M'.
23 | -e Excel importable format.
24 | -b Output best case.
25 | -w Output worst case.
26 | -d Specify starting directory.
27 | -U Mount point to remount between tests.
28 | -t Verbose output option.
29 | -v Version information.
30 | -h Help text.
31 | *
32 | * X is a force factor. The total number of files will
33 | * be X * X * X ( X ^ 3 )
34 | * The structure of the file tree is:
35 | * X number of Level 1 directories, with X number of
36 | * level 2 directories, with X number of files in each
37 | * of the level 2 directories.
38 | *
39 | * Example: fileop 2
40 | *
41 | * dir_1 dir_2
42 | * / \ / \
43 | * sdir_1 sdir_2 sdir_1 sdir_2
44 | * / \ / \ / \ / \
45 | * file_1 file_2 file_1 file_2 file_1 file_2 file_1 file_2
46 | *
47 | * Each file will be created, and then 1 byte is written to the file.
48 | *
49 | */
50 |
51 | #include
52 | #include
53 | #include
54 | #include
55 | #include
56 | #include
57 | #include
58 | #include
59 | #include
60 | #include
61 |
62 | #include
63 |
64 | #if defined(Windows)
65 | #include
66 | #endif
67 | #if !defined(PATH_MAX)
68 | #define PATH_MAX 255
69 | #endif
70 |
71 | int x,excel;
72 | int verbose = 0;
73 | int sz = 1;
74 | char *mbuffer;
75 | #define _STAT_CREATE 0
76 | #define _STAT_WRITE 1
77 | #define _STAT_CLOSE 2
78 | #define _STAT_LINK 3
79 | #define _STAT_UNLINK 4
80 | #define _STAT_DELETE 5
81 | #define _STAT_STAT 6
82 | #define _STAT_ACCESS 7
83 | #define _STAT_CHMOD 8
84 | #define _STAT_READDIR 9
85 | #define _STAT_DIR_CREATE 10
86 | #define _STAT_DIR_DELETE 11
87 | #define _STAT_READ 12
88 | #define _STAT_OPEN 13
89 | #define _STAT_DIR_TRAVERSE 14
90 | #define _NUM_STATS 15
91 | struct stat_struct {
92 | double starttime;
93 | double endtime;
94 | double speed;
95 | double best;
96 | double worst;
97 | double dummy;
98 | double total_time;
99 | double dummy1;
100 | long long counter;
101 | } volatile stats[_NUM_STATS];
102 |
103 |
104 | static double time_so_far(void);
105 | void dir_create(int);
106 | void dir_traverse(int);
107 | void dir_delete(int);
108 | void file_create(int);
109 | void file_stat(int);
110 | void file_access(int);
111 | void file_chmod(int);
112 | void file_readdir(int);
113 | void file_delete(int);
114 | void file_link(int);
115 | void file_unlink(int);
116 | void file_read(int);
117 | void splash(void);
118 | void usage(void);
119 | void bzero();
120 | void clear_stats();
121 | int validate(char *, int , char );
122 |
123 | #define THISVERSION " $Revision: 1.53 $"
124 | /*#define NULL 0*/
125 |
126 | char version[]=THISVERSION;
127 | char thedir[PATH_MAX]="."; /* Default is to use the current directory */
128 | const char *mountname=NULL; /* Default is not to unmount anything between the tests */
129 |
130 | int cret;
131 | int lower, upper,range;
132 | int i;
133 | int best, worst;
134 | int dirlen;
135 |
136 | /************************************************************************/
137 | /* Routine to purge the buffer cache by unmounting drive. */
138 | /************************************************************************/
139 | void purge_buffer_cache()
140 | {
141 | if (!mountname)
142 | return;
143 |
144 | char cwd[PATH_MAX];
145 | char command[1024];
146 | int ret,i;
147 |
148 | getcwd(cwd, sizeof(cwd));
149 | chdir("/");
150 | strcpy(command,"umount ");
151 | strcat(command, mountname);
152 | /*
153 | umount might fail if the device is still busy, so
154 | retry unmounting several times with increasing delays
155 | */
156 | for (i = 1; i < 10; ++i) {
157 | ret = system(command);
158 | if (ret == 0)
159 | break;
160 | sleep(i); // seconds
161 | }
162 | strcpy(command,"mount ");
163 | strcat(command, mountname);
164 | system(command);
165 | chdir(cwd);
166 | }
167 |
168 | int main(int argc, char **argv)
169 | {
170 | if(argc == 1)
171 | {
172 | usage();
173 | exit(1);
174 | }
175 | while((cret = getopt(argc,argv,"hbwetvf:s:l:u:d:U: ")) != EOF){
176 | switch(cret){
177 | case 'h':
178 | usage();
179 | exit(0);
180 | break;
181 | case 'd' :
182 | dirlen=strlen(optarg);
183 | if (optarg[dirlen-1]=='/')
184 | --dirlen;
185 | strncpy(thedir, optarg, dirlen);
186 | thedir[dirlen] = 0;
187 | break;
188 | case 'U':
189 | mountname = optarg;
190 | break;
191 | case 'f': /* Force factor */
192 | x=atoi(optarg);
193 | if(x < 0)
194 | x=1;
195 | break;
196 | case 's': /* Size of files */
197 | sz=atoi(optarg);
198 | if(optarg[strlen(optarg)-1]=='k' ||
199 | optarg[strlen(optarg)-1]=='K'){
200 | sz = (1024 * atoi(optarg));
201 | }
202 | if(optarg[strlen(optarg)-1]=='m' ||
203 | optarg[strlen(optarg)-1]=='M'){
204 | sz = (1024 * 1024 * atoi(optarg));
205 | }
206 | if(sz < 0)
207 | sz=1;
208 | break;
209 | case 'l': /* lower force value */
210 | lower=atoi(optarg);
211 | range=1;
212 | if(lower < 0)
213 | lower=1;
214 | break;
215 | case 'v': /* version */
216 | splash();
217 | exit(0);
218 | break;
219 | case 'u': /* upper force value */
220 | upper=atoi(optarg);
221 | range=1;
222 | if(upper < 0)
223 | upper=1;
224 | break;
225 | case 't': /* verbose */
226 | verbose=1;
227 | break;
228 | case 'e': /* Excel */
229 | excel=1;
230 | break;
231 | case 'b': /* Best */
232 | best=1;
233 | break;
234 | case 'w': /* Worst */
235 | worst=1;
236 | break;
237 | }
238 | }
239 | mbuffer=(char *)malloc(sz);
240 | memset(mbuffer,'a',sz);
241 | if(!excel)
242 | printf("\nFileop: Working in %s, File size is %d, Output is in Ops/sec. (A=Avg, B=Best, W=Worst)\n", thedir, sz);
243 | if(!verbose)
244 | {
245 | #ifdef Windows
246 | printf(" . %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %10s\n",
247 | "mkdir","chdir","rmdir","create","open","read","write","close","stat",
248 | "access","chmod","readdir","delete"," Total_files");
249 | #else
250 |
251 | printf(" . %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %7s %10s\n",
252 | "mkdir","chdir","rmdir","create","open", "read","write","close","stat",
253 | "access","chmod","readdir","link ","unlink","delete",
254 | " Total_files");
255 | #endif
256 | }
257 | chdir(thedir); /* change starting point */
258 | if(x==0)
259 | x=1;
260 | if(range==0)
261 | lower=upper=x;
262 | for(i=lower;i<=upper;i++)
263 | {
264 | clear_stats();
265 | x=i;
266 | /*
267 | * Dir Create test
268 | */
269 | purge_buffer_cache();
270 | dir_create(x);
271 |
272 | if(verbose)
273 | {
274 | printf("mkdir: Dirs = %9lld ",stats[_STAT_DIR_CREATE].counter);
275 | printf("Total Time = %12.9f seconds\n", stats[_STAT_DIR_CREATE].total_time);
276 | printf(" Avg mkdir(s)/sec = %12.2f (%12.9f seconds/op)\n",
277 | stats[_STAT_DIR_CREATE].counter/stats[_STAT_DIR_CREATE].total_time,
278 | stats[_STAT_DIR_CREATE].total_time/stats[_STAT_DIR_CREATE].counter);
279 | printf(" Best mkdir(s)/sec = %12.2f (%12.9f seconds/op)\n",1/stats[_STAT_DIR_CREATE].best,stats[_STAT_DIR_CREATE].best);
280 | printf(" Worst mkdir(s)/sec = %12.2f (%12.9f seconds/op)\n\n",1/stats[_STAT_DIR_CREATE].worst,stats[_STAT_DIR_CREATE].worst);
281 | }
282 |
283 | /*
284 | * Dir Traverse test
285 | */
286 | purge_buffer_cache();
287 | dir_traverse(x);
288 |
289 | if(verbose)
290 | {
291 | printf("chdir: Dirs = %9lld ",stats[_STAT_DIR_TRAVERSE].counter);
292 | printf("Total Time = %12.9f seconds\n", stats[_STAT_DIR_TRAVERSE].total_time);
293 | printf(" Avg chdir(s)/sec = %12.2f (%12.9f seconds/op)\n",
294 | stats[_STAT_DIR_TRAVERSE].counter/stats[_STAT_DIR_TRAVERSE].total_time,
295 | stats[_STAT_DIR_TRAVERSE].total_time/stats[_STAT_DIR_TRAVERSE].counter);
296 | printf(" Best chdir(s)/sec = %12.2f (%12.9f seconds/op)\n",1/stats[_STAT_DIR_TRAVERSE].best,stats[_STAT_DIR_TRAVERSE].best);
297 | printf(" Worst chdir(s)/sec = %12.2f (%12.9f seconds/op)\n\n",1/stats[_STAT_DIR_TRAVERSE].worst,stats[_STAT_DIR_TRAVERSE].worst);
298 | }
299 |
300 | /*
301 | * Dir delete test
302 | */
303 | purge_buffer_cache();
304 | dir_delete(x);
305 |
306 | if(verbose)
307 | {
308 | printf("rmdir: Dirs = %9lld ",stats[_STAT_DIR_DELETE].counter);
309 | printf("Total Time = %12.9f seconds\n",stats[_STAT_DIR_DELETE].total_time);
310 | printf(" Avg rmdir(s)/sec = %12.2f (%12.9f seconds/op)\n",
311 | stats[_STAT_DIR_DELETE].counter/stats[_STAT_DIR_DELETE].total_time,
312 | stats[_STAT_DIR_DELETE].total_time/stats[_STAT_DIR_DELETE].counter);
313 | printf(" Best rmdir(s)/sec = %12.2f (%12.9f seconds/op)\n",1/stats[_STAT_DIR_DELETE].best,stats[_STAT_DIR_DELETE].best);
314 | printf(" Worst rmdir(s)/sec = %12.2f (%12.9f seconds/op)\n\n",1/stats[_STAT_DIR_DELETE].worst,stats[_STAT_DIR_DELETE].worst);
315 | }
316 |
317 | /*
318 | * Create test
319 | */
320 | purge_buffer_cache();
321 | file_create(x);
322 | if(verbose)
323 | {
324 | printf("create: Files = %9lld ",stats[_STAT_CREATE].counter);
325 | printf("Total Time = %12.9f seconds\n", stats[_STAT_CREATE].total_time);
326 | printf(" Avg create(s)/sec = %12.2f (%12.9f seconds/op)\n",
327 | stats[_STAT_CREATE].counter/stats[_STAT_CREATE].total_time,
328 | stats[_STAT_CREATE].total_time/stats[_STAT_CREATE].counter);
329 | printf(" Best create(s)/sec = %12.2f (%12.9f seconds/op)\n",
330 | 1/stats[_STAT_CREATE].best,stats[_STAT_CREATE].best);
331 | printf(" Worst create(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
332 | 1/stats[_STAT_CREATE].worst,stats[_STAT_CREATE].worst);
333 | printf("write: Files = %9lld ",stats[_STAT_WRITE].counter);
334 | printf("Total Time = %12.9f seconds\n", stats[_STAT_WRITE].total_time);
335 | printf(" Avg write(s)/sec = %12.2f (%12.9f seconds/op)\n",
336 | stats[_STAT_WRITE].counter/stats[_STAT_WRITE].total_time,
337 | stats[_STAT_WRITE].total_time/stats[_STAT_WRITE].counter);
338 | printf(" Best write(s)/sec = %12.2f (%12.9f seconds/op)\n",
339 | 1/stats[_STAT_WRITE].best,stats[_STAT_WRITE].best);
340 | printf(" Worst write(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
341 | 1/stats[_STAT_WRITE].worst,stats[_STAT_WRITE].worst);
342 | printf("close: Files = %9lld ",stats[_STAT_CLOSE].counter);
343 | printf("Total Time = %12.9f seconds\n", stats[_STAT_CLOSE].total_time);
344 | printf(" Avg close(s)/sec = %12.2f (%12.9f seconds/op)\n",
345 | stats[_STAT_CLOSE].counter/stats[_STAT_CLOSE].total_time,
346 | stats[_STAT_CLOSE].total_time/stats[_STAT_CLOSE].counter);
347 | printf(" Best close(s)/sec = %12.2f (%12.9f seconds/op)\n",
348 | 1/stats[_STAT_CLOSE].best,stats[_STAT_CLOSE].best);
349 | printf(" Worst close(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
350 | 1/stats[_STAT_CLOSE].worst,stats[_STAT_CLOSE].worst);
351 | }
352 |
353 | /*
354 | * Stat test
355 | */
356 | purge_buffer_cache();
357 | file_stat(x);
358 |
359 | if(verbose)
360 | {
361 | printf("stat: Files = %9lld ",stats[_STAT_STAT].counter);
362 | printf("Total Time = %12.9f seconds\n", stats[_STAT_STAT].total_time);
363 | printf(" Avg stat(s)/sec = %12.2f (%12.9f seconds/op)\n",
364 | stats[_STAT_STAT].counter/stats[_STAT_STAT].total_time,
365 | stats[_STAT_STAT].total_time/stats[_STAT_STAT].counter);
366 | printf(" Best stat(s)/sec = %12.2f (%12.9f seconds/op)\n",
367 | 1/stats[_STAT_STAT].best,stats[_STAT_STAT].best);
368 | printf(" Worst stat(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
369 | 1/stats[_STAT_STAT].worst,stats[_STAT_STAT].worst);
370 | }
371 | /*
372 | * Read test
373 | */
374 | purge_buffer_cache();
375 | file_read(x);
376 |
377 | if(verbose)
378 | {
379 | printf("open: Files = %9lld ",stats[_STAT_OPEN].counter);
380 | printf("Total Time = %12.9f seconds\n", stats[_STAT_OPEN].total_time);
381 | printf(" Avg open(s)/sec = %12.2f (%12.9f seconds/op)\n",
382 | stats[_STAT_OPEN].counter/stats[_STAT_OPEN].total_time,
383 | stats[_STAT_OPEN].total_time/stats[_STAT_OPEN].counter);
384 | printf(" Best open(s)/sec = %12.2f (%12.9f seconds/op)\n",
385 | 1/stats[_STAT_OPEN].best,stats[_STAT_OPEN].best);
386 | printf(" Worst open(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
387 | 1/stats[_STAT_OPEN].worst,stats[_STAT_OPEN].worst);
388 |
389 | printf("read: Files = %9lld ",stats[_STAT_READ].counter);
390 | printf("Total Time = %12.9f seconds\n", stats[_STAT_READ].total_time);
391 | printf(" Avg read(s)/sec = %12.2f (%12.9f seconds/op)\n",
392 | stats[_STAT_READ].counter/stats[_STAT_READ].total_time,
393 | stats[_STAT_READ].total_time/stats[_STAT_READ].counter);
394 | printf(" Best read(s)/sec = %12.2f (%12.9f seconds/op)\n",
395 | 1/stats[_STAT_READ].best,stats[_STAT_READ].best);
396 | printf(" Worst read(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
397 | 1/stats[_STAT_READ].worst,stats[_STAT_READ].worst);
398 | }
399 |
400 | /*
401 | * Access test
402 | */
403 | purge_buffer_cache();
404 | file_access(x);
405 | if(verbose)
406 | {
407 | printf("access: Files = %9lld ",stats[_STAT_ACCESS].counter);
408 | printf("Total Time = %12.9f seconds\n", stats[_STAT_ACCESS].total_time);
409 | printf(" Avg access(s)/sec = %12.2f (%12.9f seconds/op)\n",
410 | stats[_STAT_ACCESS].counter/stats[_STAT_ACCESS].total_time,
411 | stats[_STAT_ACCESS].total_time/stats[_STAT_ACCESS].counter);
412 | printf(" Best access(s)/sec = %12.2f (%12.9f seconds/op)\n",
413 | 1/stats[_STAT_ACCESS].best,stats[_STAT_ACCESS].best);
414 | printf(" Worst access(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
415 | 1/stats[_STAT_ACCESS].worst,stats[_STAT_ACCESS].worst);
416 | }
417 | /*
418 | * Chmod test
419 | */
420 | purge_buffer_cache();
421 | file_chmod(x);
422 |
423 | if(verbose)
424 | {
425 | printf("chmod: Files = %9lld ",stats[_STAT_CHMOD].counter);
426 | printf("Total Time = %12.9f seconds\n", stats[_STAT_CHMOD].total_time);
427 | printf(" Avg chmod(s)/sec = %12.2f (%12.9f seconds/op)\n",
428 | stats[_STAT_CHMOD].counter/stats[_STAT_CHMOD].total_time,
429 | stats[_STAT_CHMOD].total_time/stats[_STAT_CHMOD].counter);
430 | printf(" Best chmod(s)/sec = %12.2f (%12.9f seconds/op)\n",
431 | 1/stats[_STAT_CHMOD].best,stats[_STAT_CHMOD].best);
432 | printf(" Worst chmod(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
433 | 1/stats[_STAT_CHMOD].worst,stats[_STAT_CHMOD].worst);
434 | }
435 | /*
436 | * readdir test
437 | */
438 | purge_buffer_cache();
439 | file_readdir(x);
440 |
441 | if(verbose)
442 | {
443 | printf("readdir: Files = %9lld ",stats[_STAT_READDIR].counter);
444 | printf("Total Time = %12.9f seconds\n", stats[_STAT_READDIR].total_time);
445 | printf(" Avg readdir(s)/sec = %12.2f (%12.9f seconds/op)\n",
446 | stats[_STAT_READDIR].counter/stats[_STAT_READDIR].total_time,
447 | stats[_STAT_READDIR].total_time/stats[_STAT_READDIR].counter);
448 | printf(" Best readdir(s)/sec = %12.2f (%12.9f seconds/op)\n",
449 | 1/stats[_STAT_READDIR].best,stats[_STAT_READDIR].best);
450 | printf(" Worst readdir(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
451 | 1/stats[_STAT_READDIR].worst,stats[_STAT_READDIR].worst);
452 | }
453 | #if !defined(Windows)
454 | /*
455 | * link test
456 | */
457 | purge_buffer_cache();
458 | file_link(x);
459 | if(verbose)
460 | {
461 | printf("link: Files = %9lld ",stats[_STAT_LINK].counter);
462 | printf("Total Time = %12.9f seconds\n",stats[_STAT_LINK].total_time);
463 | printf(" Avg link(s)/sec = %12.2f (%12.9f seconds/op)\n",
464 | stats[_STAT_LINK].counter/stats[_STAT_LINK].total_time,
465 | stats[_STAT_LINK].total_time/stats[_STAT_LINK].counter);
466 | printf(" Best link(s)/sec = %12.2f (%12.9f seconds/op)\n",
467 | 1/stats[_STAT_LINK].best,stats[_STAT_LINK].best);
468 | printf(" Worst link(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
469 | 1/stats[_STAT_LINK].worst,stats[_STAT_LINK].worst);
470 | }
471 | /*
472 | * unlink test
473 | */
474 | purge_buffer_cache();
475 | file_unlink(x);
476 | if(verbose)
477 | {
478 | printf("unlink: Files = %9lld ",stats[_STAT_UNLINK].counter);
479 | printf("Total Time = %12.9f seconds\n", stats[_STAT_UNLINK].total_time);
480 | printf(" Avg unlink(s)/sec = %12.2f (%12.9f seconds/op)\n",
481 | stats[_STAT_UNLINK].counter/stats[_STAT_UNLINK].total_time,
482 | stats[_STAT_UNLINK].total_time/stats[_STAT_UNLINK].counter);
483 | printf(" Best unlink(s)/sec = %12.2f (%12.9f seconds/op)\n",
484 | 1/stats[_STAT_UNLINK].best,stats[_STAT_UNLINK].best);
485 | printf(" Worst unlink(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
486 | 1/stats[_STAT_UNLINK].worst,stats[_STAT_UNLINK].worst);
487 | }
488 | #endif
489 | /*
490 | * Delete test
491 | */
492 | purge_buffer_cache();
493 | file_delete(x);
494 | if(verbose)
495 | {
496 | printf("delete: Files = %9lld ",stats[_STAT_DELETE].counter);
497 | printf("Total Time = %12.9f seconds\n", stats[_STAT_DELETE].total_time);
498 | printf(" Avg delete(s)/sec = %12.2f (%12.9f seconds/op)\n",
499 | stats[_STAT_DELETE].counter/stats[_STAT_DELETE].total_time,
500 | stats[_STAT_DELETE].total_time/stats[_STAT_DELETE].counter);
501 | printf(" Best delete(s)/sec = %12.2f (%12.9f seconds/op)\n",
502 | 1/stats[_STAT_DELETE].best,stats[_STAT_DELETE].best);
503 | printf(" Worst delete(s)/sec = %12.2f (%12.9f seconds/op)\n\n",
504 | 1/stats[_STAT_DELETE].worst,stats[_STAT_DELETE].worst);
505 | }
506 | if(!verbose)
507 | {
508 | printf("%c %4d %7.0f ",'A',x,stats[_STAT_DIR_CREATE].counter/stats[_STAT_DIR_CREATE].total_time);
509 | printf("%7.0f ",stats[_STAT_DIR_TRAVERSE].counter/stats[_STAT_DIR_TRAVERSE].total_time);
510 | printf("%7.0f ",stats[_STAT_DIR_DELETE].counter/stats[_STAT_DIR_DELETE].total_time);
511 | printf("%7.0f ",stats[_STAT_CREATE].counter/stats[_STAT_CREATE].total_time);
512 | printf("%7.0f ",stats[_STAT_OPEN].counter/stats[_STAT_OPEN].total_time);
513 | printf("%7.0f ",stats[_STAT_READ].counter/stats[_STAT_READ].total_time);
514 | printf("%7.0f ",stats[_STAT_WRITE].counter/stats[_STAT_WRITE].total_time);
515 | printf("%7.0f ",stats[_STAT_CLOSE].counter/stats[_STAT_CLOSE].total_time);
516 | printf("%7.0f ",stats[_STAT_STAT].counter/stats[_STAT_STAT].total_time);
517 | printf("%7.0f ",stats[_STAT_ACCESS].counter/stats[_STAT_ACCESS].total_time);
518 | printf("%7.0f ",stats[_STAT_CHMOD].counter/stats[_STAT_CHMOD].total_time);
519 | printf("%7.0f ",stats[_STAT_READDIR].counter/stats[_STAT_READDIR].total_time);
520 | #ifndef Windows
521 | printf("%7.0f ",stats[_STAT_LINK].counter/stats[_STAT_LINK].total_time);
522 | printf("%7.0f ",stats[_STAT_UNLINK].counter/stats[_STAT_UNLINK].total_time);
523 | #endif
524 | printf("%7.0f ",stats[_STAT_DELETE].counter/stats[_STAT_DELETE].total_time);
525 | printf("%10d ",x*x*x);
526 | printf("\n");
527 | fflush(stdout);
528 |
529 | if(best)
530 | {
531 | printf("%c %4d %7.0f ",'B',x, 1/stats[_STAT_DIR_CREATE].best);
532 | printf("%7.0f ",1/stats[_STAT_DIR_TRAVERSE].best);
533 | printf("%7.0f ",1/stats[_STAT_DIR_DELETE].best);
534 | printf("%7.0f ",1/stats[_STAT_CREATE].best);
535 | printf("%7.0f ",1/stats[_STAT_OPEN].best);
536 | printf("%7.0f ",1/stats[_STAT_READ].best);
537 | printf("%7.0f ",1/stats[_STAT_WRITE].best);
538 | printf("%7.0f ",1/stats[_STAT_CLOSE].best);
539 | printf("%7.0f ",1/stats[_STAT_STAT].best);
540 | printf("%7.0f ",1/stats[_STAT_ACCESS].best);
541 | printf("%7.0f ",1/stats[_STAT_CHMOD].best);
542 | printf("%7.0f ",1/stats[_STAT_READDIR].best);
543 | #ifndef Windows
544 | printf("%7.0f ",1/stats[_STAT_LINK].best);
545 | printf("%7.0f ",1/stats[_STAT_UNLINK].best);
546 | #endif
547 | printf("%7.0f ",1/stats[_STAT_DELETE].best);
548 | printf("%10d ",x*x*x);
549 | printf("\n");
550 | fflush(stdout);
551 | }
552 | if(worst)
553 | {
554 | printf("%c %4d %7.0f ",'W',x, 1/stats[_STAT_DIR_CREATE].worst);
555 | printf("%7.0f ",1/stats[_STAT_DIR_TRAVERSE].worst);
556 | printf("%7.0f ",1/stats[_STAT_DIR_DELETE].worst);
557 | printf("%7.0f ",1/stats[_STAT_CREATE].worst);
558 | printf("%7.0f ",1/stats[_STAT_OPEN].worst);
559 | printf("%7.0f ",1/stats[_STAT_READ].worst);
560 | printf("%7.0f ",1/stats[_STAT_WRITE].worst);
561 | printf("%7.0f ",1/stats[_STAT_CLOSE].worst);
562 | printf("%7.0f ",1/stats[_STAT_STAT].worst);
563 | printf("%7.0f ",1/stats[_STAT_ACCESS].worst);
564 | printf("%7.0f ",1/stats[_STAT_CHMOD].worst);
565 | printf("%7.0f ",1/stats[_STAT_READDIR].worst);
566 | #ifndef Windows
567 | printf("%7.0f ",1/stats[_STAT_LINK].worst);
568 | printf("%7.0f ",1/stats[_STAT_UNLINK].worst);
569 | #endif
570 | printf("%7.0f ",1/stats[_STAT_DELETE].worst);
571 | printf("%10d ",x*x*x);
572 | printf("\n");
573 | fflush(stdout);
574 | }
575 | }
576 | }
577 | return(0);
578 | }
579 |
580 | void
581 | dir_create(int x)
582 | {
583 | int i,j,k;
584 | int ret;
585 | char buf[100];
586 | stats[_STAT_DIR_CREATE].best=(double)99999.9;
587 | stats[_STAT_DIR_CREATE].worst=(double)0.00000000;
588 | for(i=0;i stats[_STAT_DIR_CREATE].worst)
607 | stats[_STAT_DIR_CREATE].worst=stats[_STAT_DIR_CREATE].speed;
608 | chdir(buf);
609 | for(j=0;j stats[_STAT_DIR_CREATE].worst)
628 | stats[_STAT_DIR_CREATE].worst=stats[_STAT_DIR_CREATE].speed;
629 | chdir(buf);
630 | for(k=0;k stats[_STAT_DIR_CREATE].worst)
649 | stats[_STAT_DIR_CREATE].worst=stats[_STAT_DIR_CREATE].speed;
650 | chdir(buf);
651 | chdir("..");
652 | }
653 | chdir("..");
654 | }
655 | chdir("..");
656 | }
657 | }
658 |
659 | void
660 | dir_traverse(int x)
661 | {
662 | int i,j,k;
663 | char buf[100];
664 | double time1, time2;
665 | stats[_STAT_DIR_TRAVERSE].best=(double)99999.9;
666 | stats[_STAT_DIR_TRAVERSE].worst=(double)0.00000000;
667 | for(i=0;i stats[_STAT_DIR_TRAVERSE].worst)
696 | stats[_STAT_DIR_TRAVERSE].worst=stats[_STAT_DIR_TRAVERSE].speed;
697 | }
698 | stats[_STAT_DIR_TRAVERSE].starttime=time_so_far();
699 | chdir("..");
700 | stats[_STAT_DIR_TRAVERSE].endtime=time_so_far();
701 | stats[_STAT_DIR_TRAVERSE].speed=time2+stats[_STAT_DIR_TRAVERSE].endtime-stats[_STAT_DIR_TRAVERSE].starttime;
702 | if(stats[_STAT_DIR_TRAVERSE].speed < (double)0.0)
703 | stats[_STAT_DIR_TRAVERSE].speed=(double) 0.0;
704 | stats[_STAT_DIR_TRAVERSE].total_time+=stats[_STAT_DIR_TRAVERSE].speed;
705 | stats[_STAT_DIR_TRAVERSE].counter++;
706 | if(stats[_STAT_DIR_TRAVERSE].speed < stats[_STAT_DIR_TRAVERSE].best)
707 | stats[_STAT_DIR_TRAVERSE].best=stats[_STAT_DIR_TRAVERSE].speed;
708 | if(stats[_STAT_DIR_TRAVERSE].speed > stats[_STAT_DIR_TRAVERSE].worst)
709 | stats[_STAT_DIR_TRAVERSE].worst=stats[_STAT_DIR_TRAVERSE].speed;
710 | }
711 | stats[_STAT_DIR_TRAVERSE].starttime=time_so_far();
712 | chdir("..");
713 | stats[_STAT_DIR_TRAVERSE].endtime=time_so_far();
714 | stats[_STAT_DIR_TRAVERSE].speed=time1+stats[_STAT_DIR_TRAVERSE].endtime-stats[_STAT_DIR_TRAVERSE].starttime;
715 | if(stats[_STAT_DIR_TRAVERSE].speed < (double)0.0)
716 | stats[_STAT_DIR_TRAVERSE].speed=(double)0.0;
717 | stats[_STAT_DIR_TRAVERSE].total_time+=stats[_STAT_DIR_TRAVERSE].speed;
718 | stats[_STAT_DIR_TRAVERSE].counter++;
719 | if(stats[_STAT_DIR_TRAVERSE].speed < stats[_STAT_DIR_TRAVERSE].best)
720 | stats[_STAT_DIR_TRAVERSE].best=stats[_STAT_DIR_TRAVERSE].speed;
721 | if(stats[_STAT_DIR_TRAVERSE].speed > stats[_STAT_DIR_TRAVERSE].worst)
722 | stats[_STAT_DIR_TRAVERSE].worst=stats[_STAT_DIR_TRAVERSE].speed;
723 | }
724 | }
725 |
726 | void
727 | file_create(int x)
728 | {
729 | int i,j,k;
730 | int fd;
731 | int ret;
732 | char buf[100];
733 | char value;
734 | stats[_STAT_CREATE].best=(double)999999.9;
735 | stats[_STAT_CREATE].worst=(double)0.0;
736 | stats[_STAT_WRITE].best=(double)999999.9;
737 | stats[_STAT_WRITE].worst=(double)0.0;
738 | stats[_STAT_CLOSE].best=(double)999999.9;
739 | stats[_STAT_CLOSE].worst=(double)0.0;
740 | for(i=0;i stats[_STAT_CREATE].worst)
781 | stats[_STAT_CREATE].worst=stats[_STAT_CREATE].speed;
782 |
783 | stats[_STAT_WRITE].starttime=time_so_far();
784 | write(fd,mbuffer,sz);
785 | stats[_STAT_WRITE].endtime=time_so_far();
786 | stats[_STAT_WRITE].counter++;
787 | stats[_STAT_WRITE].speed=stats[_STAT_WRITE].endtime-stats[_STAT_WRITE].starttime;
788 | if(stats[_STAT_WRITE].speed < (double)0.0)
789 | stats[_STAT_WRITE].speed=(double)0.0;
790 | stats[_STAT_WRITE].total_time+=stats[_STAT_WRITE].speed;
791 | if(stats[_STAT_WRITE].speed < stats[_STAT_WRITE].best)
792 | stats[_STAT_WRITE].best=stats[_STAT_WRITE].speed;
793 | if(stats[_STAT_WRITE].speed > stats[_STAT_WRITE].worst)
794 | stats[_STAT_WRITE].worst=stats[_STAT_WRITE].speed;
795 |
796 | fsync(fd);
797 | stats[_STAT_CLOSE].starttime=time_so_far();
798 | close(fd);
799 | stats[_STAT_CLOSE].endtime=time_so_far();
800 | stats[_STAT_CLOSE].speed=stats[_STAT_CLOSE].endtime-stats[_STAT_CLOSE].starttime;
801 | if(stats[_STAT_CLOSE].speed < (double)0.0)
802 | stats[_STAT_CLOSE].speed=(double)0.0;
803 | stats[_STAT_CLOSE].total_time+=stats[_STAT_CLOSE].speed;
804 | stats[_STAT_CLOSE].counter++;
805 | if(stats[_STAT_CLOSE].speed < stats[_STAT_CLOSE].best)
806 | stats[_STAT_CLOSE].best=stats[_STAT_CLOSE].speed;
807 | if(stats[_STAT_CLOSE].speed > stats[_STAT_CLOSE].worst)
808 | stats[_STAT_CLOSE].worst=stats[_STAT_CLOSE].speed;
809 | }
810 | chdir("..");
811 | }
812 | chdir("..");
813 | }
814 | }
815 |
816 | void
817 | file_stat(int x)
818 | {
819 | int i,j,k,y;
820 | char buf[100];
821 | struct stat mystat;
822 | stats[_STAT_STAT].best=(double)99999.9;
823 | stats[_STAT_STAT].worst=(double)0.00000000;
824 | for(i=0;i stats[_STAT_STAT].worst)
851 | stats[_STAT_STAT].worst=stats[_STAT_STAT].speed;
852 | }
853 | chdir("..");
854 | }
855 | chdir("..");
856 | }
857 | }
858 |
859 | void
860 | file_access(int x)
861 | {
862 | int i,j,k,y;
863 | char buf[100];
864 | stats[_STAT_ACCESS].best=(double)999999.9;
865 | stats[_STAT_ACCESS].worst=(double)0.0;
866 | for(i=0;i stats[_STAT_ACCESS].worst)
894 | stats[_STAT_ACCESS].worst=stats[_STAT_ACCESS].speed;
895 | }
896 | chdir("..");
897 | }
898 | chdir("..");
899 | }
900 | }
901 |
902 | void
903 | file_chmod(int x)
904 | {
905 | int i,j,k,y;
906 | char buf[100];
907 | stats[_STAT_CHMOD].best=(double)999999.9;
908 | stats[_STAT_CHMOD].worst=(double)0.0;
909 | for(i=0;i stats[_STAT_CHMOD].worst)
937 | stats[_STAT_CHMOD].worst=stats[_STAT_CHMOD].speed;
938 | }
939 | chdir("..");
940 | }
941 | chdir("..");
942 | }
943 | }
944 |
945 | void
946 | file_readdir(int x)
947 | {
948 | int i,j,ret1;
949 | char buf[100];
950 | DIR *dirbuf;
951 | struct dirent *y;
952 | stats[_STAT_READDIR].best=(double)999999.9;
953 | stats[_STAT_READDIR].worst=(double)0.0;
954 | for(i=0;i stats[_STAT_READDIR].worst)
984 | stats[_STAT_READDIR].worst=stats[_STAT_READDIR].speed;
985 | ret1=closedir(dirbuf);
986 | if(ret1 < 0)
987 | {
988 | printf("closedir failed\n");
989 | exit(1);
990 | }
991 | chdir("..");
992 | }
993 | chdir("..");
994 | }
995 | }
996 |
997 | void
998 | file_link(int x)
999 | {
1000 | int i,j,k,y;
1001 | char buf[100];
1002 | char bufn[100];
1003 | stats[_STAT_LINK].best=(double)999999.9;
1004 | stats[_STAT_LINK].worst=(double)0.0;
1005 | for(i=0;i stats[_STAT_LINK].worst)
1033 | stats[_STAT_LINK].worst=stats[_STAT_LINK].speed;
1034 | }
1035 | chdir("..");
1036 | }
1037 | chdir("..");
1038 | }
1039 | }
1040 |
1041 | void
1042 | file_unlink(int x)
1043 | {
1044 | int i,j,k,y;
1045 | char buf[100];
1046 | char bufn[100];
1047 | stats[_STAT_UNLINK].best=(double)999999.9;
1048 | stats[_STAT_UNLINK].worst=(double)0.0;
1049 | for(i=0;i stats[_STAT_UNLINK].worst)
1077 | stats[_STAT_UNLINK].worst=stats[_STAT_UNLINK].speed;
1078 | }
1079 | chdir("..");
1080 | }
1081 | chdir("..");
1082 | }
1083 | }
1084 |
1085 | void
1086 | dir_delete(int x)
1087 | {
1088 | int i,j,k;
1089 | char buf[100];
1090 | stats[_STAT_DIR_DELETE].best=(double)99999.9;
1091 | stats[_STAT_DIR_DELETE].worst=(double)0.00000000;
1092 | for(i=0;i stats[_STAT_DIR_DELETE].worst)
1116 | stats[_STAT_DIR_DELETE].worst=stats[_STAT_DIR_DELETE].speed;
1117 | }
1118 | chdir("..");
1119 | sprintf(buf,"fileop_L1_%d_L2_%d",i,j);
1120 | stats[_STAT_DIR_DELETE].starttime=time_so_far();
1121 | rmdir(buf);
1122 | stats[_STAT_DIR_DELETE].endtime=time_so_far();
1123 | stats[_STAT_DIR_DELETE].speed=stats[_STAT_DIR_DELETE].endtime-stats[_STAT_DIR_DELETE].starttime;
1124 | if(stats[_STAT_DIR_DELETE].speed < (double)0.0)
1125 | stats[_STAT_DIR_DELETE].speed=(double)0.0;
1126 | stats[_STAT_DIR_DELETE].total_time+=stats[_STAT_DIR_DELETE].speed;
1127 | stats[_STAT_DIR_DELETE].counter++;
1128 | if(stats[_STAT_DIR_DELETE].speed < stats[_STAT_DIR_DELETE].best)
1129 | stats[_STAT_DIR_DELETE].best=stats[_STAT_DIR_DELETE].speed;
1130 | if(stats[_STAT_DIR_DELETE].speed > stats[_STAT_DIR_DELETE].worst)
1131 | stats[_STAT_DIR_DELETE].worst=stats[_STAT_DIR_DELETE].speed;
1132 | }
1133 | chdir("..");
1134 | sprintf(buf,"fileop_L1_%d",i);
1135 | stats[_STAT_DIR_DELETE].starttime=time_so_far();
1136 | rmdir(buf);
1137 | stats[_STAT_DIR_DELETE].endtime=time_so_far();
1138 | stats[_STAT_DIR_DELETE].speed=stats[_STAT_DIR_DELETE].endtime-stats[_STAT_DIR_DELETE].starttime;
1139 | if(stats[_STAT_DIR_DELETE].speed < (double)0.0)
1140 | stats[_STAT_DIR_DELETE].speed=(double)0.0;
1141 | stats[_STAT_DIR_DELETE].total_time+=stats[_STAT_DIR_DELETE].speed;
1142 | stats[_STAT_DIR_DELETE].counter++;
1143 | if(stats[_STAT_DIR_DELETE].speed < stats[_STAT_DIR_DELETE].best)
1144 | stats[_STAT_DIR_DELETE].best=stats[_STAT_DIR_DELETE].speed;
1145 | if(stats[_STAT_DIR_DELETE].speed > stats[_STAT_DIR_DELETE].worst)
1146 | stats[_STAT_DIR_DELETE].worst=stats[_STAT_DIR_DELETE].speed;
1147 | }
1148 | }
1149 |
1150 | void
1151 | file_delete(int x)
1152 | {
1153 | int i,j,k;
1154 | char buf[100];
1155 | stats[_STAT_DELETE].best=(double)999999.9;
1156 | stats[_STAT_DELETE].worst=(double)0.0;
1157 | for(i=0;i stats[_STAT_DELETE].worst)
1179 | stats[_STAT_DELETE].worst=stats[_STAT_DELETE].speed;
1180 | }
1181 | chdir("..");
1182 | sprintf(buf,"fileop_L1_%d_L2_%d",i,j);
1183 | rmdir(buf);
1184 | }
1185 | chdir("..");
1186 | sprintf(buf,"fileop_L1_%d",i);
1187 | rmdir(buf);
1188 | }
1189 | }
1190 | void
1191 | file_read(int x)
1192 | {
1193 | int i,j,k,y,fd;
1194 | char buf[100];
1195 | char value;
1196 | stats[_STAT_READ].best=(double)99999.9;
1197 | stats[_STAT_READ].worst=(double)0.00000000;
1198 | stats[_STAT_OPEN].best=(double)99999.9;
1199 | stats[_STAT_OPEN].worst=(double)0.00000000;
1200 | for(i=0;i stats[_STAT_OPEN].worst)
1228 | stats[_STAT_OPEN].worst=stats[_STAT_OPEN].speed;
1229 |
1230 | stats[_STAT_READ].starttime=time_so_far();
1231 | y=read(fd,mbuffer,sz);
1232 | if(y < 0)
1233 | {
1234 | printf("Read failed\n");
1235 | exit(1);
1236 | }
1237 | if(validate(mbuffer,sz, value) !=0)
1238 | printf("Error: Data Mis-compare\n");;
1239 | stats[_STAT_READ].endtime=time_so_far();
1240 | close(fd);
1241 | stats[_STAT_READ].speed=stats[_STAT_READ].endtime-stats[_STAT_READ].starttime;
1242 | if(stats[_STAT_READ].speed < (double)0.0)
1243 | stats[_STAT_READ].speed=(double)0.0;
1244 | stats[_STAT_READ].total_time+=stats[_STAT_READ].speed;
1245 | stats[_STAT_READ].counter++;
1246 | if(stats[_STAT_READ].speed < stats[_STAT_READ].best)
1247 | stats[_STAT_READ].best=stats[_STAT_READ].speed;
1248 | if(stats[_STAT_READ].speed > stats[_STAT_READ].worst)
1249 | stats[_STAT_READ].worst=stats[_STAT_READ].speed;
1250 | }
1251 | chdir("..");
1252 | }
1253 | chdir("..");
1254 | }
1255 | }
1256 |
1257 | /************************************************************************/
1258 | /* Time measurement routines. Thanks to Iozone :-) */
1259 | /************************************************************************/
1260 |
1261 | #ifdef HAVE_ANSIC_C
1262 | static double
1263 | time_so_far(void)
1264 | #else
1265 | static double
1266 | time_so_far()
1267 | #endif
1268 | {
1269 | #ifdef Windows
1270 | LARGE_INTEGER freq,counter;
1271 | double wintime,bigcounter;
1272 | /* For Windows the time_of_day() is useless. It increments in 55 milli second */
1273 | /* increments. By using the Win32api one can get access to the high performance */
1274 | /* measurement interfaces. With this one can get back into the 8 to 9 */
1275 | /* microsecond resolution. */
1276 | QueryPerformanceFrequency(&freq);
1277 | QueryPerformanceCounter(&counter);
1278 | bigcounter=(double)counter.HighPart *(double)0xffffffff +
1279 | (double)counter.LowPart;
1280 | wintime = (double)(bigcounter/(double)freq.LowPart);
1281 | return((double)wintime);
1282 | #else
1283 | #if defined (OSFV4) || defined(OSFV3) || defined(OSFV5)
1284 | struct timespec gp;
1285 |
1286 | if (getclock(TIMEOFDAY, (struct timespec *) &gp) == -1)
1287 | perror("getclock");
1288 | return (( (double) (gp.tv_sec)) +
1289 | ( ((float)(gp.tv_nsec)) * 0.000000001 ));
1290 | #else
1291 | struct timeval tp;
1292 |
1293 | if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
1294 | perror("gettimeofday");
1295 | return ((double) (tp.tv_sec)) +
1296 | (((double) tp.tv_usec) * 0.000001 );
1297 | #endif
1298 | #endif
1299 | }
1300 |
1301 | void
1302 | splash(void)
1303 | {
1304 | printf("\n");
1305 | printf(" --------------------------------------\n");
1306 | printf(" | Fileop | \n");
1307 | printf(" | %s | \n",version);
1308 | printf(" | | \n");
1309 | printf(" | by |\n");
1310 | printf(" | | \n");
1311 | printf(" | Don Capps |\n");
1312 | printf(" --------------------------------------\n");
1313 | printf("\n");
1314 | }
1315 |
1316 | void
1317 | usage(void)
1318 | {
1319 | splash();
1320 | printf(" fileop [-f X ]|[-l # -u #] [-s Y] [-e] [-b] [-w] [-d ] [-t] [-v] [-h]\n");
1321 | printf("\n");
1322 | printf(" -f # Force factor. X^3 files will be created and removed.\n");
1323 | printf(" -l # Lower limit on the value of the Force factor.\n");
1324 | printf(" -u # Upper limit on the value of the Force factor.\n");
1325 | printf(" -s # Optional. Sets filesize for the create/write. May use suffix 'K' or 'M'.\n");
1326 | printf(" -e Excel importable format.\n");
1327 | printf(" -b Output best case results.\n");
1328 | printf(" -w Output worst case results.\n");
1329 | printf(" -d Specify starting directory.\n");
1330 | printf(" -U Mount point to remount between tests.\n");
1331 | printf(" -t Verbose output option.\n");
1332 | printf(" -v Version information.\n");
1333 | printf(" -h Help text.\n");
1334 | printf("\n");
1335 | printf(" The structure of the file tree is:\n");
1336 | printf(" X number of Level 1 directories, with X number of\n");
1337 | printf(" level 2 directories, with X number of files in each\n");
1338 | printf(" of the level 2 directories.\n");
1339 | printf("\n");
1340 | printf(" Example: fileop 2\n");
1341 | printf("\n");
1342 | printf(" dir_1 dir_2\n");
1343 | printf(" / \\ / \\ \n");
1344 | printf(" sdir_1 sdir_2 sdir_1 sdir_2\n");
1345 | printf(" / \\ / \\ / \\ / \\ \n");
1346 | printf(" file_1 file_2 file_1 file_2 file_1 file_2 file_1 file_2\n");
1347 | printf("\n");
1348 | printf(" Each file will be created, and then Y bytes is written to the file.\n");
1349 | printf("\n");
1350 | }
1351 | void
1352 | clear_stats()
1353 | {
1354 | int i;
1355 | for(i=0;i<_NUM_STATS;i++)
1356 | bzero((char *)&stats[i],sizeof(struct stat_struct));
1357 | }
1358 | int
1359 | validate(char *buffer, int size, char value)
1360 | {
1361 | register int i;
1362 | register char *cp;
1363 | register int size1;
1364 | register char v1;
1365 | v1=value;
1366 | cp = buffer;
1367 | size1=size;
1368 | for(i=0;i " >> /dev/stderr ;
42 | echo "filename is the output of iozone -a" >> /dev/stderr ;
43 | echo "test is one of write rewrite read reread randread randwrite bkwdread recrewrite strideread fwrite frewrite fread freread" >> /dev/stderr ;;
44 | esac }
45 |
46 | #filename=$1
47 | filename=iozone_gen_out
48 | query=$2
49 | if (! [ -e $query ] ) ; then mkdir $query; fi
50 | if ( [ $# -eq 2 ] ) ;
51 | then
52 | write_gnuplot_file > $query/`basename $file_name.gnuplot`
53 | else
54 | echo "Usage : gengnuplot.sh " 2>&1
55 | echo "filename is the output of iozone -a" 2>&1
56 | echo "test is one of write rewrite read reread randread randwrite bkwdread recrewrite strideread fwrite frewrite fread freread" 2>&1
57 | fi
58 |
--------------------------------------------------------------------------------
/gnu3d.dem:
--------------------------------------------------------------------------------
1 | #
2 | # $Id: 3D plot of performance
3 | #
4 | # Processes files that were created by Generate_Graphs
5 | # and displays the results. Also, saves a postscript copy.
6 | #
7 | # Don Capps
8 |
9 | set terminal x11
10 | set title "Iozone performance"
11 | set grid lt 2 lw 1
12 | set surface
13 | set parametric
14 | set xtics
15 | set ytics
16 | set logscale x 2
17 | set logscale y 2
18 | set autoscale z
19 | set xrange [2.**5:2.**24]
20 | set xlabel "File size in 2^n KBytes"
21 | set ylabel "Record size in 2^n Kbytes"
22 | set zlabel "Kbytes/sec"
23 | set data style lines
24 | set dgrid3d 80,80,3
25 | splot 'write/iozone_gen_out.gnuplot' title "Write performance"
26 | pause -1 "Hit return to continue"
27 | set terminal postscript color
28 | set output "write/write.ps"
29 | splot 'write/iozone_gen_out.gnuplot' title "Write performance"
30 |
31 | set terminal x11
32 | set title "Iozone performance"
33 | set grid lt 2 lw 1
34 | set surface
35 | set xtics
36 | set ytics
37 | set logscale x 2
38 | set logscale y 2
39 | set autoscale z
40 | set xrange [2.**5:2.**24]
41 | set xlabel "File size in 2^n KBytes"
42 | set ylabel "Record size in 2^n Kbytes"
43 | set zlabel "Kbytes/sec"
44 | set data style lines
45 | set dgrid3d 80,80,3
46 | splot 'rewrite/iozone_gen_out.gnuplot' using 1:2:3 title "ReWrite performance" with lines
47 | pause -1 "Hit return to continue"
48 | set terminal postscript color
49 | set output "rewrite/rewrite.ps"
50 | splot 'rewrite/iozone_gen_out.gnuplot' using 1:2:3 title "ReWrite performance" with lines
51 |
52 | set terminal x11
53 | set title "Iozone performance"
54 | set grid lt 2 lw 1
55 | set surface
56 | set xtics
57 | set ytics
58 | set logscale x 2
59 | set logscale y 2
60 | set autoscale z
61 | set xrange [2.**5:2.**24]
62 | set xlabel "File size in 2^n KBytes"
63 | set ylabel "Record size in 2^n Kbytes"
64 | set zlabel "Kbytes/sec"
65 | set data style lines
66 | set dgrid3d 80,80,3
67 | splot 'read/iozone_gen_out.gnuplot' using 1:2:3 title "Read performance" with lines
68 | pause -1 "Hit return to continue"
69 | set terminal postscript color
70 | set output "read/read.ps"
71 | splot 'read/iozone_gen_out.gnuplot' using 1:2:3 title "Read performance" with lines
72 |
73 |
74 | set terminal x11
75 | set title "Iozone performance"
76 | set grid lt 2 lw 1
77 | set surface
78 | set xtics
79 | set ytics
80 | set logscale x 2
81 | set logscale y 2
82 | set autoscale z
83 | set xrange [2.**5:2.**24]
84 | set xlabel "File size in 2^n KBytes"
85 | set ylabel "Record size in 2^n Kbytes"
86 | set zlabel "Kbytes/sec"
87 | set data style lines
88 | set dgrid3d 80,80,3
89 | splot 'reread/iozone_gen_out.gnuplot' using 1:2:3 title "Reread performance" with lines
90 | pause -1 "Hit return to continue"
91 | set terminal postscript color
92 | set output "reread/reread.ps"
93 | splot 'reread/iozone_gen_out.gnuplot' using 1:2:3 title "Reread performance" with lines
94 |
95 | set terminal x11
96 | set title "Iozone performance"
97 | set grid lt 2 lw 1
98 | set surface
99 | set xtics
100 | set ytics
101 | set logscale x 2
102 | set logscale y 2
103 | set autoscale z
104 | set xrange [2.**5:2.**24]
105 | set xlabel "File size in 2^n KBytes"
106 | set ylabel "Record size in 2^n Kbytes"
107 | set zlabel "Kbytes/sec"
108 | set data style lines
109 | set dgrid3d 80,80,3
110 | splot 'randread/iozone_gen_out.gnuplot' using 1:2:3 title "Random read performance" with lines
111 | pause -1 "Hit return to continue"
112 | set terminal postscript color
113 | set output "randread/randread.ps"
114 | splot 'randread/iozone_gen_out.gnuplot' using 1:2:3 title "Random read performance" with lines
115 |
116 | set terminal x11
117 | set title "Iozone performance"
118 | set grid lt 2 lw 1
119 | set surface
120 | set xtics
121 | set ytics
122 | set logscale x 2
123 | set logscale y 2
124 | set autoscale z
125 | set xrange [2.**5:2.**24]
126 | set xlabel "File size in 2^n KBytes"
127 | set ylabel "Record size in 2^n Kbytes"
128 | set zlabel "Kbytes/sec"
129 | set data style lines
130 | set dgrid3d 80,80,3
131 | splot 'randwrite/iozone_gen_out.gnuplot' using 1:2:3 title "Random write performance" with lines
132 | pause -1 "Hit return to continue"
133 | set terminal postscript color
134 | set output "randwrite/randwrite.ps"
135 | splot 'randwrite/iozone_gen_out.gnuplot' using 1:2:3 title "Random write performance" with lines
136 |
137 | set terminal x11
138 | set title "Iozone performance"
139 | set grid lt 2 lw 1
140 | set surface
141 | set xtics
142 | set ytics
143 | set logscale x 2
144 | set logscale y 2
145 | set autoscale z
146 | set xrange [2.**5:2.**24]
147 | set xlabel "File size in 2^n KBytes"
148 | set ylabel "Record size in 2^n Kbytes"
149 | set zlabel "Kbytes/sec"
150 | set data style lines
151 | set dgrid3d 80,80,3
152 | splot 'bkwdread/iozone_gen_out.gnuplot' using 1:2:3 title "Read Backwards performance" with lines
153 | pause -1 "Hit return to continue"
154 | set terminal postscript color
155 | set output "bkwdread/bkwdread.ps"
156 | splot 'bkwdread/iozone_gen_out.gnuplot' using 1:2:3 title "Read Backwards performance" with lines
157 |
158 | set terminal x11
159 | set title "Iozone performance"
160 | set grid lt 2 lw 1
161 | set surface
162 | set xtics
163 | set ytics
164 | set logscale x 2
165 | set logscale y 2
166 | set autoscale z
167 | set xrange [2.**5:2.**24]
168 | set xlabel "File size in 2^n KBytes"
169 | set ylabel "Record size in 2^n Kbytes"
170 | set zlabel "Kbytes/sec"
171 | set data style lines
172 | set dgrid3d 80,80,3
173 | splot 'recrewrite/iozone_gen_out.gnuplot' using 1:2:3 title "Record rewrite performance" with lines
174 | pause -1 "Hit return to continue"
175 | set terminal postscript color
176 | set output "recrewrite/recrewrite.ps"
177 | splot 'recrewrite/iozone_gen_out.gnuplot' using 1:2:3 title "Record rewrite performance" with lines
178 |
179 | set terminal x11
180 | set title "Iozone performance"
181 | set grid lt 2 lw 1
182 | set surface
183 | set xtics
184 | set ytics
185 | set logscale x 2
186 | set logscale y 2
187 | set autoscale z
188 | set xrange [2.**5:2.**24]
189 | set xlabel "File size in 2^n KBytes"
190 | set ylabel "Record size in 2^n Kbytes"
191 | set zlabel "Kbytes/sec"
192 | set data style lines
193 | set dgrid3d 80,80,3
194 | splot 'strideread/iozone_gen_out.gnuplot' using 1:2:3 title "Stride read performance" with lines
195 | pause -1 "Hit return to continue"
196 | set terminal postscript color
197 | set output "strideread/strideread.ps"
198 | splot 'strideread/iozone_gen_out.gnuplot' using 1:2:3 title "Stride read performance" with lines
199 |
200 | set terminal x11
201 | set title "Iozone performance"
202 | set grid lt 2 lw 1
203 | set surface
204 | set xtics
205 | set ytics
206 | set logscale x 2
207 | set logscale y 2
208 | set autoscale z
209 | set xrange [2.**5:2.**24]
210 | set xlabel "File size in 2^n KBytes"
211 | set ylabel "Record size in 2^n Kbytes"
212 | set zlabel "Kbytes/sec"
213 | set data style lines
214 | set dgrid3d 80,80,3
215 | splot 'fwrite/iozone_gen_out.gnuplot' using 1:2:3 title "Fwrite performance" with lines
216 | pause -1 "Hit return to continue"
217 | set terminal postscript color
218 | set output "fwrite/fwrite.ps"
219 | splot 'fwrite/iozone_gen_out.gnuplot' using 1:2:3 title "Fwrite performance" with lines
220 |
221 | set terminal x11
222 | set title "Iozone performance"
223 | set grid lt 2 lw 1
224 | set surface
225 | set xtics
226 | set ytics
227 | set logscale x 2
228 | set logscale y 2
229 | set autoscale z
230 | set xrange [2.**5:2.**24]
231 | set xlabel "File size in 2^n KBytes"
232 | set ylabel "Record size in 2^n Kbytes"
233 | set zlabel "Kbytes/sec"
234 | set data style lines
235 | set dgrid3d 80,80,3
236 | splot 'frewrite/iozone_gen_out.gnuplot' using 1:2:3 title "Frewrite performance" with lines
237 | pause -1 "Hit return to continue"
238 | set terminal postscript color
239 | set output "frewrite/frewrite.ps"
240 | splot 'frewrite/iozone_gen_out.gnuplot' using 1:2:3 title "Frewrite performance" with lines
241 |
242 | set terminal x11
243 | set title "Iozone performance"
244 | set grid lt 2 lw 1
245 | set surface
246 | set xtics
247 | set ytics
248 | set logscale x 2
249 | set logscale y 2
250 | set autoscale z
251 | set xrange [2.**5:2.**24]
252 | set xlabel "File size in 2^n KBytes"
253 | set ylabel "Record size in 2^n Kbytes"
254 | set zlabel "Kbytes/sec"
255 | set data style lines
256 | set dgrid3d 80,80,3
257 | splot 'fread/iozone_gen_out.gnuplot' using 1:2:3 title "Fread performance" with lines
258 | pause -1 "Hit return to continue"
259 | set terminal postscript color
260 | set output "fread/fread.ps"
261 | splot 'fread/iozone_gen_out.gnuplot' using 1:2:3 title "Fread performance" with lines
262 |
263 | set terminal x11
264 | set title "Iozone performance"
265 | set grid lt 2 lw 1
266 | set surface
267 | set xtics
268 | set ytics
269 | set logscale x 2
270 | set logscale y 2
271 | set autoscale z
272 | set xrange [2.**5:2.**24]
273 | set xlabel "File size in 2^n KBytes"
274 | set ylabel "Record size in 2^n Kbytes"
275 | set zlabel "Kbytes/sec"
276 | set data style lines
277 | set dgrid3d 80,80,3
278 | splot 'freread/iozone_gen_out.gnuplot' using 1:2:3 title "Freread performance" with lines
279 | pause -1 "Hit return to exit"
280 | set terminal postscript color
281 | set output "freread/freread.ps"
282 | splot 'freread/iozone_gen_out.gnuplot' using 1:2:3 title "Freread performance" with lines
283 |
--------------------------------------------------------------------------------
/gnuplot.dem:
--------------------------------------------------------------------------------
1 | #
2 | # $Id: Plot of latency versus offset in a file
3 | #
4 | # Requires data file "wol.dat" from this directory,
5 | # so change current working directory to this directory before running.
6 | #
7 |
8 | set title "File system write latency "
9 | set autoscale x
10 | set xtics
11 | set xlabel "Offset in file (KB)"
12 | set ylabel "Latency in Microseconds"
13 | plot 'wol.dat' using 1:2 title "Latency Plot" with lines
14 | pause -1 "Hit return to continue"
15 |
16 | #
17 | # $Id: Plot of latency versus offset in a file
18 | #
19 | # Requires data file "rwol.dat" from this directory,
20 | # so change current working directory to this directory before running.
21 | #
22 |
23 | set title "File system re-write latency "
24 | set autoscale x
25 | set xtics
26 | set xlabel "Offset in file (KB)"
27 | set ylabel "Latency in Microseconds"
28 | plot 'rwol.dat' using 1:2 title "Latency Plot" with lines
29 | pause -1 "Hit return to continue"
30 |
31 | #
32 | # $Id: Plot of latency versus offset in a file
33 | #
34 | # Requires data file "rol.dat" from this directory,
35 | # so change current working directory to this directory before running.
36 | #
37 |
38 | set title "File system read latency "
39 | set autoscale x
40 | set xtics
41 | set xlabel "Offset in file (KB)"
42 | set ylabel "Latency in Microseconds"
43 | plot 'rol.dat' using 1:2 title "Latency Plot" with lines
44 | pause -1 "Hit return to continue"
45 |
46 | #
47 | # $Id: Plot of latency versus offset in a file
48 | #
49 | # Requires data file "rrol.dat" from this directory,
50 | # so change current working directory to this directory before running.
51 | #
52 |
53 | set title "File system re-read latency "
54 | set autoscale x
55 | set xtics
56 | set xlabel "Offset in file (KB)"
57 | set ylabel "Latency in Microseconds"
58 | plot 'rrol.dat' using 1:2 title "Latency Plot" with lines
59 | pause -1 "Hit return to continue"
60 |
61 |
--------------------------------------------------------------------------------
/gnuplotps.dem:
--------------------------------------------------------------------------------
1 | #
2 | # $Id: Plot of latency versus offset in a file
3 | #
4 | # Requires data file "wol.dat" from this directory,
5 | # so change current working directory to this directory before running.
6 | #
7 |
8 | set title "File system write latency "
9 | set terminal postscript
10 | set output "gnu_wol.ps"
11 | set autoscale x
12 | set xtics
13 | set xlabel "Offset in file (KB)"
14 | set ylabel "Latency in Microseconds"
15 | plot 'wol.dat' using 1:2 title "Latency Plot" with lines
16 | #
17 | # $Id: Plot of latency versus offset in a file
18 | #
19 | # Requires data file "rwol.dat" from this directory,
20 | # so change current working directory to this directory before running.
21 | #
22 |
23 | set title "File system re-write latency "
24 | set terminal postscript
25 | set output "gnu_rwol.ps"
26 | set autoscale x
27 | set xtics
28 | set xlabel "Offset in file (KB)"
29 | set ylabel "Latency in Microseconds"
30 | plot 'rwol.dat' using 1:2 title "Latency Plot" with lines
31 |
32 | #
33 | # $Id: Plot of latency versus offset in a file
34 | #
35 | # Requires data file "rol.dat" from this directory,
36 | # so change current working directory to this directory before running.
37 | #
38 |
39 | set title "File system read latency "
40 | set autoscale x
41 | set xtics
42 | set xlabel "Offset in file (KB)"
43 | set ylabel "Latency in Microseconds"
44 | set terminal postscript
45 | set output "gnu_rol.ps"
46 | plot 'rol.dat' using 1:2 title "Latency Plot" with lines
47 |
48 | #
49 | # $Id: Plot of latency versus offset in a file
50 | #
51 | # Requires data file "rrol.dat" from this directory,
52 | # so change current working directory to this directory before running.
53 | #
54 |
55 | set title "File system re-read latency "
56 | set terminal postscript
57 | set output "gnu_rrol.ps"
58 | set autoscale x
59 | set xtics
60 | set xlabel "Offset in file (KB)"
61 | set ylabel "Latency in Microseconds"
62 | plot 'rrol.dat' using 1:2 title "Latency Plot" with lines
63 |
64 |
--------------------------------------------------------------------------------
/iozone_visualizer.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use warnings;
4 | use strict;
5 |
6 | # arguments: one of more report files
7 | #
8 | # Christian Mautner , 2005-10-31
9 | # Marc Schoechlin , 2007-12-02
10 | #
11 | # This script is just a hack :-)
12 | #
13 | # This script is based loosely on the Generate_Graph set
14 | # of scripts that come with iozone, but is a complete re-write
15 | #
16 | # The main reason to write this was the need to compare the behaviour of
17 | # two or more different setups, for tuning filesystems or
18 | # comparing different pieces of hardware.
19 | #
20 | # This script is in the public domain, too short and too trivial
21 | # to deserve a copyright.
22 | #
23 | # Simply run iozone like, for example, ./iozone -a -g 4G > config1.out (if your machine has 4GB)
24 | #
25 | # and then run perl report.pl config1.out
26 | # or get another report from another box into config2.out and run
27 | # perl report.pl config1.out config2.out
28 | # the look in the report_* directory for .png
29 | #
30 | # If you don't like png or the graphic size, search for "set terminal" in this file and put whatever gnuplot
31 | # terminal you want. Note I've also noticed that gnuplot switched the set terminal png syntax
32 | # a while back, you might need "set terminal png small size 900,700"
33 | #
34 | use Getopt::Long;
35 |
36 | my $column;
37 | my %columns;
38 | my $datafile;
39 | my @datafiles;
40 | my $outdir;
41 | my $report;
42 | my $nooffset=0;
43 | my @Reports;
44 | my @split;
45 | my $size3d; my $size2d;
46 |
47 | # evaluate options
48 | GetOptions(
49 | '3d=s' => \$size3d,
50 | '2d=s' => \$size2d,
51 | 'nooffset' => \$nooffset
52 | );
53 |
54 | $size3d = "900,700" unless defined $size3d;
55 | $size2d = "800,500" unless defined $size2d;
56 |
57 |
58 | my $xoffset = "offset -7";
59 | my $yoffset = "offset -3";
60 |
61 | if ($nooffset == 1){
62 | $xoffset = ""; $yoffset = "";
63 | }
64 |
65 | print "\niozone_visualizer.pl : this script is distributed as public domain\n";
66 | print "Christian Mautner , 2005-10-31\n";
67 | print "Marc Schoechlin , 2007-12-02\n";
68 |
69 |
70 | @Reports=@ARGV;
71 |
72 | die "usage: $0 --3d=x,y -2d=x,y [...]\n" if not @Reports or grep (m|^-|, @Reports);
73 |
74 | die "report files must be in current directory" if grep (m|/|, @Reports);
75 |
76 | print "Configured xtics-offset '$xoffset', configured ytics-offfset '$yoffset' (disable with --nooffset)\n";
77 | print "Size 3d graphs : ".$size3d." (modify with '--3d=x,y')\n";
78 | print "Size 2d graphs : ".$size2d." (modify with '--2d=x,y')\n";
79 |
80 | #KB reclen write rewrite read reread read write read rewrite read fwrite frewrite fread freread
81 | %columns=(
82 | 'KB' =>1,
83 | 'reclen' =>2,
84 | 'write' =>3,
85 | 'rewrite' =>4,
86 | 'read' =>5,
87 | 'reread' =>6,
88 | 'randread' =>7,
89 | 'randwrite' =>8,
90 | 'bkwdread' =>9,
91 | 'recrewrite'=>10,
92 | 'strideread'=>11,
93 | 'fwrite' =>12,
94 | 'frewrite' =>13,
95 | 'fread' =>14,
96 | 'freread' =>15,
97 | );
98 |
99 | #
100 | # create output directory. the name is the concatenation
101 | # of all report file names (minus the file extension, plus
102 | # prefix report_)
103 | #
104 | $outdir="report_".join("_",map{/([^\.]+)(\..*)?/ && $1}(@Reports));
105 |
106 | print STDERR "Output directory: $outdir ";
107 |
108 | if ( -d $outdir )
109 | {
110 | print STDERR "(removing old directory) ";
111 | system "rm -rf $outdir";
112 | }
113 |
114 | mkdir $outdir or die "cannot make directory $outdir";
115 |
116 | print STDERR "done.\nPreparing data files...";
117 |
118 | foreach $report (@Reports)
119 | {
120 | open(I, $report) or die "cannot open $report for reading";
121 | $report=~/^([^\.]+)/;
122 | $datafile="$1.dat";
123 | push @datafiles, $datafile;
124 | open(O, ">$outdir/$datafile") or die "cannot open $outdir/$datafile for writing";
125 | open(O2, ">$outdir/2d-$datafile") or die "cannot open $outdir/$datafile for writing";
126 |
127 | my @sorted = sort { $columns{$a} <=> $columns{$b} } keys %columns;
128 | print O "# ".join(" ",@sorted)."\n";
129 | print O2 "# ".join(" ",@sorted)."\n";
130 |
131 | while()
132 | {
133 | next unless ( /^[\s\d]+$/ );
134 | @split = split();
135 | next unless ( @split == 15 );
136 | print O;
137 | print O2 if $split[1] == 16384 or $split[0] == $split[1];
138 | }
139 | close(I);
140 | close(O);
141 | close(O2);
142 | }
143 |
144 | print STDERR "done.\nGenerating graphs:";
145 |
146 |
147 | open(HTML, ">$outdir/index.html") or die "cannot open $outdir/index.html for writing";
148 |
149 | print HTML qq{
150 |
151 |
152 |
153 | IOZone Statistics
154 |
157 |
158 |
159 |
160 | IOZone Statistics
161 |
162 |
163 |
164 | };
165 |
166 | # Generate Menu
167 | print HTML "## Overview\n\n";
168 | foreach $column (keys %columns){
169 | print HTML '- '.uc($column).' : '.
170 | '3d\n".
171 | '2d
\n";
172 | }
173 | print HTML " |
\n";
174 | # Genereate 3d plots
175 | foreach $column (keys %columns)
176 | {
177 | print STDERR " $column";
178 |
179 | open(G, ">$outdir/$column.do") or die "cannot open $outdir/$column.do for writing";
180 |
181 |
182 |
183 | print G qq{
184 | set title "Iozone performance: $column"
185 | set grid lt 2 lw 1
186 | set surface
187 | set parametric
188 | set xtics $xoffset
189 | set ytics $yoffset
190 | set logscale x 2
191 | set logscale y 2
192 | set autoscale z
193 | set xrange [2.**5:2.**24]
194 | set xlabel "File size in KBytes" -2
195 | set ylabel "Record size in Kbytes" 2
196 | set zlabel "Kbytes/sec" 4,8
197 | set data style lines
198 | set dgrid3d 80,80,3
199 | #set terminal png small picsize 900 700
200 | set terminal png small size $size3d nocrop
201 | set output "$column.png"
202 | };
203 |
204 | print HTML qq{
205 |
206 |
207 | 3d-$column[top]
208 | 
209 | |
210 |
211 | };
212 |
213 | print G "splot ". join(", ", map{qq{"$_" using 1:2:$columns{$column} title "$_"}}(@datafiles));
214 |
215 | print G "\n";
216 |
217 | close G;
218 |
219 | open(G, ">$outdir/2d-$column.do") or die "cannot open $outdir/$column.do for writing";
220 | print G qq{
221 | set title "Iozone performance: $column"
222 | #set terminal png small picsize 450 350
223 | set terminal png medium size $size2d nocrop
224 | set logscale x
225 | set xlabel "File size in KBytes"
226 | set ylabel "Kbytes/sec"
227 | set output "2d-$column.png"
228 | };
229 |
230 | print HTML qq{
231 |
232 |
233 | 2d-$column[top]
234 | 
235 | |
236 |
237 | };
238 |
239 |
240 |
241 | print G "plot ". join(", ", map{qq{"2d-$_" using 1:$columns{$column} title "$_" with lines}}(@datafiles));
242 |
243 | print G "\n";
244 |
245 | close G;
246 |
247 | if ( system("cd $outdir && gnuplot $column.do && gnuplot 2d-$column.do") )
248 | {
249 | print STDERR "(failed) ";
250 | }
251 | else
252 | {
253 | print STDERR "(ok) ";
254 | }
255 | }
256 |
257 | print HTML qq{
258 |
259 |
260 |
261 | };
262 | print STDERR "done.\n";
263 |
264 |
--------------------------------------------------------------------------------
/libasync.c:
--------------------------------------------------------------------------------
1 |
2 |
3 | /*
4 | * Library for Posix async read operations with hints.
5 | * Author: Don Capps
6 | * Company: Iozone
7 | * Date: 4/24/1998
8 | *
9 | * Two models are supported. First model is a replacement for read() where the async
10 | * operations are performed and the requested data is bcopy()-ed back into the users
11 | * buffer. The second model is a new version of read() where the caller does not
12 | * supply the address of the buffer but instead is returned an address to the
13 | * location of the data. The second model eliminates a bcopy from the path.
14 | *
15 | * To use model #1:
16 | * 1. Call async_init(&pointer_on_stack,fd,direct_flag);
17 | * The fd is the file descriptor for the async operations.
18 | * The direct_flag sets VX_DIRECT
19 | *
20 | * 2. Call async_read(gc, fd, ubuffer, offset, size, stride, max, depth)
21 | * Where:
22 | * gc ............ is the pointer on the stack
23 | * fd ............ is the file descriptor
24 | * ubuffer ....... is the address of the user buffer.
25 | * offset ........ is the offset in the file to begin reading
26 | * size .......... is the size of the transfer.
27 | * stride ........ is the distance, in size units, to space the async reads.
28 | * max ........... is the max size of the file to be read.
29 | * depth ......... is the number of async operations to perform.
30 | *
31 | * 3. Call end_async(gc) when finished.
32 | * Where:
33 | * gc ............ is the pointer on the stack.
34 | *
35 | * To use model #2:
36 | * 1. Call async_init(&pointer_on_stack,fd,direct_flag);
37 | * The fd is the file descriptor for the async operations.
38 | * The direct_flag sets VX_DIRECT
39 | * 2. Call async_read(gc, fd, &ubuffer, offset, size, stride, max, depth)
40 | * Where:
41 | * gc ............ is the pointer on the stack
42 | * fd ............ is the file descriptor
43 | * ubuffer ....... is the address of a pointer that will be filled in
44 | * by the async library.
45 | * offset ........ is the offset in the file to begin reading
46 | * size .......... is the size of the transfer.
47 | * stride ........ is the distance, in size units, to space the async reads.
48 | * max ........... is the max size of the file to be read.
49 | * depth ......... is the number of async operations to perform.
50 | *
51 | * 3. Call async_release(gc) when finished with the data that was returned.
52 | * This allows the async library to reuse the memory that was filled in
53 | * and returned to the user.
54 | *
55 | * 4. Call end_async(gc) when finished.
56 | * Where:
57 | * gc ............ is the pointer on the stack.
58 | *
59 | * To use model #1: (WRITES)
60 | * 1. Call async_init(&pointer_on_stack,fd,direct_flag);
61 | * The fd is the file descriptor for the async operations.
62 | *
63 | * 2. Call async_write(gc, fd, ubuffer, size, offset, depth)
64 | * Where:
65 | * gc ............ is the pointer on the stack
66 | * fd ............ is the file descriptor
67 | * ubuffer ....... is the address of the user buffer.
68 | * size .......... is the size of the transfer.
69 | * offset ........ is the offset in the file to begin reading
70 | * depth ......... is the number of async operations to perform.
71 | *
72 | * 4. Call end_async(gc) when finished.
73 | * Where:
74 | * gc ............ is the pointer on the stack.
75 | *
76 | * Notes:
77 | * The intended use is to replace calls to read() with calls to
78 | * async_read() and allow the user to make suggestions on
79 | * what kind of async read-ahead would be nice to have.
80 | * The first transfer requested is guarenteed to be complete
81 | * before returning to the caller. The async operations will
82 | * be started and will also be guarenteed to have completed
83 | * if the next call specifies its first request to be one
84 | * that was previously performed with an async operation.
85 | *
86 | * The async_read_no_copy() function allows the async operations
87 | * to return the data to the user and not have to perform
88 | * a bcopy of the data back into the user specified buffer
89 | * location. This model is faster but assumes that the user
90 | * application has been modified to work with this model.
91 | *
92 | * The async_write() is intended to enhance the performance of
93 | * initial writes to a file. This is the slowest case in the write
94 | * path as it must perform meta-data allocations and wait.
95 | */
96 |
97 | #include
98 | #include
99 | #if defined(solaris) || defined(linux) || defined(SCO_Unixware_gcc)
100 | #else
101 | #include
102 | #endif
103 | #include
104 | #include
105 | #ifndef bsd4_4
106 | #include
107 | #endif
108 | #ifdef VXFS
109 | #include
110 | #endif
111 |
112 | #if defined(OSFV5) || defined(linux)
113 | #include
114 | #endif
115 |
116 | #if defined(linux)
117 | #include
118 | #include
119 | #include
120 | #endif
121 |
122 | #if ((defined(solaris) && defined(__LP64__)) || defined(__s390x__))
123 | /* If we are building for 64-bit Solaris, all functions that return pointers
124 | * must be declared before they are used; otherwise the compiler will assume
125 | * that they return ints and the top 32 bits of the pointer will be lost,
126 | * causing segmentation faults. The following includes take care of this.
127 | * It should be safe to add these for all other OSs too, but we're only
128 | * doing it for Solaris now in case another OS turns out to be a special case.
129 | */
130 | #include
131 | #include
132 | #include /* For the BSD string functions */
133 | #endif
134 |
135 | void mbcopy(char *source, char *dest, size_t len);
136 |
137 |
138 | #if !defined(solaris) && !defined(off64_t) && !defined(_OFF64_T) && !defined(__off64_t_defined) && !defined(SCO_Unixware_gcc)
139 | typedef long long off64_t;
140 | #endif
141 | #if defined(OSFV5)
142 | #include
143 | #endif
144 |
145 |
146 | extern long long page_size;
147 | extern int one;
148 | /*
149 | * Internal cache entrys. Each entry on the global
150 | * cache, pointed to by async_init(gc) will be of
151 | * this structure type.
152 | */
153 | char version[] = "Libasync Version $Revision: 3.23 $";
154 | struct cache_ent {
155 | struct aiocb myaiocb; /* For use in small file mode */
156 | #ifdef _LARGEFILE64_SOURCE
157 | #if defined(__CrayX1__)
158 | aiocb64_t myaiocb64; /* For use in large file mode */
159 | #else
160 | struct aiocb64 myaiocb64; /* For use in large file mode */
161 | #endif
162 | #endif
163 | long long fd; /* File descriptor */
164 | long long size; /* Size of the transfer */
165 | struct cache_ent *forward; /* link to next element on cache list */
166 | struct cache_ent *back; /* link to previous element on the cache list */
167 | long long direct; /* flag to indicate if the buffer should be */
168 | /* de-allocated by library */
169 | char *real_address; /* Real address to free */
170 |
171 | volatile void *oldbuf; /* Used for firewall to prevent in flight */
172 | /* accidents */
173 | int oldfd; /* Used for firewall to prevent in flight */
174 | /* accidents */
175 | size_t oldsize; /* Used for firewall to prevent in flight */
176 | /* accidents */
177 | };
178 |
179 | /*
180 | * Head of the cache list
181 | */
182 | struct cache {
183 | struct cache_ent *head; /* Head of cache list */
184 | struct cache_ent *tail; /* tail of cache list */
185 | struct cache_ent *inuse_head; /* head of in-use list */
186 | long long count; /* How many elements on the cache list */
187 | struct cache_ent *w_head; /* Head of cache list */
188 | struct cache_ent *w_tail; /* tail of cache list */
189 | long long w_count; /* How many elements on the write list */
190 | };
191 |
192 | long long max_depth;
193 | extern int errno;
194 | struct cache_ent *alloc_cache();
195 | struct cache_ent *incache();
196 | void async_init();
197 | void end_async();
198 | int async_suspend();
199 | int async_read();
200 | void takeoff_cache();
201 | void del_cache();
202 | void async_release();
203 | void putoninuse();
204 | void takeoffinuse();
205 | struct cache_ent *allocate_write_buffer();
206 | size_t async_write();
207 | void async_wait_for_write();
208 | void async_put_on_write_queue();
209 | void async_write_finish();
210 |
211 | /* On Solaris _LP64 will be defined by if we're compiling
212 | * as a 64-bit binary. Make sure that __LP64__ gets defined in this case,
213 | * too -- it should be defined on the compiler command line, but let's
214 | * not rely on this.
215 | */
216 | #if defined(_LP64)
217 | #if !defined(__LP64__)
218 | #define __LP64__
219 | #endif
220 | #endif
221 |
222 |
223 | /***********************************************/
224 | /* Initialization routine to setup the library */
225 | /***********************************************/
226 | void
227 | async_init(gc,fd,flag)
228 | struct cache **gc;
229 | int fd;
230 | int flag;
231 | {
232 | #ifdef VXFS
233 | if(flag)
234 | ioctl(fd,VX_SETCACHE,VX_DIRECT);
235 | #endif
236 | if(*gc)
237 | {
238 | printf("Warning calling async_init two times ?\n");
239 | return;
240 | }
241 | *gc=(struct cache *)malloc((size_t)sizeof(struct cache));
242 | if(*gc == 0)
243 | {
244 | printf("Malloc failed\n");
245 | exit(174);
246 | }
247 | bzero(*gc,sizeof(struct cache));
248 | #if defined(__AIX__) || defined(SCO_Unixware_gcc)
249 | max_depth=500;
250 | #else
251 | max_depth=sysconf(_SC_AIO_MAX);
252 | #endif
253 | }
254 |
255 | /***********************************************/
256 | /* Tear down routine to shutdown the library */
257 | /***********************************************/
258 | void
259 | end_async(gc)
260 | struct cache *gc;
261 | {
262 | del_cache(gc);
263 | async_write_finish(gc);
264 | free((void *)gc);
265 | }
266 |
267 | /***********************************************/
268 | /* Wait for a request to finish */
269 | /***********************************************/
270 | int
271 | async_suspend(struct cache_ent *ce)
272 | {
273 | #ifdef _LARGEFILE64_SOURCE
274 | #ifdef __LP64__
275 | const struct aiocb * const cblist[1] = {&ce->myaiocb};
276 | #else
277 | const struct aiocb64 * const cblist[1] = {&ce->myaiocb64};
278 | #endif
279 | #else
280 | const struct aiocb * const cblist[1] = {&ce->myaiocb};
281 | #endif
282 |
283 | #ifdef _LARGEFILE64_SOURCE
284 | #ifdef __LP64__
285 | return aio_suspend(cblist, 1, NULL);
286 | #else
287 | return aio_suspend64(cblist, 1, NULL);
288 | #endif
289 | #else
290 | return aio_suspend(cblist, 1, NULL);
291 | #endif
292 | }
293 |
294 | /*************************************************************************
295 | * This routine is a generic async reader assist funtion. It takes
296 | * the same calling parameters as read() but also extends the
297 | * interface to include:
298 | * stride ..... For the async reads, what is the distance, in size units,
299 | * to space the reads. Note: Stride of 0 indicates that
300 | * you do not want any read-ahead.
301 | * max ..... What is the maximum file offset for this operation.
302 | * depth ..... How much read-ahead do you want.
303 | *
304 | * The calls to this will guarentee to complete the read() operation
305 | * before returning to the caller. The completion may occur in two
306 | * ways. First the operation may be completed by calling aio_read()
307 | * and then waiting for it to complete. Second the operation may be
308 | * completed by copying the data from a cache of previously completed
309 | * async operations.
310 | * In the event the read to be satisfied is not in the cache then a
311 | * series of async operations will be scheduled and then the first
312 | * async read will be completed. In the event that the read() can be
313 | * satisfied from the cache then the data is copied back to the
314 | * user buffer and a series of async reads will be initiated. If a
315 | * read is issued and the cache contains data and the read can not
316 | * be satisfied from the cache, then the cache is discarded, and
317 | * a new cache is constructed.
318 | * Note: All operations are aio_read(). The series will be issued
319 | * as asyncs in the order requested. After all are in flight
320 | * then the code will wait for the manditory first read.
321 | *************************************************************************/
322 |
323 | int
324 | async_read(gc, fd, ubuffer, offset, size, stride, max, depth)
325 | struct cache *gc;
326 | long long fd;
327 | char *ubuffer;
328 | off64_t offset;
329 | long long size;
330 | long long stride;
331 | off64_t max;
332 | long long depth;
333 | {
334 | off64_t a_offset,r_offset;
335 | long long a_size;
336 | struct cache_ent *ce,*first_ce=0;
337 | long long i;
338 | ssize_t retval=0;
339 | ssize_t ret;
340 | long long start = 0;
341 | long long del_read=0;
342 |
343 | a_offset=offset;
344 | a_size = size;
345 | /*
346 | * Check to see if it can be completed from the cache
347 | */
348 | if((ce=(struct cache_ent *)incache(gc,fd,offset,size)))
349 | {
350 | #ifdef _LARGEFILE64_SOURCE
351 | #ifdef __LP64__
352 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
353 | {
354 | async_suspend(ce);
355 | }
356 | #else
357 | while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)
358 | {
359 | async_suspend(ce);
360 | }
361 | #endif
362 | #else
363 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
364 | {
365 | async_suspend(ce);
366 | }
367 | #endif
368 | if(ret)
369 | {
370 | printf("aio_error 1: ret %d %d\n",ret,errno);
371 | }
372 | #ifdef _LARGEFILE64_SOURCE
373 | #ifdef __LP64__
374 | retval=aio_return(&ce->myaiocb);
375 | #else
376 | #if defined(__CrayX1__)
377 | retval=aio_return64((aiocb64_t *)&ce->myaiocb64);
378 | #else
379 | retval=aio_return64((struct aiocb64 *)&ce->myaiocb64);
380 | #endif
381 |
382 | #endif
383 | #else
384 | retval=aio_return(&ce->myaiocb);
385 | #endif
386 | if(retval > 0)
387 | {
388 | #ifdef _LARGEFILE64_SOURCE
389 | #ifdef __LP64__
390 | mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
391 | #else
392 | mbcopy((char *)ce->myaiocb64.aio_buf,(char *)ubuffer,(size_t)retval);
393 | #endif
394 | #else
395 | mbcopy((char *)ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
396 | #endif
397 | }
398 | #ifdef _LARGEFILE64_SOURCE
399 | #ifdef __LP64__
400 | if(retval < ce->myaiocb.aio_nbytes)
401 | #else
402 | if(retval < ce->myaiocb64.aio_nbytes)
403 | #endif
404 | #else
405 | if(retval < ce->myaiocb.aio_nbytes)
406 | #endif
407 | {
408 | printf("aio_return error1: ret %d %d\n",retval,errno);
409 | #ifdef _LARGEFILE64_SOURCE
410 | #ifdef __LP64__
411 | printf("aio_return error1: fd %d offset %ld buffer %lx size %d Opcode %d\n",
412 | ce->myaiocb.aio_fildes,
413 | ce->myaiocb.aio_offset,
414 | (long)(ce->myaiocb.aio_buf),
415 | ce->myaiocb.aio_nbytes,
416 | ce->myaiocb.aio_lio_opcode
417 | #else
418 | printf("aio_return error1: fd %d offset %lld buffer %lx size %d Opcode %d\n",
419 | ce->myaiocb64.aio_fildes,
420 | ce->myaiocb64.aio_offset,
421 | (long)(ce->myaiocb64.aio_buf),
422 | ce->myaiocb64.aio_nbytes,
423 | ce->myaiocb64.aio_lio_opcode
424 | #endif
425 | #else
426 | printf("aio_return error1: fd %d offset %d buffer %lx size %d Opcode %d\n",
427 | ce->myaiocb.aio_fildes,
428 | ce->myaiocb.aio_offset,
429 | (long)(ce->myaiocb.aio_buf),
430 | ce->myaiocb.aio_nbytes,
431 | ce->myaiocb.aio_lio_opcode
432 | #endif
433 | );
434 | }
435 | ce->direct=0;
436 | takeoff_cache(gc,ce);
437 | }else
438 | {
439 | /*
440 | * Clear the cache and issue the first request async()
441 | */
442 | del_cache(gc);
443 | del_read++;
444 | first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ);
445 | again:
446 | #ifdef _LARGEFILE64_SOURCE
447 | #ifdef __LP64__
448 | ret=aio_read(&first_ce->myaiocb);
449 | #else
450 | ret=aio_read64(&first_ce->myaiocb64);
451 | #endif
452 | #else
453 | ret=aio_read(&first_ce->myaiocb);
454 | #endif
455 | if(ret!=0)
456 | {
457 | if(errno==EAGAIN)
458 | goto again;
459 | else
460 | printf("error returned from aio_read(). Ret %d errno %d\n",ret,errno);
461 | }
462 | }
463 | if(stride==0) /* User does not want read-ahead */
464 | goto out;
465 | if(a_offset<0) /* Before beginning of file */
466 | goto out;
467 | if(a_offset+size>max) /* After end of file */
468 | goto out;
469 | if(depth >=(max_depth-1))
470 | depth=max_depth-1;
471 | if(depth==0)
472 | goto out;
473 | if(gc->count > 1)
474 | start=depth-1;
475 | for(i=start;i max)
481 | continue;
482 | if((ce=incache(gc,fd,r_offset,a_size)))
483 | continue;
484 | ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ);
485 | #ifdef _LARGEFILE64_SOURCE
486 | #ifdef __LP64__
487 | ret=aio_read(&ce->myaiocb);
488 | #else
489 | ret=aio_read64(&ce->myaiocb64);
490 | #endif
491 | #else
492 | ret=aio_read(&ce->myaiocb);
493 | #endif
494 | if(ret!=0)
495 | {
496 | takeoff_cache(gc,ce);
497 | break;
498 | }
499 | }
500 | out:
501 | if(del_read) /* Wait for the first read to complete */
502 | {
503 | #ifdef _LARGEFILE64_SOURCE
504 | #ifdef __LP64__
505 | while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
506 | {
507 | async_suspend(first_ce);
508 | }
509 | #else
510 | while((ret=aio_error64(&first_ce->myaiocb64))== EINPROGRESS)
511 | {
512 | async_suspend(first_ce);
513 | }
514 | #endif
515 | #else
516 | while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
517 | {
518 | async_suspend(first_ce);
519 | }
520 | #endif
521 | if(ret)
522 | printf("aio_error 2: ret %d %d\n",ret,errno);
523 | #ifdef _LARGEFILE64_SOURCE
524 | #ifdef __LP64__
525 | retval=aio_return(&first_ce->myaiocb);
526 | #else
527 | retval=aio_return64(&first_ce->myaiocb64);
528 | #endif
529 | #else
530 | retval=aio_return(&first_ce->myaiocb);
531 | #endif
532 | #ifdef _LARGEFILE64_SOURCE
533 | #ifdef __LP64__
534 | if(retval < first_ce->myaiocb.aio_nbytes)
535 | #else
536 | if(retval < first_ce->myaiocb64.aio_nbytes)
537 | #endif
538 | #else
539 | if(retval < first_ce->myaiocb.aio_nbytes)
540 | #endif
541 | {
542 | printf("aio_return error2: ret %d %d\n",retval,errno);
543 | #ifdef _LARGEFILE64_SOURCE
544 | #ifdef __LP64__
545 | printf("aio_return error2: fd %d offset %lld buffer %lx size %d Opcode %d\n",
546 | first_ce->myaiocb.aio_fildes,
547 | first_ce->myaiocb.aio_offset,
548 | (long)(first_ce->myaiocb.aio_buf),
549 | first_ce->myaiocb.aio_nbytes,
550 | first_ce->myaiocb.aio_lio_opcode
551 | #else
552 | printf("aio_return error2: fd %d offset %lld buffer %lx size %d Opcode %d\n",
553 | first_ce->myaiocb64.aio_fildes,
554 | first_ce->myaiocb64.aio_offset,
555 | (long)(first_ce->myaiocb64.aio_buf),
556 | first_ce->myaiocb64.aio_nbytes,
557 | first_ce->myaiocb64.aio_lio_opcode
558 | #endif
559 | #else
560 | printf("aio_return error2: fd %d offset %d buffer %lx size %d Opcode %d\n",
561 | first_ce->myaiocb.aio_fildes,
562 | first_ce->myaiocb.aio_offset,
563 | (long)(first_ce->myaiocb.aio_buf),
564 | first_ce->myaiocb.aio_nbytes,
565 | first_ce->myaiocb.aio_lio_opcode
566 | #endif
567 | );
568 | }
569 | if(retval > 0)
570 | {
571 | #ifdef _LARGEFILE64_SOURCE
572 | #ifdef __LP64__
573 | mbcopy((char *)first_ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
574 | #else
575 | mbcopy((char *)first_ce->myaiocb64.aio_buf,(char *)ubuffer,(size_t)retval);
576 | #endif
577 | #else
578 | mbcopy((char *)first_ce->myaiocb.aio_buf,(char *)ubuffer,(size_t)retval);
579 | #endif
580 | }
581 | first_ce->direct=0;
582 | takeoff_cache(gc,first_ce);
583 | }
584 | return((int)retval);
585 | }
586 |
587 | /************************************************************************
588 | * This routine allocates a cache_entry. It contains the
589 | * aiocb block as well as linkage for use in the cache mechanism.
590 | * The space allocated here will be released after the cache entry
591 | * has been consumed. The routine takeoff_cache() will be called
592 | * after the data has been copied to user buffer or when the
593 | * cache is purged. The routine takeoff_cache() will also release
594 | * all memory associated with this cache entry.
595 | ************************************************************************/
596 |
597 | struct cache_ent *
598 | alloc_cache(gc,fd,offset,size,op)
599 | struct cache *gc;
600 | long long fd,size,op;
601 | off64_t offset;
602 | {
603 | struct cache_ent *ce;
604 | long temp;
605 | ce=(struct cache_ent *)malloc((size_t)sizeof(struct cache_ent));
606 | if(ce == (struct cache_ent *)0)
607 | {
608 | printf("Malloc failed\n");
609 | exit(175);
610 | }
611 | bzero(ce,sizeof(struct cache_ent));
612 | #ifdef _LARGEFILE64_SOURCE
613 | #ifdef __LP64__
614 | ce->myaiocb.aio_fildes=(int)fd;
615 | ce->myaiocb.aio_offset=(off64_t)offset;
616 | ce->real_address = (char *)malloc((size_t)(size+page_size));
617 | temp=(long)ce->real_address;
618 | temp = (temp+page_size) & ~(page_size-1);
619 | ce->myaiocb.aio_buf=(volatile void *)temp;
620 | if(ce->myaiocb.aio_buf == 0)
621 | #else
622 | ce->myaiocb64.aio_fildes=(int)fd;
623 | ce->myaiocb64.aio_offset=(off64_t)offset;
624 | ce->real_address = (char *)malloc((size_t)(size+page_size));
625 | temp=(long)ce->real_address;
626 | temp = (temp+page_size) & ~(page_size-1);
627 | ce->myaiocb64.aio_buf=(volatile void *)temp;
628 | if(ce->myaiocb64.aio_buf == 0)
629 | #endif
630 | #else
631 | ce->myaiocb.aio_fildes=(int)fd;
632 | ce->myaiocb.aio_offset=(off_t)offset;
633 | ce->real_address = (char *)malloc((size_t)(size+page_size));
634 | temp=(long)ce->real_address;
635 | temp = (temp+page_size) & ~(page_size-1);
636 | ce->myaiocb.aio_buf=(volatile void *)temp;
637 | if(ce->myaiocb.aio_buf == 0)
638 | #endif
639 | {
640 | printf("Malloc failed\n");
641 | exit(176);
642 | }
643 | /*bzero(ce->myaiocb.aio_buf,(size_t)size);*/
644 | #ifdef _LARGEFILE64_SOURCE
645 | #ifdef __LP64__
646 | ce->myaiocb.aio_reqprio=0;
647 | ce->myaiocb.aio_nbytes=(size_t)size;
648 | ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
649 | ce->myaiocb.aio_lio_opcode=(int)op;
650 | #else
651 | ce->myaiocb64.aio_reqprio=0;
652 | ce->myaiocb64.aio_nbytes=(size_t)size;
653 | ce->myaiocb64.aio_sigevent.sigev_notify=SIGEV_NONE;
654 | ce->myaiocb64.aio_lio_opcode=(int)op;
655 | #endif
656 | #else
657 | ce->myaiocb.aio_reqprio=0;
658 | ce->myaiocb.aio_nbytes=(size_t)size;
659 | ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
660 | ce->myaiocb.aio_lio_opcode=(int)op;
661 | #endif
662 | ce->fd=(int)fd;
663 | ce->forward=0;
664 | ce->back=gc->tail;
665 | if(gc->tail)
666 | gc->tail->forward = ce;
667 | gc->tail= ce;
668 | if(!gc->head)
669 | gc->head=ce;
670 | gc->count++;
671 | return(ce);
672 | }
673 |
674 | /************************************************************************
675 | * This routine checks to see if the requested data is in the
676 | * cache.
677 | *************************************************************************/
678 | struct cache_ent *
679 | incache(gc,fd,offset,size)
680 | struct cache *gc;
681 | long long fd,size;
682 | off64_t offset;
683 | {
684 | struct cache_ent *move;
685 | if(gc->head==0)
686 | {
687 | return(0);
688 | }
689 | move=gc->head;
690 | #ifdef _LARGEFILE64_SOURCE
691 | #ifdef __LP64__
692 | while(move)
693 | {
694 | if((move->fd == fd) && (move->myaiocb.aio_offset==(off64_t)offset) &&
695 | ((size_t)size==move->myaiocb.aio_nbytes))
696 | {
697 | return(move);
698 | }
699 | move=move->forward;
700 | }
701 | #else
702 | while(move)
703 | {
704 | if((move->fd == fd) && (move->myaiocb64.aio_offset==(off64_t)offset) &&
705 | ((size_t)size==move->myaiocb64.aio_nbytes))
706 | {
707 | return(move);
708 | }
709 | move=move->forward;
710 | }
711 | #endif
712 | #else
713 | while(move)
714 | {
715 | if((move->fd == fd) && (move->myaiocb.aio_offset==(off_t)offset) &&
716 | ((size_t)size==move->myaiocb.aio_nbytes))
717 | {
718 | return(move);
719 | }
720 | move=move->forward;
721 | }
722 | #endif
723 | return(0);
724 | }
725 |
726 | /************************************************************************
727 | * This routine removes a specific cache entry from the cache, and
728 | * releases all memory associated witht the cache entry (if not direct).
729 | *************************************************************************/
730 |
731 | void
732 | takeoff_cache(gc,ce)
733 | struct cache *gc;
734 | struct cache_ent *ce;
735 | {
736 | struct cache_ent *move;
737 | long long found;
738 | move=gc->head;
739 | if(move==ce) /* Head of list */
740 | {
741 |
742 | gc->head=ce->forward;
743 | if(gc->head)
744 | gc->head->back=0;
745 | else
746 | gc->tail = 0;
747 | if(!ce->direct)
748 | {
749 | free((void *)(ce->real_address));
750 | free((void *)ce);
751 | }
752 | gc->count--;
753 | return;
754 | }
755 | found=0;
756 | while(move)
757 | {
758 | if(move==ce)
759 | {
760 | if(move->forward)
761 | {
762 | move->forward->back=move->back;
763 | }
764 | if(move->back)
765 | {
766 | move->back->forward=move->forward;
767 | }
768 | found=1;
769 | break;
770 | }
771 | else
772 | {
773 | move=move->forward;
774 | }
775 | }
776 | if(gc->head == ce)
777 | gc->tail = ce;
778 | if(!found)
779 | printf("Internal Error in takeoff cache\n");
780 | move=gc->head;
781 | if(!ce->direct)
782 | {
783 | free((void *)(ce->real_address));
784 | free((void *)ce);
785 | }
786 | gc->count--;
787 | }
788 |
789 | /************************************************************************
790 | * This routine is used to purge the entire cache. This is called when
791 | * the cache contains data but the incomming read was not able to
792 | * be satisfied from the cache. This indicates that the previous
793 | * async read-ahead was not correct and a new pattern is emerging.
794 | ************************************************************************/
795 | void
796 | del_cache(gc)
797 | struct cache *gc;
798 | {
799 | struct cache_ent *ce;
800 | ssize_t ret;
801 | ce=gc->head;
802 | while(1)
803 | {
804 | ce=gc->head;
805 | if(ce==0)
806 | return;
807 | #ifdef _LARGEFILE64_SOURCE
808 | #ifdef __LP64__
809 | while((ret = aio_cancel(0,&ce->myaiocb))==AIO_NOTCANCELED)
810 | #else
811 | while((ret = aio_cancel64(0,&ce->myaiocb64))==AIO_NOTCANCELED)
812 | #endif
813 | #else
814 | while((ret = aio_cancel(0,&ce->myaiocb))==AIO_NOTCANCELED)
815 | #endif
816 | ;
817 |
818 | #ifdef _LARGEFILE64_SOURCE
819 | #ifdef __LP64__
820 | ret = aio_return(&ce->myaiocb);
821 | #else
822 | ret = aio_return64(&ce->myaiocb64);
823 | #endif
824 | #else
825 | ret = aio_return(&ce->myaiocb);
826 | #endif
827 | ce->direct=0;
828 | takeoff_cache(gc,ce); /* remove from cache */
829 | }
830 | }
831 |
832 | /************************************************************************
833 | * Like its sister async_read() this function performs async I/O for
834 | * all buffers but it differs in that it expects the caller to
835 | * request a pointer to the data to be returned instead of handing
836 | * the function a location to put the data. This will allow the
837 | * async I/O to be performed and does not require any bcopy to be
838 | * done to put the data back into the location specified by the caller.
839 | ************************************************************************/
840 | int
841 | async_read_no_copy(gc, fd, ubuffer, offset, size, stride, max, depth)
842 | struct cache *gc;
843 | long long fd;
844 | char **ubuffer;
845 | off64_t offset;
846 | long long size;
847 | long long stride;
848 | off64_t max;
849 | long long depth;
850 | {
851 | off64_t a_offset,r_offset;
852 | long long a_size;
853 | struct cache_ent *ce,*first_ce=0;
854 | long long i;
855 | ssize_t retval=0;
856 | ssize_t ret;
857 | long long del_read=0;
858 | long long start=0;
859 |
860 | a_offset=offset;
861 | a_size = size;
862 | /*
863 | * Check to see if it can be completed from the cache
864 | */
865 | if((ce=(struct cache_ent *)incache(gc,fd,offset,size)))
866 | {
867 | #ifdef _LARGEFILE64_SOURCE
868 | #ifdef __LP64__
869 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
870 | {
871 | async_suspend(ce);
872 | }
873 | #else
874 | while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)
875 | {
876 | async_suspend(ce);
877 | }
878 | #endif
879 | #else
880 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
881 | {
882 | async_suspend(ce);
883 | }
884 | #endif
885 | if(ret)
886 | printf("aio_error 3: ret %d %d\n",ret,errno);
887 | #ifdef _LARGEFILE64_SOURCE
888 | #ifdef __LP64__
889 | if(ce->oldbuf != ce->myaiocb.aio_buf ||
890 | ce->oldfd != ce->myaiocb.aio_fildes ||
891 | ce->oldsize != ce->myaiocb.aio_nbytes)
892 | #else
893 | if(ce->oldbuf != ce->myaiocb64.aio_buf ||
894 | ce->oldfd != ce->myaiocb64.aio_fildes ||
895 | ce->oldsize != ce->myaiocb64.aio_nbytes)
896 | #endif
897 | #else
898 | if(ce->oldbuf != ce->myaiocb.aio_buf ||
899 | ce->oldfd != ce->myaiocb.aio_fildes ||
900 | ce->oldsize != ce->myaiocb.aio_nbytes)
901 | #endif
902 | printf("It changed in flight\n");
903 |
904 | #ifdef _LARGEFILE64_SOURCE
905 | #ifdef __LP64__
906 | retval=aio_return(&ce->myaiocb);
907 | #else
908 | retval=aio_return64(&ce->myaiocb64);
909 | #endif
910 | #else
911 | retval=aio_return(&ce->myaiocb);
912 | #endif
913 | if(retval > 0)
914 | {
915 | #ifdef _LARGEFILE64_SOURCE
916 | #ifdef __LP64__
917 | *ubuffer=(char *)ce->myaiocb.aio_buf;
918 | #else
919 | *ubuffer=(char *)ce->myaiocb64.aio_buf;
920 | #endif
921 | #else
922 | *ubuffer=(char *)ce->myaiocb.aio_buf;
923 | #endif
924 | }else
925 | *ubuffer=0;
926 | #ifdef _LARGEFILE64_SOURCE
927 | #ifdef __LP64__
928 | if(retval < ce->myaiocb.aio_nbytes)
929 | #else
930 | if(retval < ce->myaiocb64.aio_nbytes)
931 | #endif
932 | #else
933 | if(retval < ce->myaiocb.aio_nbytes)
934 | #endif
935 | {
936 | printf("aio_return error4: ret %d %d\n",retval,errno);
937 | #ifdef _LARGEFILE64_SOURCE
938 | #ifdef __LP64__
939 | printf("aio_return error4: fd %d offset %lld buffer %lx size %d Opcode %d\n",
940 | ce->myaiocb.aio_fildes,
941 | ce->myaiocb.aio_offset,
942 | (long)(ce->myaiocb.aio_buf),
943 | ce->myaiocb.aio_nbytes,
944 | ce->myaiocb.aio_lio_opcode
945 | #else
946 | printf("aio_return error4: fd %d offset %lld buffer %lx size %d Opcode %d\n",
947 | ce->myaiocb64.aio_fildes,
948 | ce->myaiocb64.aio_offset,
949 | (long)(ce->myaiocb64.aio_buf),
950 | ce->myaiocb64.aio_nbytes,
951 | ce->myaiocb64.aio_lio_opcode
952 | #endif
953 | #else
954 | printf("aio_return error4: fd %d offset %d buffer %lx size %d Opcode %d\n",
955 | ce->myaiocb.aio_fildes,
956 | ce->myaiocb.aio_offset,
957 | (long)(ce->myaiocb.aio_buf),
958 | ce->myaiocb.aio_nbytes,
959 | ce->myaiocb.aio_lio_opcode
960 | #endif
961 | );
962 | }
963 | ce->direct=1;
964 | takeoff_cache(gc,ce); /* do not delete buffer*/
965 | putoninuse(gc,ce);
966 | }else
967 | {
968 | /*
969 | * Clear the cache and issue the first request async()
970 | */
971 | del_cache(gc);
972 | del_read++;
973 | first_ce=alloc_cache(gc,fd,offset,size,(long long)LIO_READ); /* allocate buffer */
974 | /*printf("allocated buffer/read %x offset %d\n",first_ce->myaiocb.aio_buf,offset);*/
975 | again:
976 | #ifdef _LARGEFILE64_SOURCE
977 | #ifdef __LP64__
978 | first_ce->oldbuf=first_ce->myaiocb.aio_buf;
979 | first_ce->oldfd=first_ce->myaiocb.aio_fildes;
980 | first_ce->oldsize=first_ce->myaiocb.aio_nbytes;
981 | ret=aio_read(&first_ce->myaiocb);
982 | #else
983 | first_ce->oldbuf=first_ce->myaiocb64.aio_buf;
984 | first_ce->oldfd=first_ce->myaiocb64.aio_fildes;
985 | first_ce->oldsize=first_ce->myaiocb64.aio_nbytes;
986 | ret=aio_read64(&first_ce->myaiocb64);
987 | #endif
988 | #else
989 | first_ce->oldbuf=first_ce->myaiocb.aio_buf;
990 | first_ce->oldfd=first_ce->myaiocb.aio_fildes;
991 | first_ce->oldsize=first_ce->myaiocb.aio_nbytes;
992 | ret=aio_read(&first_ce->myaiocb);
993 | #endif
994 | if(ret!=0)
995 | {
996 | if(errno==EAGAIN)
997 | goto again;
998 | else
999 | printf("error returned from aio_read(). Ret %d errno %d\n",ret,errno);
1000 | }
1001 | }
1002 | if(stride==0) /* User does not want read-ahead */
1003 | goto out;
1004 | if(a_offset<0) /* Before beginning of file */
1005 | goto out;
1006 | if(a_offset+size>max) /* After end of file */
1007 | goto out;
1008 | if(depth >=(max_depth-1))
1009 | depth=max_depth-1;
1010 | if(depth==0)
1011 | goto out;
1012 | if(gc->count > 1)
1013 | start=depth-1;
1014 | for(i=start;i max)
1020 | continue;
1021 | if((ce=incache(gc,fd,r_offset,a_size)))
1022 | continue;
1023 | ce=alloc_cache(gc,fd,r_offset,a_size,(long long)LIO_READ);
1024 | #ifdef _LARGEFILE64_SOURCE
1025 | #ifdef __LP64__
1026 | ce->oldbuf=ce->myaiocb.aio_buf;
1027 | ce->oldfd=ce->myaiocb.aio_fildes;
1028 | ce->oldsize=ce->myaiocb.aio_nbytes;
1029 | ret=aio_read(&ce->myaiocb);
1030 | #else
1031 | ce->oldbuf=ce->myaiocb64.aio_buf;
1032 | ce->oldfd=ce->myaiocb64.aio_fildes;
1033 | ce->oldsize=ce->myaiocb64.aio_nbytes;
1034 | ret=aio_read64(&ce->myaiocb64);
1035 | #endif
1036 | #else
1037 | ce->oldbuf=ce->myaiocb.aio_buf;
1038 | ce->oldfd=ce->myaiocb.aio_fildes;
1039 | ce->oldsize=ce->myaiocb.aio_nbytes;
1040 | ret=aio_read(&ce->myaiocb);
1041 | #endif
1042 | if(ret!=0)
1043 | {
1044 | takeoff_cache(gc,ce);
1045 | break;
1046 | }
1047 | }
1048 | out:
1049 | if(del_read) /* Wait for the first read to complete */
1050 | {
1051 | #ifdef _LARGEFILE64_SOURCE
1052 | #ifdef __LP64__
1053 | while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
1054 | {
1055 | async_suspend(first_ce);
1056 | }
1057 | #else
1058 | while((ret=aio_error64(&first_ce->myaiocb64))== EINPROGRESS)
1059 | {
1060 | async_suspend(first_ce);
1061 | }
1062 | #endif
1063 | #else
1064 | while((ret=aio_error(&first_ce->myaiocb))== EINPROGRESS)
1065 | {
1066 | async_suspend(first_ce);
1067 | }
1068 | #endif
1069 | if(ret)
1070 | printf("aio_error 4: ret %d %d\n",ret,errno);
1071 | #ifdef _LARGEFILE64_SOURCE
1072 | #ifdef __LP64__
1073 | if(first_ce->oldbuf != first_ce->myaiocb.aio_buf ||
1074 | first_ce->oldfd != first_ce->myaiocb.aio_fildes ||
1075 | first_ce->oldsize != first_ce->myaiocb.aio_nbytes)
1076 | printf("It changed in flight2\n");
1077 | retval=aio_return(&first_ce->myaiocb);
1078 | #else
1079 | if(first_ce->oldbuf != first_ce->myaiocb64.aio_buf ||
1080 | first_ce->oldfd != first_ce->myaiocb64.aio_fildes ||
1081 | first_ce->oldsize != first_ce->myaiocb64.aio_nbytes)
1082 | printf("It changed in flight2\n");
1083 | retval=aio_return64(&first_ce->myaiocb64);
1084 | #endif
1085 | #else
1086 | if(first_ce->oldbuf != first_ce->myaiocb.aio_buf ||
1087 | first_ce->oldfd != first_ce->myaiocb.aio_fildes ||
1088 | first_ce->oldsize != first_ce->myaiocb.aio_nbytes)
1089 | printf("It changed in flight2\n");
1090 | retval=aio_return(&first_ce->myaiocb);
1091 | #endif
1092 | #ifdef _LARGEFILE64_SOURCE
1093 | #ifdef __LP64__
1094 | if(retval < first_ce->myaiocb.aio_nbytes)
1095 | #else
1096 | if(retval < first_ce->myaiocb64.aio_nbytes)
1097 | #endif
1098 | #else
1099 | if(retval < first_ce->myaiocb.aio_nbytes)
1100 | #endif
1101 | {
1102 | printf("aio_return error5: ret %d %d\n",retval,errno);
1103 | #ifdef _LARGEFILE64_SOURCE
1104 | #ifdef __LP64__
1105 | printf("aio_return error5: fd %d offset %lld buffer %lx size %d Opcode %d\n",
1106 | first_ce->myaiocb.aio_fildes,
1107 | first_ce->myaiocb.aio_offset,
1108 | (long)(first_ce->myaiocb.aio_buf),
1109 | first_ce->myaiocb.aio_nbytes,
1110 | first_ce->myaiocb.aio_lio_opcode
1111 | #else
1112 | printf("aio_return error5: fd %d offset %lld buffer %lx size %d Opcode %d\n",
1113 | first_ce->myaiocb64.aio_fildes,
1114 | first_ce->myaiocb64.aio_offset,
1115 | (long)(first_ce->myaiocb64.aio_buf),
1116 | first_ce->myaiocb64.aio_nbytes,
1117 | first_ce->myaiocb64.aio_lio_opcode
1118 | #endif
1119 | #else
1120 | printf("aio_return error5: fd %d offset %ld buffer %lx size %d Opcode %d\n",
1121 | first_ce->myaiocb.aio_fildes,
1122 | first_ce->myaiocb.aio_offset,
1123 | (long)(first_ce->myaiocb.aio_buf),
1124 | first_ce->myaiocb.aio_nbytes,
1125 | first_ce->myaiocb.aio_lio_opcode
1126 | #endif
1127 | );
1128 | }
1129 | if(retval > 0)
1130 | {
1131 | #ifdef _LARGEFILE64_SOURCE
1132 | #ifdef __LP64__
1133 | *ubuffer=(char *)first_ce->myaiocb.aio_buf;
1134 | #else
1135 | *ubuffer=(char *)first_ce->myaiocb64.aio_buf;
1136 | #endif
1137 | #else
1138 | *ubuffer=(char *)first_ce->myaiocb.aio_buf;
1139 | #endif
1140 | }else
1141 | *ubuffer=(char *)0;
1142 | first_ce->direct=1; /* do not delete the buffer */
1143 | takeoff_cache(gc,first_ce);
1144 | putoninuse(gc,first_ce);
1145 | }
1146 | return((int)retval);
1147 | }
1148 |
1149 | /************************************************************************
1150 | * The caller is now finished with the data that was provided so
1151 | * the library is now free to return the memory to the pool for later
1152 | * reuse.
1153 | ************************************************************************/
1154 | void
1155 | async_release(gc)
1156 | struct cache *gc;
1157 | {
1158 | takeoffinuse(gc);
1159 | }
1160 |
1161 |
1162 | /************************************************************************
1163 | * Put the buffer on the inuse list. When the user is finished with
1164 | * the buffer it will call back into async_release and the items on the
1165 | * inuse list will be deallocated.
1166 | ************************************************************************/
1167 | void
1168 | putoninuse(gc,entry)
1169 | struct cache *gc;
1170 | struct cache_ent *entry;
1171 | {
1172 | if(gc->inuse_head)
1173 | entry->forward=gc->inuse_head;
1174 | else
1175 | entry->forward=0;
1176 | gc->inuse_head=entry;
1177 | }
1178 |
1179 | /************************************************************************
1180 | * This is called when the application is finished with the data that
1181 | * was provided. The memory may now be returned to the pool.
1182 | ************************************************************************/
1183 | void
1184 | takeoffinuse(gc)
1185 | struct cache *gc;
1186 | {
1187 | struct cache_ent *ce;
1188 | if(gc->inuse_head==0)
1189 | printf("Takeoffinuse error\n");
1190 | ce=gc->inuse_head;
1191 | gc->inuse_head=gc->inuse_head->forward;
1192 |
1193 | if(gc->inuse_head !=0)
1194 | printf("Error in take off inuse\n");
1195 | free((void*)(ce->real_address));
1196 | free(ce);
1197 | }
1198 |
1199 | /*************************************************************************
1200 | * This routine is a generic async writer assist funtion. It takes
1201 | * the same calling parameters as write() but also extends the
1202 | * interface to include:
1203 | *
1204 | * offset ..... offset in the file.
1205 | * depth ..... How much read-ahead do you want.
1206 | *
1207 | *************************************************************************/
1208 | size_t
1209 | async_write(gc,fd,buffer,size,offset,depth)
1210 | struct cache *gc;
1211 | long long fd,size;
1212 | char *buffer;
1213 | off64_t offset;
1214 | long long depth;
1215 | {
1216 | struct cache_ent *ce;
1217 | size_t ret;
1218 | ce=allocate_write_buffer(gc,fd,offset,size,(long long)LIO_WRITE,depth,0LL,(char *)0,(char *)0);
1219 | ce->direct=0; /* not direct. Lib supplies buffer and must free it */
1220 | #ifdef _LARGEFILE64_SOURCE
1221 | #ifdef __LP64__
1222 | mbcopy(buffer,(char *)(ce->myaiocb.aio_buf),(size_t)size);
1223 | #else
1224 | mbcopy(buffer,(char *)(ce->myaiocb64.aio_buf),(size_t)size);
1225 | #endif
1226 | #else
1227 | mbcopy(buffer,(char *)(ce->myaiocb.aio_buf),(size_t)size);
1228 | #endif
1229 | async_put_on_write_queue(gc,ce);
1230 | /*
1231 | printf("asw: fd %d offset %lld, size %d\n",ce->myaiocb64.aio_fildes,
1232 | ce->myaiocb64.aio_offset,
1233 | ce->myaiocb64.aio_nbytes);
1234 | */
1235 |
1236 | again:
1237 | #ifdef _LARGEFILE64_SOURCE
1238 | #ifdef __LP64__
1239 | ret=aio_write(&ce->myaiocb);
1240 | #else
1241 | ret=aio_write64(&ce->myaiocb64);
1242 | #endif
1243 | #else
1244 | ret=aio_write(&ce->myaiocb);
1245 | #endif
1246 | if(ret==-1)
1247 | {
1248 | if(errno==EAGAIN)
1249 | {
1250 | async_wait_for_write(gc);
1251 | goto again;
1252 | }
1253 | if(errno==0)
1254 | {
1255 | /* Compensate for bug in async library */
1256 | async_wait_for_write(gc);
1257 | goto again;
1258 | }
1259 | else
1260 | {
1261 | printf("Error in aio_write: ret %d errno %d count %lld\n",ret,errno,gc->w_count);
1262 | /*
1263 | printf("aio_write_no_copy: fd %d buffer %x offset %lld size %d\n",
1264 | ce->myaiocb64.aio_fildes,
1265 | ce->myaiocb64.aio_buf,
1266 | ce->myaiocb64.aio_offset,
1267 | ce->myaiocb64.aio_nbytes);
1268 | */
1269 | exit(177);
1270 | }
1271 | }
1272 | return((ssize_t)size);
1273 | }
1274 |
1275 | /*************************************************************************
1276 | * Allocate a write aiocb and write buffer of the size specified. Also
1277 | * put some extra buffer padding so that VX_DIRECT can do its job when
1278 | * needed.
1279 | *************************************************************************/
1280 |
1281 | struct cache_ent *
1282 | allocate_write_buffer(gc,fd,offset,size,op,w_depth,direct,buffer,free_addr)
1283 | struct cache *gc;
1284 | long long fd,size,op;
1285 | off64_t offset;
1286 | long long w_depth;
1287 | long long direct;
1288 | char *buffer,*free_addr;
1289 | {
1290 | struct cache_ent *ce;
1291 | long temp;
1292 | if(fd==0LL)
1293 | {
1294 | printf("Setting up write buffer insane\n");
1295 | exit(178);
1296 | }
1297 | if(gc->w_count > w_depth)
1298 | async_wait_for_write(gc);
1299 | ce=(struct cache_ent *)malloc((size_t)sizeof(struct cache_ent));
1300 | if(ce == (struct cache_ent *)0)
1301 | {
1302 | printf("Malloc failed 1\n");
1303 | exit(179);
1304 | }
1305 | bzero(ce,sizeof(struct cache_ent));
1306 | #ifdef _LARGEFILE64_SOURCE
1307 | #ifdef __LP64__
1308 | ce->myaiocb.aio_fildes=(int)fd;
1309 | ce->myaiocb.aio_offset=(off64_t)offset;
1310 | if(!direct)
1311 | {
1312 | ce->real_address = (char *)malloc((size_t)(size+page_size));
1313 | temp=(long)ce->real_address;
1314 | temp = (temp+page_size) & ~(page_size-1);
1315 | ce->myaiocb.aio_buf=(volatile void *)temp;
1316 | }else
1317 | {
1318 | ce->myaiocb.aio_buf=(volatile void *)buffer;
1319 | ce->real_address=(char *)free_addr;
1320 | }
1321 | if(ce->myaiocb.aio_buf == 0)
1322 | #else
1323 | ce->myaiocb64.aio_fildes=(int)fd;
1324 | ce->myaiocb64.aio_offset=(off64_t)offset;
1325 | if(!direct)
1326 | {
1327 | ce->real_address = (char *)malloc((size_t)(size+page_size));
1328 | temp=(long)ce->real_address;
1329 | temp = (temp+page_size) & ~(page_size-1);
1330 | ce->myaiocb64.aio_buf=(volatile void *)temp;
1331 | }
1332 | else
1333 | {
1334 | ce->myaiocb64.aio_buf=(volatile void *)buffer;
1335 | ce->real_address=(char *)free_addr;
1336 | }
1337 | if(ce->myaiocb64.aio_buf == 0)
1338 | #endif
1339 | #else
1340 | ce->myaiocb.aio_fildes=(int)fd;
1341 | ce->myaiocb.aio_offset=(off_t)offset;
1342 | if(!direct)
1343 | {
1344 | ce->real_address = (char *)malloc((size_t)(size+page_size));
1345 | temp=(long)ce->real_address;
1346 | temp = (temp+page_size) & ~(page_size-1);
1347 | ce->myaiocb.aio_buf=(volatile void *)temp;
1348 | }
1349 | else
1350 | {
1351 | ce->myaiocb.aio_buf=(volatile void *)buffer;
1352 | ce->real_address=(char *)free_addr;
1353 | }
1354 | if(ce->myaiocb.aio_buf == 0)
1355 | #endif
1356 | {
1357 | printf("Malloc failed 2\n");
1358 | exit(180);
1359 | }
1360 | #ifdef _LARGEFILE64_SOURCE
1361 | #ifdef __LP64__
1362 | ce->myaiocb.aio_reqprio=0;
1363 | ce->myaiocb.aio_nbytes=(size_t)size;
1364 | ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
1365 | ce->myaiocb.aio_lio_opcode=(int)op;
1366 | #else
1367 | ce->myaiocb64.aio_reqprio=0;
1368 | ce->myaiocb64.aio_nbytes=(size_t)size;
1369 | ce->myaiocb64.aio_sigevent.sigev_notify=SIGEV_NONE;
1370 | ce->myaiocb64.aio_lio_opcode=(int)op;
1371 | #endif
1372 | #else
1373 | ce->myaiocb.aio_reqprio=0;
1374 | ce->myaiocb.aio_nbytes=(size_t)size;
1375 | ce->myaiocb.aio_sigevent.sigev_notify=SIGEV_NONE;
1376 | ce->myaiocb.aio_lio_opcode=(int)op;
1377 | #endif
1378 | ce->fd=(int)fd;
1379 | return(ce);
1380 | }
1381 |
1382 | /*************************************************************************
1383 | * Put it on the outbound queue.
1384 | *************************************************************************/
1385 |
1386 | void
1387 | async_put_on_write_queue(gc,ce)
1388 | struct cache *gc;
1389 | struct cache_ent *ce;
1390 | {
1391 | ce->forward=0;
1392 | ce->back=gc->w_tail;
1393 | if(gc->w_tail)
1394 | gc->w_tail->forward = ce;
1395 | gc->w_tail= ce;
1396 | if(!gc->w_head)
1397 | gc->w_head=ce;
1398 | gc->w_count++;
1399 | return;
1400 | }
1401 |
1402 | /*************************************************************************
1403 | * Cleanup all outstanding writes
1404 | *************************************************************************/
1405 | void
1406 | async_write_finish(gc)
1407 | struct cache *gc;
1408 | {
1409 | while(gc->w_head)
1410 | {
1411 | /*printf("async_write_finish: Waiting for buffer %x to finish\n",gc->w_head->myaiocb64.aio_buf);*/
1412 | async_wait_for_write(gc);
1413 | }
1414 | }
1415 |
1416 | /*************************************************************************
1417 | * Wait for an I/O to finish
1418 | *************************************************************************/
1419 |
1420 | void
1421 | async_wait_for_write(gc)
1422 | struct cache *gc;
1423 | {
1424 | struct cache_ent *ce;
1425 | size_t ret,retval;
1426 | if(gc->w_head==0)
1427 | return;
1428 | ce=gc->w_head;
1429 | gc->w_head=ce->forward;
1430 | gc->w_count--;
1431 | ce->forward=0;
1432 | if(ce==gc->w_tail)
1433 | gc->w_tail=0;
1434 | /*printf("Wait for buffer %x offset %lld size %d to finish\n",
1435 | ce->myaiocb64.aio_buf,
1436 | ce->myaiocb64.aio_offset,
1437 | ce->myaiocb64.aio_nbytes);
1438 | printf("write count %lld \n",gc->w_count);
1439 | */
1440 | #ifdef _LARGEFILE64_SOURCE
1441 | #ifdef __LP64__
1442 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
1443 | {
1444 | async_suspend(ce);
1445 | }
1446 | #else
1447 | while((ret=aio_error64(&ce->myaiocb64))== EINPROGRESS)
1448 | {
1449 | async_suspend(ce);
1450 | }
1451 | #endif
1452 | #else
1453 | while((ret=aio_error(&ce->myaiocb))== EINPROGRESS)
1454 | {
1455 | async_suspend(ce);
1456 | }
1457 | #endif
1458 | if(ret)
1459 | {
1460 | printf("aio_error 5: ret %d %d\n",ret,errno);
1461 | #ifdef _LARGEFILE64_SOURCE
1462 | #ifdef __LP64__
1463 | printf("fd %d offset %lld size %d\n",
1464 | ce->myaiocb.aio_fildes,
1465 | ce->myaiocb.aio_offset,
1466 | ce->myaiocb.aio_nbytes);
1467 | #else
1468 | printf("fd %d offset %lld size %d\n",
1469 | ce->myaiocb64.aio_fildes,
1470 | ce->myaiocb64.aio_offset,
1471 | ce->myaiocb64.aio_nbytes);
1472 | #endif
1473 | #else
1474 | printf("fd %d offset %lld size %d\n",
1475 | ce->myaiocb.aio_fildes,
1476 | ce->myaiocb.aio_offset,
1477 | ce->myaiocb.aio_nbytes);
1478 | #endif
1479 | exit(181);
1480 | }
1481 |
1482 | #ifdef _LARGEFILE64_SOURCE
1483 | #ifdef __LP64__
1484 | retval=aio_return(&ce->myaiocb);
1485 | #else
1486 | #if defined(__CrayX1__)
1487 | retval=aio_return64((aiocb64_t *)&ce->myaiocb64);
1488 | #else
1489 | retval=aio_return64((struct aiocb64 *)&ce->myaiocb64);
1490 | #endif
1491 |
1492 | #endif
1493 | #else
1494 | retval=aio_return(&ce->myaiocb);
1495 | #endif
1496 | if((int)retval < 0)
1497 | {
1498 | printf("aio_return error: %d\n",errno);
1499 | }
1500 |
1501 | if(!ce->direct)
1502 | {
1503 | /* printf("Freeing buffer %x\n",ce->real_address);*/
1504 | free((void *)(ce->real_address));
1505 | free((void *)ce);
1506 | }
1507 |
1508 | }
1509 |
1510 | /*************************************************************************
1511 | * This routine is a generic async writer assist funtion. It takes
1512 | * the same calling parameters as write() but also extends the
1513 | * interface to include:
1514 | *
1515 | * offset ..... offset in the file.
1516 | * depth ..... How much read-ahead do you want.
1517 | * free_addr .. address of memory to free after write is completed.
1518 | *
1519 | *************************************************************************/
1520 | size_t
1521 | async_write_no_copy(gc,fd,buffer,size,offset,depth,free_addr)
1522 | struct cache *gc;
1523 | long long fd,size;
1524 | char *buffer;
1525 | off64_t offset;
1526 | long long depth;
1527 | char *free_addr;
1528 | {
1529 | struct cache_ent *ce;
1530 | size_t ret;
1531 | long long direct = 1;
1532 | ce=allocate_write_buffer(gc,fd,offset,size,(long long)LIO_WRITE,depth,direct,buffer,free_addr);
1533 | ce->direct=0; /* have library de-allocate the buffer */
1534 | async_put_on_write_queue(gc,ce);
1535 | /*
1536 | printf("awnc: fd %d offset %lld, size %d\n",ce->myaiocb64.aio_fildes,
1537 | ce->myaiocb64.aio_offset,
1538 | ce->myaiocb64.aio_nbytes);
1539 | */
1540 |
1541 | again:
1542 | #ifdef _LARGEFILE64_SOURCE
1543 | #ifdef __LP64__
1544 | ret=aio_write(&ce->myaiocb);
1545 | #else
1546 | ret=aio_write64(&ce->myaiocb64);
1547 | #endif
1548 | #else
1549 | ret=aio_write(&ce->myaiocb);
1550 | #endif
1551 | if(ret==-1)
1552 | {
1553 | if(errno==EAGAIN)
1554 | {
1555 | async_wait_for_write(gc);
1556 | goto again;
1557 | }
1558 | if(errno==0)
1559 | {
1560 | /* Compensate for bug in async library */
1561 | async_wait_for_write(gc);
1562 | goto again;
1563 | }
1564 | else
1565 | {
1566 | printf("Error in aio_write: ret %d errno %d\n",ret,errno);
1567 | #ifdef _LARGEFILE64_SOURCE
1568 | #ifdef __LP64__
1569 | printf("aio_write_no_copy: fd %d buffer %lx offset %lld size %d\n",
1570 | ce->myaiocb.aio_fildes,
1571 | (long)(ce->myaiocb.aio_buf),
1572 | ce->myaiocb.aio_offset,
1573 | ce->myaiocb.aio_nbytes);
1574 | #else
1575 | printf("aio_write_no_copy: fd %d buffer %lx offset %lld size %d\n",
1576 | ce->myaiocb64.aio_fildes,
1577 | (long)(ce->myaiocb64.aio_buf),
1578 | ce->myaiocb64.aio_offset,
1579 | ce->myaiocb64.aio_nbytes);
1580 | #endif
1581 | #else
1582 | printf("aio_write_no_copy: fd %d buffer %lx offset %ld size %d\n",
1583 | ce->myaiocb.aio_fildes,
1584 | (long)(ce->myaiocb.aio_buf),
1585 | ce->myaiocb.aio_offset,
1586 | ce->myaiocb.aio_nbytes);
1587 | #endif
1588 | exit(182);
1589 | }
1590 | }
1591 | else
1592 | {
1593 | return((ssize_t)size);
1594 | }
1595 | }
1596 |
1597 | void mbcopy(source, dest, len)
1598 | char *source,*dest;
1599 | size_t len;
1600 | {
1601 | int i;
1602 | for(i=0;i
15 | #include
16 | #include
17 | #if defined(__AIX__) || defined(linux) || defined(__FreeBSD__) || defined(__DragonFly__)
18 | #include
19 | #else
20 | #include
21 | #endif
22 |
23 | #if defined(OSV5) || defined(linux) || defined (__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) || defined(__DragonFly__)
24 | #include
25 | #endif
26 |
27 | #if defined(linux) || defined(__DragonFly__) || defined(macosx)
28 | #include
29 | #include
30 | #endif
31 |
32 | #if ((defined(solaris) && defined( __LP64__ )) || defined(__s390x__))
33 | /* If we are building for 64-bit Solaris, all functions that return pointers
34 | * must be declared before they are used; otherwise the compiler will assume
35 | * that they return ints and the top 32 bits of the pointer will be lost,
36 | * causing segmentation faults. The following includes take care of this.
37 | * It should be safe to add these for all other OSs too, but we're only
38 | * doing it for Solaris now in case another OS turns out to be a special case.
39 | */
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 | #endif
46 | /* Little Endian */
47 | #define ENDIAN_1 1
48 | /* Big Endian */
49 | #define ENDIAN_2 2
50 | /* Middle Endian */
51 | #define ENDIAN_3 3
52 | /* Middle Endian */
53 | #define ENDIAN_4 4
54 |
55 |
56 | #ifdef HAVE_ANSIC_C
57 | /************************************************************************/
58 | /* Here is the API... Enjoy */
59 | /************************************************************************/
60 | /* Create worksheet */
61 | int create_xls(char *);
62 | /* Args: Filename */
63 | /* */
64 | /* Close worksheet */
65 | void close_xls(int);
66 | /* Args: file descriptor */
67 | /* */
68 | /* Put a 16 bit integer in worksheet */
69 | void do_int(int,int,int,int);
70 | /* Args: file descriptor, */
71 | /* value, */
72 | /* row, */
73 | /* column */
74 |
75 | /* Put a double in 8 byte float */
76 | void do_float(int,double,int,int);
77 | /* Args: file descriptor, */
78 | /* value, */
79 | /* row, */
80 | /* column */
81 | /* Put a string in worksheet */
82 | void do_label(int,char *,int,int);
83 | /* Args: file descriptor, */
84 | /* string, */
85 | /* row, */
86 | /* column */
87 | /************************************************************************/
88 |
89 | char libbif_version[] = "Libbif Version $Revision: 3.22 $";
90 | void do_eof(int ); /* Used internally */
91 | void do_header(int ); /* Used internally */
92 | int endian(void);
93 | #endif
94 |
95 | #define BOF 0x9
96 | #define INTEGER 0x2
97 | #define FLOAT 0x3
98 | #define LABEL 0x4
99 | #define EXCEL_VERS 0x2
100 | #define WORKSHEET 0x10
101 |
102 | struct bof_record{ /* Beginning of file */
103 | char hi_opcode;
104 | char lo_opcode;
105 | char hi_length;
106 | char lo_length;
107 | char hi_version; /* Excel version */
108 | char lo_version;
109 | char hi_filetype;
110 | char lo_filetype;
111 | };
112 | struct int_record {
113 | char hi_opcode; /* Type 2 of record */
114 | char lo_opcode;
115 | char hi_length;
116 | char lo_length;
117 | char hi_row;
118 | char lo_row;
119 | char hi_column;
120 | char lo_column;
121 | char rgbhi;
122 | char rgbmed;
123 | char rgblo;
124 | char hi_data;
125 | char lo_data;
126 | };
127 | struct label_record {
128 | char hi_opcode; /* Type 4 of record */
129 | char lo_opcode;
130 | char hi_length;
131 | char lo_length;
132 | char hi_row;
133 | char lo_row;
134 | char hi_column;
135 | char lo_column;
136 | char rgbhi;
137 | char rgbmed;
138 | char rgblo;
139 | char string_length;
140 | char str_array[256];
141 | };
142 | struct float_record { /* Type 3 record */
143 | char hi_opcode;
144 | char lo_opcode;
145 | char hi_length;
146 | char lo_length;
147 | char hi_row;
148 | char lo_row;
149 | char hi_column;
150 | char lo_column;
151 | char rgbhi;
152 | char rgbmed;
153 | char rgblo;
154 | double data;
155 | };
156 | /*
157 | * Write the EOF and close the file
158 | */
159 | #ifdef HAVE_ANSIC_C
160 | void
161 | close_xls(int fd)
162 | {
163 | #else
164 | close_xls(fd)
165 | int fd;
166 | {
167 | #endif
168 | do_eof(fd);
169 | close(fd);
170 | }
171 |
172 | /*
173 | * Create xls worksheet. Create file and put the BOF record in it.
174 | */
175 | #ifdef HAVE_ANSIC_C
176 | int
177 | create_xls(char *name)
178 | {
179 | #else
180 | create_xls(name)
181 | char *name;
182 | {
183 | #endif
184 | int fd;
185 | unlink(name);
186 | #ifdef Windows
187 | fd=open(name,O_BINARY|O_CREAT|O_RDWR,0666);
188 | #else
189 | fd=open(name,O_CREAT|O_RDWR,0666);
190 | #endif
191 | if(fd<0)
192 | {
193 | printf("Error opening file %s\n",name);
194 | exit(-1);
195 | }
196 | do_header(fd);
197 | return(fd);
198 | }
199 |
200 | #ifdef HAVE_ANSIC_C
201 | void
202 | do_header(int fd) /* Stick the BOF at the beginning of the file */
203 | {
204 | #else
205 | do_header(fd)
206 | int fd;
207 | {
208 | #endif
209 | struct bof_record bof;
210 | bof.hi_opcode=BOF;
211 | bof.lo_opcode = 0x0;
212 | bof.hi_length=0x4;
213 | bof.lo_length=0x0;
214 | bof.hi_version=EXCEL_VERS;
215 | bof.lo_version=0x0;
216 | bof.hi_filetype=WORKSHEET;
217 | bof.lo_filetype=0x0;
218 | write(fd,&bof,sizeof(struct bof_record));
219 | }
220 |
221 | /*
222 | * Put an integer (16 bit) in the worksheet
223 | */
224 | #ifdef HAVE_ANSIC_C
225 | void
226 | do_int(int fd,int val, int row, int column)
227 | {
228 | #else
229 | do_int(fd,val,row,column)
230 | int fd,val,row,column;
231 | {
232 | #endif
233 | struct int_record intrec;
234 | short s_row,s_column;
235 | s_row=(short)row;
236 | s_column=(short)column;
237 | intrec.hi_opcode=INTEGER;
238 | intrec.lo_opcode=0x00;
239 | intrec.hi_length=0x09;
240 | intrec.lo_length=0x00;
241 | intrec.rgbhi=0x0;
242 | intrec.rgbmed=0x0;
243 | intrec.rgblo=0x0;
244 | intrec.hi_row=(char)s_row&0xff;
245 | intrec.lo_row=(char)(s_row>>8)&0xff;
246 | intrec.hi_column=(char)(s_column&0xff);
247 | intrec.lo_column=(char)(s_column>>8)&0xff;
248 | intrec.hi_data=(val & 0xff);
249 | intrec.lo_data=(val & 0xff00)>>8;
250 | write(fd,&intrec,13);
251 | }
252 |
253 | /* Note: This routine converts Big Endian to Little Endian
254 | * and writes the record out.
255 | */
256 |
257 | /*
258 | * Put a double in the worksheet as 8 byte float in IEEE format.
259 | */
260 | #ifdef HAVE_ANSIC_C
261 | void
262 | do_float(int fd, double value, int row, int column)
263 | {
264 | #else
265 | do_float(fd, value, row, column)
266 | int fd;
267 | double value;
268 | int row,column;
269 | {
270 | #endif
271 | struct float_record floatrec;
272 | short s_row,s_column;
273 | unsigned char *sptr,*dptr;
274 | s_row=(short)row;
275 | s_column=(short)column;
276 | floatrec.hi_opcode=FLOAT;
277 | floatrec.lo_opcode=0x00;
278 | floatrec.hi_length=0xf;
279 | floatrec.lo_length=0x00;
280 | floatrec.rgbhi=0x0;
281 | floatrec.rgbmed=0x0;
282 | floatrec.rgblo=0x0;
283 | floatrec.hi_row=(char)(s_row&0xff);
284 | floatrec.lo_row=(char)((s_row>>8)&0xff);
285 | floatrec.hi_column=(char)(s_column&0xff);
286 | floatrec.lo_column=(char)((s_column>>8)&0xff);
287 | sptr =(unsigned char *) &value;
288 | dptr =(unsigned char *) &floatrec.data;
289 |
290 | if(endian()==ENDIAN_2) /* Big Endian */
291 | {
292 | dptr[0]=sptr[7]; /* Convert to Little Endian */
293 | dptr[1]=sptr[6];
294 | dptr[2]=sptr[5];
295 | dptr[3]=sptr[4];
296 | dptr[4]=sptr[3];
297 | dptr[5]=sptr[2];
298 | dptr[6]=sptr[1];
299 | dptr[7]=sptr[0];
300 | }
301 | if(endian()==ENDIAN_3) /* Middle Endian */
302 | {
303 | dptr[0]=sptr[4]; /* 16 bit swapped ARM */
304 | dptr[1]=sptr[5];
305 | dptr[2]=sptr[6];
306 | dptr[3]=sptr[7];
307 | dptr[4]=sptr[0];
308 | dptr[5]=sptr[1];
309 | dptr[6]=sptr[2];
310 | dptr[7]=sptr[3];
311 | }
312 |
313 | if(endian()==ENDIAN_1) /* Little Endian */
314 | {
315 | dptr[0]=sptr[0]; /* Do not convert to Little Endian */
316 | dptr[1]=sptr[1];
317 | dptr[2]=sptr[2];
318 | dptr[3]=sptr[3];
319 | dptr[4]=sptr[4];
320 | dptr[5]=sptr[5];
321 | dptr[6]=sptr[6];
322 | dptr[7]=sptr[7];
323 | }
324 | if(endian()==-1) /* Unsupported architecture */
325 | {
326 | dptr[0]=0;
327 | dptr[1]=0;
328 | dptr[2]=0;
329 | dptr[3]=0;
330 | dptr[4]=0;
331 | dptr[5]=0;
332 | dptr[6]=0;
333 | dptr[7]=0;
334 | printf("Excel output not supported on this architecture.\n");
335 | }
336 | write(fd,&floatrec,11); /* Don't write floatrec. Padding problems */
337 | write(fd,&floatrec.data,8); /* Write value seperately */
338 | }
339 |
340 | /*
341 | * Put a string as a label in the worksheet.
342 | */
343 | #ifdef HAVE_ANSIC_C
344 | void
345 | do_label(int fd, char *string, int row, int column)
346 | {
347 | #else
348 | do_label(fd, string, row, column)
349 | int fd;
350 | char *string;
351 | int row,column;
352 | {
353 | #endif
354 | struct label_record labelrec;
355 | short s_row,s_column;
356 | int i;
357 | for(i=0;i<255;i++)
358 | labelrec.str_array[i]=0;
359 | s_row=(short)row;
360 | s_column=(short)column;
361 | i=strlen(string);
362 | labelrec.hi_opcode=LABEL;
363 | labelrec.lo_opcode=0x00;
364 | labelrec.hi_length=0x08; /* 264 total bytes */
365 | labelrec.lo_length=0x01;
366 | labelrec.rgblo=0x0;
367 | labelrec.rgbmed=0x0;
368 | labelrec.rgbhi=0x0;
369 | labelrec.hi_row=(char)(s_row&0xff);
370 | labelrec.lo_row=(char)((s_row>>8)&0xff);
371 | labelrec.hi_column=(char)(s_column&0xff);
372 | labelrec.lo_column=(char)((s_column>>8)&0xff);
373 | labelrec.string_length=i;
374 | if(i > 255) /* If too long then terminate it early */
375 | string[254]=0;
376 | i=strlen(string);
377 | strcpy(labelrec.str_array,string);
378 |
379 | write(fd,&labelrec,sizeof(struct label_record));
380 |
381 | }
382 |
383 | /*
384 | * Write the EOF in the file
385 | */
386 | #ifdef HAVE_ANSIC_C
387 | void
388 | do_eof(int fd)
389 | {
390 | #else
391 | do_eof(fd)
392 | int fd;
393 | {
394 | #endif
395 | char buf[]={0x0a,0x00,0x00,0x00};
396 | write(fd,buf,4);
397 | }
398 |
399 | /*
400 | * Routine to determine the Endian-ness of the system. This
401 | * is needed for Iozone to convert doubles (floats) into
402 | * Little-endian format. This is needed for Excel to be
403 | * able to interpret the file
404 | */
405 | int
406 | endian(void)
407 | {
408 | long long foo = 0x0102030405060708LL;
409 | long foo1 = 0x012345678;
410 | unsigned char *c,c1,c2,c3,c4,c5,c6,c7,c8;
411 | c=(unsigned char *)&foo;
412 | c1=*c++;
413 | c2=*c++;
414 | c3=*c++;
415 | c4=*c++;
416 | c5=*c++;
417 | c6=*c++;
418 | c7=*c++;
419 | c8=*c;
420 |
421 | /*--------------------------------------------------------------*/
422 | /* printf("%x %x %x %x %x %x %x %x\n",c1,c2,c3,c4,c5,c6,c7,c8); */
423 | /*--------------------------------------------------------------*/
424 |
425 | /* Little Endian format ? ( Intel ) */
426 | if( (c1==0x08) && (c2==0x07) && (c3==0x06) && (c4==0x05) &&
427 | (c5==0x04) && (c6==0x03) && (c7==0x02) && (c8==0x01) )
428 | return(ENDIAN_1);
429 | /* Big Endian format ? ( Sparc, Risc... */
430 | if( (c1==0x01) && (c2==0x02) && (c3==0x03) && (c4==0x04) &&
431 | (c5==0x05) && (c6==0x06) && (c7==0x07) && (c8==0x08) )
432 | return(ENDIAN_2);
433 | /* Middle Endian format ? ( ARM ... ) */
434 | if( (c1==0x04) && (c2==0x03) && (c3==0x02) && (c4==0x01) &&
435 | (c5==0x08) && (c6==0x07) && (c7==0x06) && (c8==0x05) )
436 | return(ENDIAN_3);
437 | c=(unsigned char *)&foo1;
438 | c1=*c++;
439 | c2=*c++;
440 | c3=*c++;
441 | c4=*c++;
442 | /* Another middle endian format ? ( PDP-11 ... ) */
443 | if( (c1==0x34) && (c2==0x12) && (c3==0x78) && (c4==0x56))
444 | return(ENDIAN_4);
445 |
446 | return(-1);
447 | }
448 |
--------------------------------------------------------------------------------
/pit_server.c:
--------------------------------------------------------------------------------
1 | /******************************************************************************
2 | * File: pit_server.c
3 | *
4 | * Description: Contains source code for an IPv6-capable 'PIT' server.
5 | * This is a derivative of the tod6 (time-of-day) server that was written
6 | * by John Wenker.
7 | * .......
8 | * Author of tod6: John Wenker, Sr. Software Engineer,
9 | * Performance Technologies, San Diego, USA
10 | * .......
11 | * The program tod6 was a time of day server. It has beeen modified
12 | * to provide a microsecond timestamp on request. Modified and adapted
13 | * for PIT purposes by Don Capps. [ capps@iozone.org ]
14 | *
15 | * This server sends the current value of gettimeofday() in
16 | * microseconds back to the client, as a numerical string.
17 | *
18 | * /etc/services should contain "PIT" with a specified port value.
19 | *
20 | ******************************************************************************/
21 | /*
22 | ** System header files.
23 | */
24 | #include /* errno declaration & error codes. */
25 | #include /* getaddrinfo(3) et al. */
26 | #include /* sockaddr_in & sockaddr_in6 definition. */
27 | #include /* printf(3) et al. */
28 | #include /* exit(2). */
29 | #include /* String manipulation & memory functions. */
30 | #include /* poll(2) and related definitions. */
31 | #include /* Socket functions (socket(2), bind(2), etc). */
32 | #include /* time(2) & ctime(3). */
33 | #include /* gettimeofday */
34 | #include /* getopt(3), read(2), etc. */
35 | /* Include for Cygnus development environment for Windows */
36 | #if defined (Windows)
37 | #include
38 | int errno;
39 | #endif
40 |
41 | /*
42 | ** Constants.
43 | **
44 | ** Please remember to add PIT service to the /etc/services file.
45 | */
46 | #define DFLT_SERVICE "PIT" /* Programmable Interdimensional Timer */
47 |
48 | #define INVALID_DESC -1 /* Invalid file descriptor. */
49 | #define MAXCONNQLEN 3 /* Max nbr of connection requests to queue. */
50 | #define MAXTCPSCKTS 2 /* One TCP socket for IPv4 & one for IPv6. */
51 | #define MAXUDPSCKTS 2 /* One UDP socket for IPv4 & one for IPv6. */
52 | #define VALIDOPTS "vh:p:" /* Valid command options. */
53 | /*
54 | ** Simple boolean type definition.
55 | */
56 | int false = 0;
57 | int true = 1;
58 | /*
59 | ** Prototypes for internal helper functions.
60 | */
61 | static int openSckt( const char *service,
62 | const char *protocol,
63 | int desc[ ],
64 | size_t *descSize );
65 | static void pit( int tSckt[ ],
66 | size_t tScktSize,
67 | int uSckt[ ],
68 | size_t uScktSize );
69 | /*
70 | ** Global data objects.
71 | */
72 | static char hostBfr[ NI_MAXHOST ]; /* For use w/getnameinfo(3). */
73 | static const char *pgmName; /* Program name w/o dir prefix. */
74 | static char servBfr[ NI_MAXSERV ]; /* For use w/getnameinfo(3). */
75 | static int verbose = 0; /* Verbose mode indication. */
76 | struct timeval tm; /* Timeval structure, used with gettimeofday() */
77 | char timeStr[40]; /* String for time in microseconds */
78 | char service_name[20];
79 | int need;
80 | /*
81 | ** Usage macro for command syntax violations.
82 | */
83 | #define USAGE \
84 | { \
85 | fprintf( stderr, \
86 | "Usage: %s [-v] -p service \n", \
87 | pgmName ); \
88 | exit( 127 ); \
89 | } /* End USAGE macro. */
90 | /*
91 | ** Macro to terminate the program if a system call error occurs. The system
92 | ** call must be one of the usual type that returns -1 on error.
93 | */
94 | #define CHK(expr) \
95 | do \
96 | { \
97 | if ( (expr) == -1 ) \
98 | { \
99 | fprintf( stderr, \
100 | "%s (line %d): System call ERROR - %s.\n", \
101 | pgmName, \
102 | __LINE__, \
103 | strerror( errno ) ); \
104 | exit( 1 ); \
105 | } /* End IF system call failed. */ \
106 | } while ( false )
107 | /******************************************************************************
108 | * Function: main
109 | *
110 | * Description:
111 | * Set up a PIT server and handle network requests. This server
112 | * handles both TCP and UDP requests.
113 | *
114 | * Parameters:
115 | * The usual argc and argv parameters to a main() function.
116 | *
117 | * Return Value:
118 | * This is a daemon program and never returns. However, in the degenerate
119 | * case where no sockets are created, the function returns zero.
120 | ******************************************************************************/
121 | int main( int argc,
122 | char *argv[ ] )
123 | {
124 | int opt;
125 | int tSckt[ MAXTCPSCKTS ]; /* Array of TCP socket descriptors. */
126 | size_t tScktSize = MAXTCPSCKTS; /* Size of uSckt (# of elements). */
127 | int uSckt[ MAXUDPSCKTS ]; /* Array of UDP socket descriptors. */
128 | size_t uScktSize = MAXUDPSCKTS; /* Size of uSckt (# of elements). */
129 |
130 | strcpy(service_name,DFLT_SERVICE);
131 | /*
132 | ** Set the program name (w/o directory prefix).
133 | */
134 | pgmName = strrchr( argv[ 0 ], '/' );
135 | pgmName = pgmName == NULL ? argv[ 0 ] : pgmName + 1;
136 | /*
137 | ** Process command options.
138 | */
139 | opterr = 0; /* Turns off "invalid option" error messages. */
140 | while ( ( opt = getopt( argc, argv, VALIDOPTS ) ) >= 0 )
141 | {
142 | switch ( opt )
143 | {
144 | case 'v': /* Verbose mode. */
145 | {
146 | verbose = true;
147 | break;
148 | }
149 | case 'p': /* Get the port number */
150 | {
151 | strcpy(service_name,optarg);
152 | need++;
153 | break;
154 | }
155 | default:
156 | {
157 | USAGE;
158 | }
159 | } /* End SWITCH on command option. */
160 | } /* End WHILE processing options. */
161 |
162 | if(need < 1)
163 | {
164 | USAGE;
165 | exit;
166 | }
167 | /*
168 | ** Open both a TCP and UDP socket, for both IPv4 & IPv6, on which to receive
169 | ** service requests.
170 | */
171 | if ( ( openSckt( service_name, "tcp", tSckt, &tScktSize ) < 0 ) ||
172 | ( openSckt( service_name, "udp", uSckt, &uScktSize ) < 0 ) )
173 | {
174 | exit( 1 );
175 | }
176 | /*
177 | ** Run the Programmable Interdimensional Timer server.
178 | */
179 | if ( ( tScktSize > 0 ) || ( uScktSize > 0 ) )
180 | {
181 | pit( tSckt, /* pit() never returns. */
182 | tScktSize,
183 | uSckt,
184 | uScktSize );
185 | }
186 | /*
187 | ** Since pit() never returns, execution only gets here if no sockets were
188 | ** created.
189 | */
190 | if ( verbose )
191 | {
192 | fprintf( stderr,
193 | "%s: No sockets opened... terminating.\n",
194 | pgmName );
195 | }
196 | return 0;
197 | } /* End main() */
198 | /******************************************************************************
199 | * Function: openSckt
200 | *
201 | * Description:
202 | * Open passive (server) sockets for the indicated inet service & protocol.
203 | * Notice in the last sentence that "sockets" is plural. During the interim
204 | * transition period while everyone is switching over to IPv6, the server
205 | * application has to open two sockets on which to listen for connections...
206 | * one for IPv4 traffic and one for IPv6 traffic.
207 | *
208 | * Parameters:
209 | * service - Pointer to a character string representing the well-known port
210 | * on which to listen (can be a service name or a decimal number).
211 | * protocol - Pointer to a character string representing the transport layer
212 | * protocol (only "tcp" or "udp" are valid).
213 | * desc - Pointer to an array into which the socket descriptors are
214 | * placed when opened.
215 | * descSize - This is a value-result parameter. On input, it contains the
216 | * max number of descriptors that can be put into 'desc' (i.e. the
217 | * number of elements in the array). Upon return, it will contain
218 | * the number of descriptors actually opened. Any unused slots in
219 | * 'desc' are set to INVALID_DESC.
220 | *
221 | * Return Value:
222 | * 0 on success, -1 on error.
223 | ******************************************************************************/
224 | static int openSckt( const char *service,
225 | const char *protocol,
226 | int desc[ ],
227 | size_t *descSize )
228 | {
229 | struct addrinfo *ai;
230 | int aiErr;
231 | struct addrinfo *aiHead;
232 | struct addrinfo hints = { .ai_flags = AI_PASSIVE, /* Server mode. */
233 | .ai_family = PF_UNSPEC }; /* IPv4 or IPv6. */
234 | size_t maxDescs = *descSize;
235 | /*
236 | ** Initialize output parameters. When the loop completes, *descSize is 0.
237 | */
238 | while ( *descSize > 0 )
239 | {
240 | desc[ --( *descSize ) ] = INVALID_DESC;
241 | }
242 | /*
243 | ** Check which protocol is selected (only TCP and UDP are valid).
244 | */
245 | if ( strcmp( protocol, "tcp" ) == 0 ) /* TCP protocol. */
246 | {
247 | hints.ai_socktype = SOCK_STREAM;
248 | hints.ai_protocol = IPPROTO_TCP;
249 | }
250 | else if ( strcmp( protocol, "udp" ) == 0 ) /* UDP protocol. */
251 | {
252 | hints.ai_socktype = SOCK_DGRAM;
253 | hints.ai_protocol = IPPROTO_UDP;
254 | }
255 | else /* Invalid protocol. */
256 | {
257 | fprintf( stderr,
258 | "%s (line %d): ERROR - Unknown transport "
259 | "layer protocol \"%s\".\n",
260 | pgmName,
261 | __LINE__,
262 | protocol );
263 | return -1;
264 | }
265 | /*
266 | ** Look up the service's "well-known" port number. Notice that NULL is being
267 | ** passed for the 'node' parameter, and that the AI_PASSIVE flag is set in
268 | ** 'hints'. Thus, the program is requesting passive address information.
269 | ** The network address is initialized to :: (all zeros) for IPv6 records, or
270 | ** 0.0.0.0 for IPv4 records.
271 | */
272 | if ( ( aiErr = getaddrinfo( NULL,
273 | service,
274 | &hints,
275 | &aiHead ) ) != 0 )
276 | {
277 | fprintf( stderr,
278 | "%s (line %d): ERROR - %s.\n",
279 | pgmName,
280 | __LINE__,
281 | gai_strerror( aiErr ) );
282 | return -1;
283 | }
284 | /*
285 | ** For each of the address records returned, attempt to set up a passive
286 | ** socket.
287 | */
288 | for ( ai = aiHead;
289 | ( ai != NULL ) && ( *descSize < maxDescs );
290 | ai = ai->ai_next )
291 | {
292 | if ( verbose )
293 | {
294 | /*
295 | ** Display the current address info. Start with the protocol-
296 | ** independent fields first.
297 | */
298 | fprintf( stderr,
299 | "Setting up a passive socket based on the "
300 | "following address info:\n"
301 | " ai_flags = 0x%02X\n"
302 | " ai_family = %d (PF_INET = %d, PF_INET6 = %d)\n"
303 | " ai_socktype = %d (SOCK_STREAM = %d, SOCK_DGRAM = %d)\n"
304 | " ai_protocol = %d (IPPROTO_TCP = %d, IPPROTO_UDP = %d)\n"
305 | " ai_addrlen = %d (sockaddr_in = %d, "
306 | "sockaddr_in6 = %d)\n",
307 | ai->ai_flags,
308 | ai->ai_family,
309 | PF_INET,
310 | PF_INET6,
311 | ai->ai_socktype,
312 | SOCK_STREAM,
313 | SOCK_DGRAM,
314 | ai->ai_protocol,
315 | IPPROTO_TCP,
316 | IPPROTO_UDP,
317 | ai->ai_addrlen,
318 | sizeof( struct sockaddr_in ),
319 | sizeof( struct sockaddr_in6 ) );
320 | /*
321 | ** Now display the protocol-specific formatted socket address. Note
322 | ** that the program is requesting that getnameinfo(3) convert the
323 | ** host & service into numeric strings.
324 | */
325 | getnameinfo( ai->ai_addr,
326 | ai->ai_addrlen,
327 | hostBfr,
328 | sizeof( hostBfr ),
329 | servBfr,
330 | sizeof( servBfr ),
331 | NI_NUMERICHOST | NI_NUMERICSERV );
332 | switch ( ai->ai_family )
333 | {
334 | case PF_INET: /* IPv4 address record. */
335 | {
336 | struct sockaddr_in *p = (struct sockaddr_in*) ai->ai_addr;
337 | fprintf( stderr,
338 | " ai_addr = sin_family: %d (AF_INET = %d, "
339 | "AF_INET6 = %d)\n"
340 | " sin_addr: %s\n"
341 | " sin_port: %s\n",
342 | p->sin_family,
343 | AF_INET,
344 | AF_INET6,
345 | hostBfr,
346 | servBfr );
347 | break;
348 | } /* End CASE of IPv4. */
349 | case PF_INET6: /* IPv6 address record. */
350 | {
351 | struct sockaddr_in6 *p = (struct sockaddr_in6*) ai->ai_addr;
352 | fprintf( stderr,
353 | " ai_addr = sin6_family: %d (AF_INET = %d, "
354 | "AF_INET6 = %d)\n"
355 | " sin6_addr: %s\n"
356 | " sin6_port: %s\n"
357 | " sin6_flowinfo: %d\n"
358 | " sin6_scope_id: %d\n",
359 | p->sin6_family,
360 | AF_INET,
361 | AF_INET6,
362 | hostBfr,
363 | servBfr,
364 | p->sin6_flowinfo,
365 | p->sin6_scope_id );
366 | break;
367 | } /* End CASE of IPv6. */
368 | default: /* Can never get here, but just for completeness. */
369 | {
370 | fprintf( stderr,
371 | "%s (line %d): ERROR - Unknown protocol family (%d).\n",
372 | pgmName,
373 | __LINE__,
374 | ai->ai_family );
375 | freeaddrinfo( aiHead );
376 | return -1;
377 | } /* End DEFAULT case (unknown protocol family). */
378 | } /* End SWITCH on protocol family. */
379 | } /* End IF verbose mode. */
380 | /*
381 | ** Create a socket using the info in the addrinfo structure.
382 | */
383 | CHK( desc[ *descSize ] = socket( ai->ai_family,
384 | ai->ai_socktype,
385 | ai->ai_protocol ) );
386 | /*
387 | ** Here is the code that prevents "IPv4 mapped addresses", as discussed
388 | ** in Section 22.1.3.1. If an IPv6 socket was just created, then set the
389 | ** IPV6_V6ONLY socket option.
390 | */
391 | if ( ai->ai_family == PF_INET6 )
392 | {
393 | #if defined( IPV6_V6ONLY )
394 | /*
395 | ** Disable IPv4 mapped addresses.
396 | */
397 | int v6Only = 1;
398 | CHK( setsockopt( desc[ *descSize ],
399 | IPPROTO_IPV6,
400 | IPV6_V6ONLY,
401 | &v6Only,
402 | sizeof( v6Only ) ) );
403 | #else
404 | /*
405 | ** IPV6_V6ONLY is not defined, so the socket option can't be set and
406 | ** thus IPv4 mapped addresses can't be disabled. Print a warning
407 | ** message and close the socket. Design note: If the
408 | ** #if...#else...#endif construct were removed, then this program
409 | ** would not compile (because IPV6_V6ONLY isn't defined). That's an
410 | ** acceptable approach; IPv4 mapped addresses are certainly disabled
411 | ** if the program can't build! However, since this program is also
412 | ** designed to work for IPv4 sockets as well as IPv6, I decided to
413 | ** allow the program to compile when IPV6_V6ONLY is not defined, and
414 | ** turn it into a run-time warning rather than a compile-time error.
415 | ** IPv4 mapped addresses are still disabled because _all_ IPv6 traffic
416 | ** is disabled (all IPv6 sockets are closed here), but at least this
417 | ** way the server can still service IPv4 network traffic.
418 | */
419 | fprintf( stderr,
420 | "%s (line %d): WARNING - Cannot set IPV6_V6ONLY socket "
421 | "option. Closing IPv6 %s socket.\n",
422 | pgmName,
423 | __LINE__,
424 | ai->ai_protocol == IPPROTO_TCP ? "TCP" : "UDP" );
425 | CHK( close( desc[ *descSize ] ) );
426 | continue; /* Go to top of FOR loop w/o updating *descSize! */
427 | #endif /* IPV6_V6ONLY */
428 | } /* End IF this is an IPv6 socket. */
429 | /*
430 | ** Bind the socket. Again, the info from the addrinfo structure is used.
431 | */
432 | CHK( bind( desc[ *descSize ],
433 | ai->ai_addr,
434 | ai->ai_addrlen ) );
435 | /*
436 | ** If this is a TCP socket, put the socket into passive listening mode
437 | ** (listen is only valid on connection-oriented sockets).
438 | */
439 | if ( ai->ai_socktype == SOCK_STREAM )
440 | {
441 | CHK( listen( desc[ *descSize ],
442 | MAXCONNQLEN ) );
443 | }
444 | /*
445 | ** Socket set up okay. Bump index to next descriptor array element.
446 | */
447 | *descSize += 1;
448 | } /* End FOR each address info structure returned. */
449 | /*
450 | ** Dummy check for unused address records.
451 | */
452 | if ( verbose && ( ai != NULL ) )
453 | {
454 | fprintf( stderr,
455 | "%s (line %d): WARNING - Some address records were "
456 | "not processed due to insufficient array space.\n",
457 | pgmName,
458 | __LINE__ );
459 | } /* End IF verbose and some address records remain unprocessed. */
460 | /*
461 | ** Clean up.
462 | */
463 | freeaddrinfo( aiHead );
464 | return 0;
465 | } /* End openSckt() */
466 | /******************************************************************************
467 | * Function: pit
468 | *
469 | * Description:
470 | * Listen on a set of sockets and send the current microsecond counter
471 | * that was produced by gettimeofday(), to any clients. This function
472 | * never returns.
473 | *
474 | * Parameters:
475 | * tSckt - Array of TCP socket descriptors on which to listen.
476 | * tScktSize - Size of the tSckt array (nbr of elements).
477 | * uSckt - Array of UDP socket descriptors on which to listen.
478 | * uScktSize - Size of the uSckt array (nbr of elements).
479 | *
480 | * Return Value: None.
481 | ******************************************************************************/
482 | static void pit( int tSckt[ ],
483 | size_t tScktSize,
484 | int uSckt[ ],
485 | size_t uScktSize )
486 | {
487 | char bfr[ 256 ];
488 | ssize_t count;
489 | struct pollfd *desc;
490 | size_t descSize = tScktSize + uScktSize;
491 | int idx;
492 | int newSckt;
493 | struct sockaddr *sadr;
494 | socklen_t sadrLen;
495 | struct sockaddr_storage sockStor;
496 | int status;
497 | size_t timeLen;
498 | time_t timeVal;
499 | ssize_t wBytes;
500 | unsigned long long secs;
501 | int ret;
502 | /*
503 | ** Allocate memory for the poll(2) array.
504 | */
505 | desc = malloc( descSize * sizeof( struct pollfd ) );
506 | if ( desc == NULL )
507 | {
508 | fprintf( stderr,
509 | "%s (line %d): ERROR - %s.\n",
510 | pgmName,
511 | __LINE__,
512 | strerror( ENOMEM ) );
513 | exit( 1 );
514 | }
515 | /*
516 | ** Initialize the poll(2) array.
517 | */
518 | for ( idx = 0; idx < descSize; idx++ )
519 | {
520 | desc[ idx ].fd = idx < tScktSize ? tSckt[ idx ]
521 | : uSckt[ idx - tScktSize ];
522 | desc[ idx ].events = POLLIN;
523 | desc[ idx ].revents = 0;
524 | }
525 | /*
526 | ** Main PIT server loop. Handles both TCP & UDP requests. This is
527 | ** an interative server, and all requests are handled directly within the
528 | ** main loop.
529 | */
530 | while ( true ) /* Do forever. */
531 | {
532 | /*
533 | ** Wait for activity on one of the sockets. The DO..WHILE construct is
534 | ** used to restart the system call in the event the process is
535 | ** interrupted by a signal.
536 | */
537 | do
538 | {
539 | status = poll( desc,
540 | descSize,
541 | -1 /* Wait indefinitely for input. */ );
542 | } while ( ( status < 0 ) && ( errno == EINTR ) );
543 | CHK( status ); /* Check for a bona fide system call error. */
544 | /*
545 | ** Get the current time.
546 | */
547 | #if defined(Windows)
548 | LARGE_INTEGER freq,counter;
549 | double wintime,bigcounter;
550 | /* For Windows the time_of_day() is useless. It increments in 55 milli
551 | * second increments. By using the Win32api one can get access to the
552 | * high performance measurement interfaces. With this one can get back
553 | * into the 8 to 9 microsecond resolution.
554 | */
555 | QueryPerformanceFrequency(&freq);
556 | QueryPerformanceCounter(&counter);
557 | bigcounter=(double)counter.HighPart *(double)0xffffffff +
558 | (double)counter.LowPart;
559 | wintime = (double)(bigcounter/(double)freq.LowPart);
560 | secs = (long long)(wintime * 1000000);
561 | #else
562 | ret = gettimeofday( &tm,0 );
563 | secs = ((unsigned long long)tm.tv_sec * 1000000)
564 | + (unsigned long long)tm.tv_usec;
565 | #endif
566 |
567 | ret = sprintf(timeStr,"%lld",secs);
568 | timeLen = strlen( timeStr );
569 | /*
570 | ** Process sockets with input available.
571 | */
572 | for ( idx = 0; idx < descSize; idx++ )
573 | {
574 | switch ( desc[ idx ].revents )
575 | {
576 | case 0: /* No activity on this socket; try the next. */
577 | continue;
578 | case POLLIN: /* Network activity. Go process it. */
579 | break;
580 | default: /* Invalid poll events. */
581 | {
582 | fprintf( stderr,
583 | "%s (line %d): ERROR - Invalid poll event (0x%02X).\n",
584 | pgmName,
585 | __LINE__,
586 | desc[ idx ].revents );
587 | exit( 1 );
588 | }
589 | } /* End SWITCH on returned poll events. */
590 | /*
591 | ** Determine if this is a TCP request or UDP request.
592 | */
593 | if ( idx < tScktSize )
594 | {
595 | /*
596 | ** TCP connection requested. Accept it. Notice the use of
597 | ** the sockaddr_storage data type.
598 | */
599 | sadrLen = sizeof( sockStor );
600 | sadr = (struct sockaddr*) &sockStor;
601 | CHK( newSckt = accept( desc[ idx ].fd,
602 | sadr,
603 | &sadrLen ) );
604 | CHK( shutdown( newSckt, /* Server never recv's anything. */
605 | SHUT_RD ) );
606 | if ( verbose )
607 | {
608 | /*
609 | ** Display the socket address of the remote client. Begin with
610 | ** the address-independent fields.
611 | */
612 | fprintf( stderr,
613 | "Sockaddr info for new TCP client:\n"
614 | " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n"
615 | " addr len = %d (sockaddr_in = %d, "
616 | "sockaddr_in6 = %d)\n",
617 | sadr->sa_family,
618 | AF_INET,
619 | AF_INET6,
620 | sadrLen,
621 | sizeof( struct sockaddr_in ),
622 | sizeof( struct sockaddr_in6 ) );
623 | /*
624 | ** Display the address-specific fields.
625 | */
626 | getnameinfo( sadr,
627 | sadrLen,
628 | hostBfr,
629 | sizeof( hostBfr ),
630 | servBfr,
631 | sizeof( servBfr ),
632 | NI_NUMERICHOST | NI_NUMERICSERV );
633 | /*
634 | ** Notice that we're switching on an address family now, not a
635 | ** protocol family.
636 | */
637 | switch ( sadr->sa_family )
638 | {
639 | case AF_INET: /* IPv4 address. */
640 | {
641 | struct sockaddr_in *p = (struct sockaddr_in*) sadr;
642 | fprintf( stderr,
643 | " sin_addr = sin_family: %d\n"
644 | " sin_addr: %s\n"
645 | " sin_port: %s\n",
646 | p->sin_family,
647 | hostBfr,
648 | servBfr );
649 | break;
650 | } /* End CASE of IPv4. */
651 | case AF_INET6: /* IPv6 address. */
652 | {
653 | struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr;
654 | fprintf( stderr,
655 | " sin6_addr = sin6_family: %d\n"
656 | " sin6_addr: %s\n"
657 | " sin6_port: %s\n"
658 | " sin6_flowinfo: %d\n"
659 | " sin6_scope_id: %d\n",
660 | p->sin6_family,
661 | hostBfr,
662 | servBfr,
663 | p->sin6_flowinfo,
664 | p->sin6_scope_id );
665 | break;
666 | } /* End CASE of IPv6. */
667 | default: /* Can never get here, but for completeness. */
668 | {
669 | fprintf( stderr,
670 | "%s (line %d): ERROR - Unknown address "
671 | "family (%d).\n",
672 | pgmName,
673 | __LINE__,
674 | sadr->sa_family );
675 | break;
676 | } /* End DEFAULT case (unknown address family). */
677 | } /* End SWITCH on address family. */
678 | } /* End IF verbose mode. */
679 | /*
680 | ** Send the PIT to the client.
681 | */
682 | wBytes = timeLen;
683 | while ( wBytes > 0 )
684 | {
685 | do
686 | {
687 | count = write( newSckt,
688 | timeStr,
689 | wBytes );
690 | } while ( ( count < 0 ) && ( errno == EINTR ) );
691 | CHK( count ); /* Check for an error. */
692 | wBytes -= count;
693 | } /* End WHILE there is data to send. */
694 | CHK( close( newSckt ) );
695 | } /* End IF this was a TCP connection request. */
696 | else
697 | {
698 | /*
699 | ** This is a UDP socket, and a datagram is available. The funny
700 | ** thing about UDP requests is that this server doesn't require any
701 | ** client input; but it can't send the PIT unless it knows a client
702 | ** wants the data, and the only way that can occur with UDP is if
703 | ** the server receives a datagram from the client. Thus, the
704 | ** server must receive _something_, but the content of the datagram
705 | ** is irrelevant. Read in the datagram. Again note the use of
706 | ** sockaddr_storage to receive the address.
707 | */
708 | sadrLen = sizeof( sockStor );
709 | sadr = (struct sockaddr*) &sockStor;
710 | CHK( count = recvfrom( desc[ idx ].fd,
711 | bfr,
712 | sizeof( bfr ),
713 | 0,
714 | sadr,
715 | &sadrLen ) );
716 | /*
717 | ** Display whatever was received on stdout.
718 | */
719 | if ( verbose )
720 | {
721 | ssize_t rBytes = count;
722 | fprintf( stderr,
723 | "%s: UDP datagram received (%d bytes).\n",
724 | pgmName,
725 | count );
726 | while ( count > 0 )
727 | {
728 | fputc( bfr[ rBytes - count-- ],
729 | stdout );
730 | }
731 | if ( bfr[ rBytes-1 ] != '\n' )
732 | fputc( '\n', stdout ); /* Newline also flushes stdout. */
733 | /*
734 | ** Display the socket address of the remote client. Address-
735 | ** independent fields first.
736 | */
737 | fprintf( stderr,
738 | "Remote client's sockaddr info:\n"
739 | " sa_family = %d (AF_INET = %d, AF_INET6 = %d)\n"
740 | " addr len = %d (sockaddr_in = %d, "
741 | "sockaddr_in6 = %d)\n",
742 | sadr->sa_family,
743 | AF_INET,
744 | AF_INET6,
745 | sadrLen,
746 | sizeof( struct sockaddr_in ),
747 | sizeof( struct sockaddr_in6 ) );
748 | /*
749 | ** Display the address-specific information.
750 | */
751 | getnameinfo( sadr,
752 | sadrLen,
753 | hostBfr,
754 | sizeof( hostBfr ),
755 | servBfr,
756 | sizeof( servBfr ),
757 | NI_NUMERICHOST | NI_NUMERICSERV );
758 | switch ( sadr->sa_family )
759 | {
760 | case AF_INET: /* IPv4 address. */
761 | {
762 | struct sockaddr_in *p = (struct sockaddr_in*) sadr;
763 | fprintf( stderr,
764 | " sin_addr = sin_family: %d\n"
765 | " sin_addr: %s\n"
766 | " sin_port: %s\n",
767 | p->sin_family,
768 | hostBfr,
769 | servBfr );
770 | break;
771 | } /* End CASE of IPv4 address. */
772 | case AF_INET6: /* IPv6 address. */
773 | {
774 | struct sockaddr_in6 *p = (struct sockaddr_in6*) sadr;
775 | fprintf( stderr,
776 | " sin6_addr = sin6_family: %d\n"
777 | " sin6_addr: %s\n"
778 | " sin6_port: %s\n"
779 | " sin6_flowinfo: %d\n"
780 | " sin6_scope_id: %d\n",
781 | p->sin6_family,
782 | hostBfr,
783 | servBfr,
784 | p->sin6_flowinfo,
785 | p->sin6_scope_id );
786 | break;
787 | } /* End CASE of IPv6 address. */
788 | default: /* Can never get here, but for completeness. */
789 | {
790 | fprintf( stderr,
791 | "%s (line %d): ERROR - Unknown address "
792 | "family (%d).\n",
793 | pgmName,
794 | __LINE__,
795 | sadr->sa_family );
796 | break;
797 | } /* End DEFAULT case (unknown address family). */
798 | } /* End SWITCH on address family. */
799 | } /* End IF verbose mode. */
800 | /*
801 | ** Send the PIT to the client.
802 | */
803 | wBytes = timeLen;
804 | while ( wBytes > 0 )
805 | {
806 | do
807 | {
808 | count = sendto( desc[ idx ].fd,
809 | timeStr,
810 | wBytes,
811 | 0,
812 | sadr, /* Address & address length */
813 | sadrLen ); /* received in recvfrom(). */
814 | } while ( ( count < 0 ) && ( errno == EINTR ) );
815 | CHK( count ); /* Check for a bona fide error. */
816 | wBytes -= count;
817 | } /* End WHILE there is data to send. */
818 | } /* End ELSE a UDP datagram is available. */
819 | desc[ idx ].revents = 0; /* Clear the returned poll events. */
820 | } /* End FOR each socket descriptor. */
821 | } /* End WHILE forever. */
822 | } /* End pit() */
823 |
824 |
--------------------------------------------------------------------------------
/read_telemetry:
--------------------------------------------------------------------------------
1 | #
2 | #
3 | # The format is:
4 | #
5 | # All fields are space delimited.
6 | # A # symbol in column 1 indicates a comment.
7 | # First field: Byte offset within the file.
8 | # Second field: Size in bytes of the I/O operation.
9 | # Third field: Number of milliseconds to delay before I/O operation.
10 | #
11 | # This is an example of sequential 64k reader with 2 milliseconds
12 | # before each read.
13 | #
14 | 0 65536 2
15 | 65536 65536 2
16 | 131072 65536 2
17 | 196608 65536 2
18 | 262144 65536 2
19 | 327680 65536 2
20 | 393216 65536 2
21 | 458752 65536 2
22 | 524288 65536 2
23 | 589824 65536 2
24 | 655360 65536 2
25 | 720896 65536 2
26 | 786432 65536 2
27 | 851968 65536 2
28 | 917504 65536 2
29 | 983040 65536 2
30 |
--------------------------------------------------------------------------------
/report.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | #
3 | # arguments: one of more report files
4 | #
5 | # Christian Mautner , 2005-10-31
6 | #
7 | # This script is based loosely on the Generate_Graph set
8 | # of scripts that come with iozone, but is a complete re-write
9 | #
10 | # The main reason to write this was the need to compare the behaviour of
11 | # two or more different setups, for tuning filesystems or
12 | # comparing different pieces of hardware.
13 | #
14 | # This script is in the public domain, too short and too trivial
15 | # to deserve a copyright.
16 | #
17 | # Simply run iozone like, for example, ./iozone -a -g 4G > config1.out (if your machine has 4GB)
18 | # and then run perl report.pl config1.out
19 | # or get another report from another box into config2.out and run
20 | # perl report.pl config1.out config2.out
21 | # the look in the report_* directory for .png
22 | #
23 | # If you don't like png or the graphic size, search for "set terminal" in this file and put whatever gnuplot
24 | # terminal you want. Note I've also noticed that gnuplot switched the set terminal png syntax
25 | # a while back, you might need "set terminal png small size 900,700"
26 | #
27 |
28 |
29 | @Reports=@ARGV;
30 |
31 | die "usage: $0 [...]\n" if not @Reports or grep (m|^-|, @Reports);
32 |
33 | die "report files must be in current directory" if grep (m|/|, @Reports);
34 |
35 | %columns=(
36 | 'write' =>3,
37 | 'read' =>5,
38 | 'rewrite' =>4,
39 | 'reread' =>6,
40 | 'randread' =>7,
41 | 'randwrite' =>8,
42 | 'bkwdread' =>9,
43 | 'recrewrite'=>10,
44 | 'strideread'=>11,
45 | 'fwrite' =>12,
46 | 'frewrite' =>13,
47 | 'fread' =>14,
48 | 'freread' =>15,
49 | );
50 |
51 | #
52 | # create output directory. the name is the concatenation
53 | # of all report file names (minus the file extension, plus
54 | # prefix report_)
55 | #
56 | $outdir="report_".join("_",map{/([^\.]+)(\..*)?/ && $1}(@Reports));
57 |
58 | print STDERR "Output directory: $outdir ";
59 |
60 | if ( -d $outdir )
61 | {
62 | print STDERR "(removing old directory) ";
63 | system "rm -rf $outdir";
64 | }
65 |
66 | mkdir $outdir or die "cannot make directory $outdir";
67 |
68 | print STDERR "done.\nPreparing data files...";
69 |
70 | foreach $report (@Reports)
71 | {
72 | open(I, $report) or die "cannot open $report for reading";
73 | $report=~/^([^\.]+)/;
74 | $datafile="$1.dat";
75 | push @datafiles, $datafile;
76 | open(O, ">$outdir/$datafile") or die "cannot open $outdir/$datafile for writing";
77 | open(O2, ">$outdir/2d-$datafile") or die "cannot open $outdir/$datafile for writing";
78 | while()
79 | {
80 | next unless ( /^[\s\d]+$/ );
81 | @split = split();
82 | next unless ( @split == 15 );
83 | print O;
84 | print O2 if $split[1] == 16384 or $split[0] == $split[1];
85 | }
86 | close I, O, O2;
87 | }
88 |
89 | print STDERR "done.\nGenerating graphs:";
90 |
91 | foreach $column (keys %columns)
92 | {
93 | print STDERR " $column";
94 |
95 | open(G, ">$outdir/$column.do") or die "cannot open $outdir/$column.do for writing";
96 | print G qq{
97 | set title "Iozone performance: $column"
98 | set grid lt 2 lw 1
99 | set surface
100 | set parametric
101 | set xtics
102 | set ytics
103 | set logscale x 2
104 | set logscale y 2
105 | set autoscale z
106 | set xrange [2.**5:2.**24]
107 | set xlabel "File size in KBytes"
108 | set ylabel "Record size in Kbytes"
109 | set zlabel "Kbytes/sec"
110 | set data style lines
111 | set dgrid3d 80,80,3
112 | #set terminal png small picsize 900 700
113 | set terminal png small size 900 700
114 | set output "$column.png"
115 | };
116 |
117 | print G "splot ". join(", ", map{qq{"$_" using 1:2:$columns{$column} title "$_"}}(@datafiles));
118 |
119 | print G "\n";
120 |
121 | close G;
122 |
123 | open(G, ">$outdir/2d-$column.do") or die "cannot open $outdir/$column.do for writing";
124 | print G qq{
125 | set title "Iozone performance: $column"
126 | #set terminal png small picsize 450 350
127 | set terminal png small size 450 350
128 | set logscale x
129 | set xlabel "File size in KBytes"
130 | set ylabel "Kbytes/sec"
131 | set output "2d-$column.png"
132 | };
133 |
134 | print G "plot ". join(", ", map{qq{"2d-$_" using 1:$columns{$column} title "$_" with lines}}(@datafiles));
135 |
136 | print G "\n";
137 |
138 | close G;
139 |
140 | if ( system("cd $outdir && gnuplot $column.do && gnuplot 2d-$column.do") )
141 | {
142 | print STDERR "(failed) ";
143 | }
144 | else
145 | {
146 | print STDERR "(ok) ";
147 | }
148 | }
149 |
150 | print STDERR "done.\n";
151 |
152 |
--------------------------------------------------------------------------------
/spec.in:
--------------------------------------------------------------------------------
1 | Summary: Iozone Filesystem Benchmark
2 | Name: iozone
3 | Version: 3
4 | Release: 347
5 | License: Freeware
6 | Group: Applications/Engineering
7 | Source: %{name}%{version}_%{release}.tar
8 | Buildroot: /var/tmp/%{name}-buildroot
9 |
10 | %description
11 | IOzone is a filesystem benchmark tool. The benchmark generates and
12 | measures a variety of file operations. Iozone has been ported to many machines and runs under many operating systems.
13 |
14 | Iozone is useful for performing a broad filesystem analysis of a vendors
15 | computer platform. The benchmark tests file I/O performance for the following
16 | operations: Read, write, re-read, re-write, read backwards, read strided,
17 | fread, fwrite, random read, pread ,mmap, aio_read, aio_write.
18 |
19 |
20 | ##
21 | ## PREP
22 | ##
23 | %prep
24 |
25 | ##
26 | ## SETUP and PATCH
27 | ##
28 | %setup -n iozone3_347/src/current
29 |
30 |
31 | ##
32 | ## BUILD
33 | ##
34 | ##
35 | ## BUILD
36 | ##
37 | %build
38 | %ifarch %{ix86}
39 | make linux
40 | %else
41 | %ifarch x86_64
42 | make linux-AMD64
43 | %else
44 | %ifarch ia64
45 | make linux-ia64
46 | %else
47 | %ifarch ppc
48 | make linux-powerpc
49 | %else
50 | %ifarch ppc64
51 | make linux-powerpc64
52 | %else
53 | %ifarch s390
54 | make linux-S390
55 | %else
56 | %ifarch s390x
57 | make linux-S390X
58 | %endif
59 | %endif
60 | %endif
61 | %endif
62 | %endif
63 | %endif
64 | %endif
65 |
66 | ##
67 | ## INSTALL
68 | ##
69 | %install
70 | mkdir -p $RPM_BUILD_ROOT/opt/iozone/bin
71 | cp $RPM_BUILD_DIR/iozone3_347/src/current/iozone $RPM_BUILD_ROOT/opt/iozone/bin/
72 | cp $RPM_BUILD_DIR/iozone3_347/src/current/fileop $RPM_BUILD_ROOT/opt/iozone/bin/
73 | cp $RPM_BUILD_DIR/iozone3_347/src/current/pit_server $RPM_BUILD_ROOT/opt/iozone/bin/
74 | cp $RPM_BUILD_DIR/iozone3_347/src/current/Generate_Graphs $RPM_BUILD_ROOT/opt/iozone/bin/
75 | cp $RPM_BUILD_DIR/iozone3_347/src/current/gengnuplot.sh $RPM_BUILD_ROOT/opt/iozone/bin/
76 | cp $RPM_BUILD_DIR/iozone3_347/src/current/gnu3d.dem $RPM_BUILD_ROOT/opt/iozone/bin/
77 |
78 | mkdir -p $RPM_BUILD_ROOT/opt/iozone/docs
79 | cp $RPM_BUILD_DIR/iozone3_347/docs/IOzone_msword_98.pdf $RPM_BUILD_ROOT/opt/iozone/docs/
80 | cp $RPM_BUILD_DIR/iozone3_347/docs/Run_rules.doc $RPM_BUILD_ROOT/opt/iozone/docs/
81 | cp $RPM_BUILD_DIR/iozone3_347/docs/IOzone_msword_98.doc $RPM_BUILD_ROOT/opt/iozone/docs/
82 | cp $RPM_BUILD_DIR/iozone3_347/docs/Iozone_ps.gz $RPM_BUILD_ROOT/opt/iozone/docs/
83 | cp $RPM_BUILD_DIR/iozone3_347/src/current/Gnuplot.txt $RPM_BUILD_ROOT/opt/iozone/docs/
84 |
85 | mkdir -p $RPM_BUILD_ROOT/opt/iozone/man/man1
86 | cp $RPM_BUILD_DIR/iozone3_347/docs/iozone.1 $RPM_BUILD_ROOT/opt/iozone/man/man1/
87 |
88 |
89 | ##
90 | ## FILES
91 | ##
92 | %files
93 | %attr(755,root,root) /opt/
94 |
95 |
96 | ##
97 | ## CLEAN
98 | ##
99 | %clean
100 | rm -rf $RPM_BUILD_ROOT
101 |
--------------------------------------------------------------------------------
/write_telemetry:
--------------------------------------------------------------------------------
1 | #
2 | #
3 | # The format is:
4 | #
5 | # All fields are space delimited.
6 | # A # symbol in column 1 indicates a comment.
7 | # First field: Byte offset within the file.
8 | # Second field: Size in bytes of the I/O operation.
9 | # Third field: Number of milliseconds to delay before I/O operation.
10 | #
11 | # This is an example of sequential 64k writer with 2 milliseconds
12 | # before each write.
13 | #
14 | 0 65536 2
15 | 65536 65536 2
16 | 131072 65536 2
17 | 196608 65536 2
18 | 262144 65536 2
19 | 327680 65536 2
20 | 393216 65536 2
21 | 458752 65536 2
22 | 524288 65536 2
23 | 589824 65536 2
24 | 655360 65536 2
25 | 720896 65536 2
26 | 786432 65536 2
27 | 851968 65536 2
28 | 917504 65536 2
29 | 983040 65536 2
30 |
--------------------------------------------------------------------------------