├── 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 | \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 | 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 | 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 |
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 "
207 |

3d-$column

[top]
208 | 3d-$column
209 |
233 |

2d-$column

[top]
234 | 2d-$column
235 |
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 | --------------------------------------------------------------------------------