Stxxl
1.4.0
|
00001 /*************************************************************************** 00002 * io/verify_disks.cpp 00003 * 00004 * Part of the STXXL. See http://stxxl.sourceforge.net 00005 * 00006 * Copyright (C) 2002-2003 Roman Dementiev <dementiev@mpi-sb.mpg.de> 00007 * Copyright (C) 2007-2010 Andreas Beckmann <beckmann@cs.uni-frankfurt.de> 00008 * 00009 * Distributed under the Boost Software License, Version 1.0. 00010 * (See accompanying file LICENSE_1_0.txt or copy at 00011 * http://www.boost.org/LICENSE_1_0.txt) 00012 **************************************************************************/ 00013 00014 /* 00015 example gnuplot command for the output of this program: 00016 (x-axis: disk offset in GiB, y-axis: bandwidth in MiB/s) 00017 00018 plot \ 00019 "disk.log" using ($3/1024):($14) w l title "read", \ 00020 "disk.log" using ($3/1024):($7) w l title "write" 00021 */ 00022 00023 #include <iomanip> 00024 #include <vector> 00025 00026 #include <stxxl/io> 00027 #include <stxxl/aligned_alloc> 00028 #include <stxxl/timer> 00029 00030 00031 using stxxl::request_ptr; 00032 using stxxl::file; 00033 using stxxl::timer; 00034 using stxxl::timestamp; 00035 00036 00037 #ifdef BLOCK_ALIGN 00038 #undef BLOCK_ALIGN 00039 #endif 00040 00041 #define BLOCK_ALIGN 4096 00042 00043 //#define NOREAD 00044 00045 //#define DO_ONLY_READ 00046 00047 #define POLL_DELAY 1000 00048 00049 #define RAW_ACCESS 00050 00051 //#define WATCH_TIMES 00052 00053 00054 #ifdef WATCH_TIMES 00055 void watch_times(request_ptr reqs[], unsigned n, double * out) 00056 { 00057 bool * finished = new bool[n]; 00058 unsigned count = 0; 00059 for (unsigned i = 0; i < n; i++) 00060 finished[i] = false; 00061 00062 while (count != n) 00063 { 00064 usleep(POLL_DELAY); 00065 unsigned i = 0; 00066 for (i = 0; i < n; i++) 00067 { 00068 if (!finished[i]) 00069 if (reqs[i]->poll()) 00070 { 00071 finished[i] = true; 00072 out[i] = timestamp(); 00073 count++; 00074 } 00075 } 00076 } 00077 delete[] finished; 00078 } 00079 00080 00081 void out_stat(double start, double end, double * times, unsigned n, const std::vector<std::string> & names) 00082 { 00083 for (unsigned i = 0; i < n; i++) 00084 { 00085 std::cout << i << " " << names[i] << " took " << 00086 100. * (times[i] - start) / (end - start) << " %" << std::endl; 00087 } 00088 } 00089 #endif 00090 00091 #define MB (1024 * 1024) 00092 #define GB (1024 * 1024 * 1024) 00093 00094 void usage(const char * argv0) 00095 { 00096 std::cout << "Usage: " << argv0 << " pattern offset length [block_size [batch_size]] [nd] [r|w] [--] diskfile..." << std::endl; 00097 std::cout << " 'pattern' is a 32bit unsigned value like '0', '0xffffffff', ..." << std::endl; 00098 std::cout << " starting 'offset' and 'length' are given in GiB," << std::endl; 00099 std::cout << " 'block_size' (default 8) in MiB (in B if it has a suffix B)," << std::endl; 00100 std::cout << " increase 'batch_size' (default 1)" << std::endl; 00101 std::cout << " to submit several I/Os at once and report average rate" << std::endl; 00102 #ifdef RAW_ACCESS 00103 std::cout << " open mode: includes O_DIRECT unless the 'nd' flag is given" << std::endl; 00104 #endif 00105 std::cout << " ops: write and reread (default), (r)ead only, (w)rite only" << std::endl; 00106 std::cout << " length == 0 implies till end of space (please ignore the write error)" << std::endl; 00107 std::cout << " Memory consumption: block_size * batch_size * num_disks" << std::endl; 00108 exit(-1); 00109 } 00110 00111 // returns throughput in MiB/s 00112 inline double throughput(double bytes, double seconds) 00113 { 00114 if (seconds == 0.0) 00115 return 0.0; 00116 return bytes / (1024 * 1024) / seconds; 00117 } 00118 00119 int main(int argc, char * argv[]) 00120 { 00121 if (argc < 5) 00122 usage(argv[0]); 00123 00124 unsigned pattern = strtol(argv[1], NULL, 0); 00125 stxxl::int64 offset = stxxl::int64(GB) * stxxl::int64(atoi(argv[2])); 00126 stxxl::int64 length = stxxl::int64(GB) * stxxl::int64(atoi(argv[3])); 00127 stxxl::int64 endpos = offset + length; 00128 stxxl::int64 block_size = 0; 00129 stxxl::int64 batch_size = 0; 00130 00131 bool verify_failed = false; 00132 bool do_read = true, do_write = true; 00133 bool direct_io = true; 00134 int first_disk_arg = 4; 00135 00136 if (first_disk_arg < argc) 00137 block_size = atoi(argv[first_disk_arg]); 00138 if (block_size > 0) { 00139 int l = strlen(argv[first_disk_arg]); 00140 if (argv[first_disk_arg][l - 1] == 'B' || argv[first_disk_arg][l - 1] == 'b') { 00141 // suffix B means exact size 00142 } else { 00143 block_size *= MB; 00144 } 00145 ++first_disk_arg; 00146 } else { 00147 block_size = 8 * MB; 00148 } 00149 00150 if (first_disk_arg < argc) 00151 batch_size = atoi(argv[first_disk_arg]); 00152 if (batch_size > 0) { 00153 ++first_disk_arg; 00154 } else { 00155 batch_size = 1; 00156 } 00157 00158 if (first_disk_arg < argc && (strcmp("nd", argv[first_disk_arg]) == 0 || strcmp("ND", argv[first_disk_arg]) == 0)) { 00159 direct_io = false; 00160 ++first_disk_arg; 00161 } 00162 00163 if (first_disk_arg < argc && (strcmp("r", argv[first_disk_arg]) == 0 || strcmp("R", argv[first_disk_arg]) == 0)) { 00164 do_write = false; 00165 ++first_disk_arg; 00166 } else if (first_disk_arg < argc && (strcmp("w", argv[first_disk_arg]) == 0 || strcmp("W", argv[first_disk_arg]) == 0)) { 00167 do_read = false; 00168 ++first_disk_arg; 00169 } 00170 00171 if (first_disk_arg < argc && strcmp("--", argv[first_disk_arg]) == 0) { 00172 ++first_disk_arg; 00173 } 00174 00175 std::vector<std::string> disks_arr; 00176 00177 if (!(first_disk_arg < argc)) 00178 usage(argv[0]); 00179 00180 for (int ii = first_disk_arg; ii < argc; ii++) 00181 { 00182 std::cout << "# Add disk: " << argv[ii] << std::endl; 00183 disks_arr.push_back(argv[ii]); 00184 } 00185 00186 const unsigned ndisks = disks_arr.size(); 00187 00188 const stxxl::unsigned_type step_size = block_size * batch_size; 00189 const unsigned block_size_int = block_size / sizeof(int); 00190 const stxxl::int64 step_size_int = step_size / sizeof(int); 00191 00192 unsigned * buffer = (unsigned *)stxxl::aligned_alloc<BLOCK_ALIGN>(step_size * ndisks); 00193 file ** disks = new file *[ndisks]; 00194 request_ptr * reqs = new request_ptr[ndisks * batch_size]; 00195 #ifdef WATCH_TIMES 00196 double * r_finish_times = new double[ndisks]; 00197 double * w_finish_times = new double[ndisks]; 00198 #endif 00199 double totaltimeread = 0, totaltimewrite = 0; 00200 stxxl::int64 totalsizeread = 0, totalsizewrite = 0; 00201 00202 for (unsigned i = 0; i < ndisks * step_size_int; i++) 00203 buffer[i] = pattern; 00204 00205 for (unsigned i = 0; i < ndisks; i++) 00206 { 00207 int openmode = file::CREAT | file::RDWR; 00208 if (direct_io) { 00209 #ifdef RAW_ACCESS 00210 openmode |= file::DIRECT; 00211 #endif 00212 } 00213 00214 #ifdef BOOST_MSVC 00215 disks[i] = new stxxl::wincall_file(disks_arr[i], openmode, i); 00216 #else 00217 disks[i] = new stxxl::syscall_file(disks_arr[i], openmode, i); 00218 #endif 00219 } 00220 00221 #ifdef DO_ONLY_READ 00222 do_write = false; 00223 #endif 00224 #ifdef NOREAD 00225 do_read = false; 00226 #endif 00227 00228 const char * myrev = "$Revision$"; 00229 const char * myself = strrchr(argv[0], '/'); 00230 if (!myself || !*(++myself)) 00231 myself = argv[0]; 00232 std::cout << "# " << myself << " " << myrev << std::endl; 00233 std::cout << "# Step size: " 00234 << step_size << " bytes per disk (" 00235 << batch_size << " block" << (batch_size == 1 ? "" : "s") << " of " 00236 << block_size << " bytes) pattern=0x" 00237 << std::hex << pattern << std::dec << std::endl; 00238 timer t_total(true); 00239 try { 00240 while (offset < endpos) 00241 { 00242 const stxxl::int64 current_step_size = std::min<stxxl::int64>(step_size, endpos - offset); 00243 const stxxl::int64 current_step_size_int = current_step_size / sizeof(int); 00244 const unsigned current_num_blocks = stxxl::div_ceil(current_step_size, block_size); 00245 00246 std::cout << "Disk offset " << std::setw(8) << offset / MB << " MiB: " << std::fixed; 00247 00248 double begin = timestamp(), end, elapsed; 00249 00250 if (do_write) { 00251 // write block number (512 byte blocks) into each block at position 42 * sizeof(unsigned) 00252 for (unsigned j = 42, b = offset >> 9; j < current_step_size_int; j += 512 / sizeof(unsigned), ++b) 00253 { 00254 for (unsigned i = 0; i < ndisks; i++) 00255 buffer[current_step_size_int * i + j] = b; 00256 } 00257 for (unsigned i = 0; i < ndisks; i++) 00258 { 00259 for (unsigned j = 0; j < current_num_blocks; j++) 00260 reqs[i * current_num_blocks + j] = 00261 disks[i]->awrite(buffer + current_step_size_int * i + j * block_size_int, 00262 offset + j * block_size, 00263 block_size, 00264 stxxl::default_completion_handler()); 00265 } 00266 00267 #ifdef WATCH_TIMES 00268 watch_times(reqs, ndisks, w_finish_times); 00269 #else 00270 wait_all(reqs, ndisks * current_num_blocks); 00271 #endif 00272 00273 end = timestamp(); 00274 elapsed = end - begin; 00275 totalsizewrite += current_step_size; 00276 totaltimewrite += elapsed; 00277 } else { 00278 elapsed = 0.0; 00279 } 00280 00281 #if 0 00282 std::cout << "WRITE\nDisks: " << ndisks 00283 << " \nElapsed time: " << end - begin 00284 << " \nThroughput: " << int(double(current_step_size * ndisks) / MB / (end - begin)) 00285 << " MiB/s \nPer one disk:" 00286 << int(double(current_step_size) / MB / (end - begin)) << " MiB/s" 00287 << std::endl; 00288 #endif 00289 00290 #ifdef WATCH_TIMES 00291 out_stat(begin, end, w_finish_times, ndisks, disks_arr); 00292 #endif 00293 std::cout << std::setw(2) << ndisks << " * " 00294 << std::setw(8) << std::setprecision(3) << (throughput(current_step_size, elapsed)) << " = " 00295 << std::setw(8) << std::setprecision(3) << (throughput(current_step_size, elapsed) * ndisks) << " MiB/s write,"; 00296 00297 00298 begin = timestamp(); 00299 00300 if (do_read) { 00301 for (unsigned i = 0; i < ndisks; i++) 00302 { 00303 for (unsigned j = 0; j < current_num_blocks; j++) 00304 reqs[i * current_num_blocks + j] = disks[i]->aread(buffer + current_step_size_int * i + j * block_size_int, 00305 offset + j * block_size, 00306 block_size, 00307 stxxl::default_completion_handler()); 00308 } 00309 00310 #ifdef WATCH_TIMES 00311 watch_times(reqs, ndisks, r_finish_times); 00312 #else 00313 wait_all(reqs, ndisks * current_num_blocks); 00314 #endif 00315 00316 end = timestamp(); 00317 elapsed = end - begin; 00318 totalsizeread += current_step_size; 00319 totaltimeread += elapsed; 00320 } else { 00321 elapsed = 0.0; 00322 } 00323 00324 #if 0 00325 std::cout << "READ\nDisks: " << ndisks 00326 << " \nElapsed time: " << end - begin 00327 << " \nThroughput: " << int(double(current_step_size * ndisks) / MB / (end - begin)) 00328 << " MiB/s \nPer one disk:" 00329 << int(double(current_step_size) / MB / (end - begin)) << " MiB/s" 00330 << std::endl; 00331 #endif 00332 00333 std::cout << std::setw(2) << ndisks << " * " 00334 << std::setw(8) << std::setprecision(3) << (throughput(current_step_size, elapsed)) << " = " 00335 << std::setw(8) << std::setprecision(3) << (throughput(current_step_size, elapsed) * ndisks) << " MiB/s read"; 00336 00337 #ifdef WATCH_TIMES 00338 out_stat(begin, end, r_finish_times, ndisks, disks_arr); 00339 #endif 00340 00341 if (do_read) { 00342 for (unsigned d = 0; d < ndisks; ++d) { 00343 for (unsigned s = 0; s < (current_step_size >> 9); ++s) { 00344 unsigned i = d * current_step_size_int + s * (512 / sizeof(unsigned)) + 42; 00345 unsigned b = (offset >> 9) + s; 00346 if (buffer[i] != b) { 00347 verify_failed = true; 00348 std::cout << "Error on disk " << d << " sector " << std::hex << std::setw(8) << b 00349 << " got: " << std::hex << std::setw(8) << buffer[i] << " wanted: " << std::hex << std::setw(8) << b 00350 << std::dec << std::endl; 00351 } 00352 buffer[i] = pattern; 00353 } 00354 } 00355 for (unsigned i = 0; i < ndisks * current_step_size_int; i++) 00356 { 00357 if (buffer[i] != pattern) 00358 { 00359 verify_failed = true; 00360 int ibuf = i / current_step_size_int; 00361 int pos = i % current_step_size_int; 00362 00363 std::cout << "Error on disk " << ibuf << " position " << std::hex << std::setw(8) << offset + pos * sizeof(int) 00364 << " got: " << std::hex << std::setw(8) << buffer[i] << " wanted: " << std::hex << std::setw(8) << pattern 00365 << std::dec << std::endl; 00366 00367 i = (ibuf + 1) * current_step_size_int; // jump to next 00368 } 00369 } 00370 } 00371 std::cout << std::endl; 00372 00373 offset += current_step_size; 00374 } 00375 } 00376 catch (const std::exception & ex) 00377 { 00378 std::cout << std::endl; 00379 STXXL_ERRMSG(ex.what()); 00380 } 00381 t_total.stop(); 00382 00383 std::cout << "=============================================================================================" << std::endl; 00384 // the following line of output is parsed by misc/diskbench-avgplot.sh 00385 std::cout << "# Average over " << std::setw(8) << stxxl::STXXL_MAX(totalsizewrite, totalsizeread) / MB << " MiB: "; 00386 std::cout << std::setw(2) << ndisks << " * " 00387 << std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite, totaltimewrite)) << " = " 00388 << std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite, totaltimewrite) * ndisks) << " MiB/s write,"; 00389 std::cout << std::setw(2) << ndisks << " * " 00390 << std::setw(8) << std::setprecision(3) << (throughput(totalsizeread, totaltimeread)) << " = " 00391 << std::setw(8) << std::setprecision(3) << (throughput(totalsizeread, totaltimeread) * ndisks) << " MiB/s read" 00392 << std::endl; 00393 if (totaltimewrite != 0.0) 00394 std::cout << "# Write time " << std::setw(8) << std::setprecision(3) << totaltimewrite << " s" << std::endl; 00395 if (totaltimeread != 0.0) 00396 std::cout << "# Read time " << std::setw(8) << std::setprecision(3) << totaltimeread << " s" << std::endl; 00397 std::cout << "# Non-I/O time " << std::setw(8) << std::setprecision(3) << (t_total.seconds() - totaltimewrite - totaltimeread) << " s, average throughput " 00398 << std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite + totalsizeread, t_total.seconds() - totaltimewrite - totaltimeread) * ndisks) << " MiB/s" 00399 << std::endl; 00400 std::cout << "# Total time " << std::setw(8) << std::setprecision(3) << t_total.seconds() << " s, average throughput " 00401 << std::setw(8) << std::setprecision(3) << (throughput(totalsizewrite + totalsizeread, t_total.seconds()) * ndisks) << " MiB/s" 00402 << std::endl; 00403 00404 #ifdef WATCH_TIMES 00405 delete[] r_finish_times; 00406 delete[] w_finish_times; 00407 #endif 00408 delete[] reqs; 00409 for (unsigned i = 0; i < ndisks; i++) 00410 delete disks[i]; 00411 delete[] disks; 00412 stxxl::aligned_dealloc<BLOCK_ALIGN>(buffer); 00413 00414 return verify_failed ? 1 : 0; 00415 } 00416 00417 // vim: et:ts=4:sw=4