1#!/usr/bin/perl 2# 3# Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README 4# 5 6# 7# Mongo.pl is reiserfs benchmark. 8# 9# To run please use run_mongo script or : 10# 11# # ./mongo.pl reiserfs /dev/xxxx /testfs log1 5 12# or 13# # ./mongo.pl ext2 /dev/xxxx /testfs log2 5 14# 15# 5 - number of processes, you can set any number here 16# 17# Test will format partition /dev/xxxx by 'mkreiserfs' or 'mke2fs' 18# mount it and run given number of processes during each phase : 19# Create, Copy, Symlinks, Read, Stats, Rename and Delete. 20# 21# Also, the program calc fragmentations after Create and Copy phases: 22# Fragm = number_of_fragments / number_of_files 23# (Current version use the files more than 16KB to calc Fragm.) 24# 25# You can find the same results in files : log, log.tbl, log_table 26# 27# log - raw results 28# log.tbl - results for compare program 29# log_table - results in table form 30# 31 32$EXTENDED_STATISTICS = 1; 33 34 35use POSIX; 36use File::stat; 37 38sub print_usage { 39 40 print "\nUsage: mongo.pl <filesystem> <device>"; 41 print " <mount_point> <log> <processes>\n"; 42 43 print "<filesystem> - the name of filesystem [reiserfs|ext2]\n"; 44 print "<device> - the device for benchmark (e.g. /dev/hda9)\n"; 45 print "<mount_point> - mount-point for the filesystem"; 46 print " (e.g. /mnt/testfs)\n"; 47 print "<log> - the name prefix for benchmark results\n"; 48 print "<processes> - the number of benchmark processes\n"; 49 50 print "\nexamples:\n"; 51 print "mongo.pl reiserfs /dev/hda9 /testfs reiserfs_results 1\n"; 52 print "mongo.pl ext2 /dev/hda9 /testfs ext2_results 1\n"; 53 54 print "\nThe results will be put in ./results directory\n"; 55} 56 57 58#------- Subroutines declaration -------- 59sub make_fsys; 60sub mongo_x_process; 61sub mongo_launcher; 62sub set_params; 63 64#------- main() ------------------------- 65 66if ( $#{ARGV} != 4 ) { 67 print_usage; 68 exit(0); 69 } 70 71#-------------------------------------------- 72# Set working directories 73#-------------------------------------------- 74$TOPDIR = "$ENV{PWD}"; 75 76$RESDIR = "${TOPDIR}/results"; 77$HTMLDIR = "${RESDIR}/html"; 78 79$FILESYSTEM = $ARGV[0]; 80$DEVICE = $ARGV[1]; 81$TESTDIR = $ARGV[2]; 82$PROCESSES = $ARGV[4]; 83 84$LOGFILE = "${RESDIR}/${ARGV[3]}"; 85$LOGFILE2 = "${LOGFILE}_table"; 86$LOGFILE3 = "${LOGFILE}.tbl"; 87 88$TMPFILE = "${RESDIR}/mongo_tmp"; 89$nproc = $PROCESSES; 90$READIT = "${TOPDIR}/mongo_read"; 91$SLINKS = "${TOPDIR}/mongo_slinks"; 92 93#-------- reiser_fract_tree parameters---------------- 94$x1mb = 1024 * 1024; 95$x2mb = 2 * $x1mb; 96$x3mb = 3 * $x1mb; 97 98$x5mb = 5 * $x1mb; 99$x50mb = 50 * $x1mb; 100$x100mb = 100 * $x1mb; 101 102# Total amount of bytes in all files on test partition 103#----------------------------------------------------- 104 105$small_bytes = $x50mb; 106$medium_bytes = $x100mb; 107$big_bytes = $x100mb; 108$large_bytes = $x100mb; 109 110# Median size of files in bytes for first tree to create 111#------------------------------------------------------- 112$small_size = 100; 113$medium_size = 1000; 114$big_size = 10000; 115$large_size = 100000; 116 117# Keep the largest file to one fifth (100 million bytes) 118# of the total tree size. 119#------------------------------------------------------- 120$max_file_size = 100000000; 121 122# Yuri Shevchuk says that 0 is the median size 123# in real life, so I believe him. 124#---------------------------------------------- 125$median_dir_nr_files = 0; 126 127# This should be larger, change once done testing. 128#------------------------------------------------- 129$bytes_to_consume = 10000000; 130 131$median_file_size = 100; 132$max_file_size = 1000000; 133 134$median_dir_nr_files = 100; 135$max_directory_nr_files = 10000; 136 137$median_dir_branching = 0; 138$max_dir_branching = 1; 139 140# This should be varying, someday.... 141#------------------------------------ 142$write_buffer_size = 4096; 143 144@numb_of_bytes = ($small_bytes, $medium_bytes, $big_bytes, $large_bytes); 145@size_of_files = ($small_size, $medium_size, $big_size, $large_size); 146 147$reiser_fract_tree_rep_counter = 3; 148 149$total_params = $#{numb_of_bytes}; 150 151#... Make directories for results 152#-------------------------------- 153unless (-e $RESDIR) { 154 print "Creating dir: ${RESDIR} \n"; 155 system("mkdir $RESDIR"); 156} 157 158unless ( -e $HTMLDIR ) { 159 print "Creating dir: ${HTMLDIR} \n"; 160 system("mkdir $HTMLDIR"); 161} 162 163#... Compile *.c files if it is necessary 164#---------------------------------------- 165sub compile 166{ 167 my $file = shift @_; 168 my $opt = shift @_ if @_ ; 169 my $cfile = $file . ".c"; 170 die "source file \"${cfile}\" does not exist" unless (-e "$cfile"); 171 if ( -e "$file" && (stat("$file")->mtime >= stat("$cfile")->mtime)) { 172 print "$file is up to date ...\n"; 173 } else { 174 print "Compiling ${cfile} ...\n"; 175 system ("gcc $cfile -o $file $opt"); 176 } 177} 178 179compile("reiser_fract_tree", "-lm"); 180compile("mongo_slinks"); 181compile("mongo_read"); 182compile("map5"); 183compile("summ"); 184compile("mongo_compare"); 185 186#... Check the command string parameters 187#--------------------------------------- 188unless ( ($FILESYSTEM eq "reiserfs") or ($FILESYSTEM eq "ext2") ) { 189 print "mongo.pl: not valid filesystem name: ${FILESYSTEM} \n"; 190 print "Usage: mongo.pl <filesystem> <device> <mount_point> <log> <repeat>\n"; 191 exit(0); 192} 193 194unless ( -b $DEVICE ) { 195 print "mongo.pl: not valid device: ${DEVICE} \n"; 196 print "Usage: mongo.pl <filesystem> <device> <mount_point> <log> <repeat>\n"; 197 exit(0); 198} 199 200 201#------- Subroutines -------------------------------------- 202#---------------------------------------------------------- 203sub get_blocks_usage ($) { 204 my ($mp) = @_; 205 my $df = `df -k $mp | tail -n 1`; 206 chomp $df; 207 my @items = split / +/, $df; 208 return $items[2]; 209} 210 211sub make_fsys { 212 213 system ("umount $TESTDIR") ; 214 215 if ( $FILESYSTEM eq "reiserfs" ) { 216 system("echo y | mkreiserfs $DEVICE") ; 217 system("mount -t reiserfs $DEVICE $TESTDIR") ; 218 } 219 220 if ( $FILESYSTEM eq "ext2" ) { 221 system("mke2fs $DEVICE") ; 222 system("mount $DEVICE $TESTDIR") ; 223 } 224} 225 226 227#------------------------------------------------------------------ 228# Mongo Launcher 229#------------------------------------------------------------------ 230sub mongo_launcher { 231 232 my ($phase_num, $phase_name, $cmd, $dir1, $dir2, $flag, $processes) = @_ ; 233 234 235 print "$phase_num.$phase_name files of median size $median_file_size bytes ($p processes)...\n"; 236 print LOG "********* Phase $phase_num: $phase_name files of median size $median_file_size bytes ($p processes) *********\n"; 237 $i=0; 238 $total=0; 239 240# eliminate the rep counter and the while 241 while ( $i < $reiser_fract_tree_rep_counter ) { 242 print "$phase_name : "; 243 print LOG "$phase_name : "; 244 $com = ""; 245 $pp=$processes; 246 247 $j=0; 248 while ($pp > 0) { 249 $pp--; 250 251# the fact that this if statement was necessary indicated you 252# attempted excessive generalization and abstraction where it was not 253# natural to the task that makes the code harder to understand. put 254# every command on one line to execute. I like it when I can read a 255# one line command and see what that phase of the test does instead of 256# looking in many places throughout the code. 257 258 if ($phase_num == 1) { 259 $com .= "$cmd $dir1-$i-$j $flag"; 260 } 261 elsif ($phase_num == 2) { 262 $com .= "$cmd $dir1-$i-$j $dir2-$i-$j"; 263 } 264 elsif ($phase_num == 3) { 265 $com .= "$cmd $dir1-$i-$j "."-type f | while read X; do echo \$X \$X.lnk ; done | $TOPDIR/mongo_slinks "; 266 } 267 elsif ($phase_num == 4) { 268 $com .= "$cmd"; 269 } 270 elsif ($phase_num == 5) { 271 $com .= "$cmd"; 272 } 273 elsif ($phase_num == 6) { 274 $com .= "$cmd $dir1-$i-$j -type f | perl -e 'while (<>) { chomp; rename (\$_, \"\$_.r\"); };'"; 275 #$com .= " & $cmd $dir2-$i-$j "."-type d -exec mv {} {}.r ';'"; 276 } 277 elsif ($phase_num == 7) { 278 if ($processes > 1) { 279 $com .= "$cmd $dir1-$i-$j & $cmd $dir2-$i-$j"; 280 } 281 else { 282 $com .= "$cmd $dir1-$i-$j ; $cmd $dir2-$i-$j"; 283 } 284 } 285 $com .= " & "; 286 $j++; 287 } 288 289 $com .= " wait"; 290 #print $com, "\n"; 291 292 @t=`(time -p $com) 2>&1`; 293 294 @tt = split ' ', $t[0]; 295 $res = $tt[1]; 296 unless ( $res =~ /\s*\d+/) { 297 print @t , "\n"; 298 print LOG @t, "\n"; 299 } else { 300 print LOG "$res sec.\n"; 301 print "$res sec.\n"; 302 } 303 304 $total += $res; 305 $i++; 306 } 307 308 print "total $phase_name time: $total sec.\n"; 309 print LOG "total $phase_name time: $total sec.\n"; 310 311 $ares[$phase_num]=$total; # ser array of results 312 313 if ($EXTENDED_STATISTICS) { 314 if( $phase_num < 3) { 315 $used = get_blocks_usage($TESTDIR) - $used0; 316 if ($phase_num == 1) { 317 $used1=$used; 318 }elsif($phase_num == 2){ 319 $used2=$used; 320 } 321 print "Used disk space (df) : $used KB\n"; 322 print LOG "Used disk space (df) : $used KB\n"; 323 324 open (FIND_PIPE, "find $TESTDIR|") || die "cannnot open pipe from \"find\": $!\n"; 325 $dirs = 0; 326 $files = 0; 327 $files16 = 0; 328 329 while(<FIND_PIPE>) { 330 chomp; 331 $st = lstat ($_); 332 if (S_ISDIR($st->mode)) { 333 $dirs ++; 334 } elsif (S_ISREG($st->mode)) { 335 $files ++; 336 $files16 ++ if ($st->size > 16384); 337 } 338 } 339 340 close (FIND_PIPE); 341 342 print "Total dirs: $dirs\n"; 343 print "Total files: $files\n"; 344 print LOG "Total dirs: $dirs\n"; 345 print LOG "Total files: $files\n"; 346 347 #$f=$frag; 348 $f16 = $files16; 349 $fr16 =`find $TESTDIR -type f -size +16k | xargs $TOPDIR/map5 | $TOPDIR/summ | tail -n 1 2>&1`; 350 @ff16= split ' ', $f16; 351 @ffr16= split ' ', $fr16; 352 $files16 = $ff16[0]; 353 $frag = $ffr16[0]; 354 $procent = $frag / $files16; 355 print "Total fragments : $frag \n"; 356 print LOG "Total fragments : $frag \n"; 357 358 printf "Fragments / files :%.3f\n", $procent; 359 printf LOG "Fragments / files :%.3f\n", $procent; 360 $frag_res[$phase_num]=$procent; # ser array of results 361 } 362 } 363 364 system("sync"); 365 print "\n"; 366 print LOG "\n"; 367 368} 369 370# and what is an x process? 371 372#------------------------------------------------------------------ 373# MONGO_X_PROCESS ( x is number of processes to run ) 374#------------------------------------------------------------------ 375sub mongo_x_process { 376 377 my ($processes) = @_ ; 378 $p = $processes; 379 380 make_fsys; # make and mount the file system 381 $used0 = get_blocks_usage($TESTDIR); 382 383 open LOG, ">>$LOGFILE" or die "Can not open log file $LOGFILE\n"; 384 open LOG2, ">>$LOGFILE2" or die "Can not open log file $LOGFILE2\n"; 385 open LOG3, ">>$LOGFILE3" or die "Can not open log file $LOGFILE2\n"; 386 387 print LOG "FILESYSTEM=$FILESYSTEM \n"; 388 389 print "\n"; 390 if($p == 1) { 391 print "mongo_single_process, the_set_of_param.N=$par_set_n of $total_params \n"; 392 print LOG "mongo_single_process, the_set_of_paramN=$par_set_n of $total_params \n"; 393 } elsif ($p > 1) { 394 print "mongo_multi_process ($p processes), the_set_of_param.N=$par_set_n of $total_params \n"; 395 print LOG "mongo_multi_process ($p processes), the_set_of_paramN=$par_set_n of $total_params \n"; 396 } 397 398 print "Results in file : $LOGFILE \n"; 399 print "\n"; 400 401 $dir1 = "$TESTDIR/testdir1"; 402 $dir2 = "$TESTDIR/testdir2"; 403 $flag = 0; 404 405 $cmd_1 = "$TOPDIR/reiser_fract_tree $bytes_to_consume $median_file_size $max_file_size $median_dir_nr_files $max_directory_nr_files $median_dir_branching $max_dir_branching $write_buffer_size"; 406 $cmd_2 = "cp -r"; 407 $cmd_3 = "find"; 408 $cmd_4 = "find $TESTDIR -type f | xargs $TOPDIR/mongo_read"; 409 $cmd_5 = "find $TESTDIR -type f > /dev/null"; # it should be enough for stat all files. -zam 410 $cmd_6 = "find"; #" $TESTDIR -type f -exec mv {} {}.r ';'"; 411 $cmd_7 = "rm -r"; 412 413 system("sync"); 414 $frag = 0; 415 mongo_launcher ( 1, "Create", $cmd_1, $dir1, $dir2, $flag, $p); # phase 1 416 mongo_launcher ( 2, "Copy ", $cmd_2, $dir1, $dir2, $flag, $p); # phase 2 417 mongo_launcher ( 3, "Slinks", $cmd_3, $dir1, $dir2, $flag, $p); # phase 3 418 mongo_launcher ( 4, "Read ", $cmd_4, $dir1, $dir2, $flag, $p); # phase 4 419 mongo_launcher ( 5, "Stats ", $cmd_5, $dir1, $dir2, $flag, $p); # phase 5 420 mongo_launcher ( 6, "Rename", $cmd_6, $dir1, $dir2, $flag, $p); # phase 6 421 mongo_launcher ( 7, "Delete", $cmd_7, $dir1, $dir2, $flag, $p); # phase 7 422 423 print LOG2 "\n"; 424 if ($processes > 1) { 425 print LOG2 "MONGO_MULTI_PROCESS ($processes processes) BENCHMARK RESULTS (time in sec.)\n"; 426 }else { 427 print LOG2 "MONGO_SINGLE_PROCESS BENCHMARK RESULTS (time in sec.)\n"; 428 } 429 print LOG2 " FILESYSTEM=$FILESYSTEM\n"; 430 print LOG2 " parameters: files=$files, base_size=$median_file_size bytes, dirs=$dirs\n"; 431 print LOG2 "--------------------------------------------------------------\n"; 432 print LOG2 "Create\tCopy\tSlink\tRead\tStats\tRename\tDelete\n"; 433 print LOG2 " time \ttime\ttime\ttime\ttime \t time \t time\n"; 434 print LOG2 "--------------------------------------------------------------\n"; 435 print LOG2 "$ares[1]\t$ares[2]\t$ares[3]\t$ares[4]\t$ares[5]\t$ares[6]\t$ares[7]\n"; 436 print LOG2 "--------------------------------------------------------------\n"; 437 print LOG2 "The size of files tree : \n"; 438 print LOG2 " after create = $used1 kb\n"; 439 print LOG2 " after copy = $used2 kb\n"; 440 print LOG2 "\n"; 441 442 443 print LOG3 "\n"; 444 if ($processes > 1) { 445 print LOG3 "MONGO_MULTI_PROCESS ($processes) \n"; 446 }else { 447 print LOG3 "MONGO_SINGLE_PROCESS \n"; 448 } 449 print LOG3 "parameters: \n"; 450 print LOG3 "files=$files \n"; 451 print LOG3 "base_size=$median_file_size bytes \n"; 452 print LOG3 "dirs=$dirs \n"; 453 print LOG3 "\n"; 454 455 print LOG3 "FSYS=$FILESYSTEM \n"; 456 print LOG3 "(time in sec.) \n"; 457 print LOG3 "Create : $ares[1]\n"; 458 print LOG3 "Fragm. : $frag_res[1]\n"; 459 print LOG3 "df : $used1\n\n"; 460 print LOG3 "Copy : $ares[2] \n"; 461 print LOG3 "Fragm. : $frag_res[2]\n"; 462 print LOG3 "df : $used2\n\n"; 463 print LOG3 "Slinks : $ares[3]\n"; 464 print LOG3 "Read : $ares[4]\n"; 465 print LOG3 "Stats : $ares[5]\n"; 466 print LOG3 "Rename : $ares[6] \n"; 467 print LOG3 "Delete : $ares[7]\n"; 468 469 print LOG3 "\n"; 470 471 472 if($processes > 1) { 473 print LOG "******* The end of mongo_multi_process *******"; 474 }else { 475 print LOG "******* The end of mongo_single_process *******"; 476 } 477} 478 479#--------------------------------------------------- 480# Set parameters 481#--------------------------------------------------- 482sub set_params { 483 my ($n) = @_ ; 484 485 $bytes_to_consume = $numb_of_bytes[$n]; 486 $median_file_size = $size_of_files[$n]; 487 488 #$max_file_size = 1000000; 489 490 #$median_dir_nr_files = 100; 491 #$max_directory_nr_files = 10000; 492 493 #$median_dir_branching = 0; 494 #$max_dir_branching = 1; 495 496} 497 498#---------------------------------------------------------- 499# TEST START 500#---------------------------------------------------------- 501 502 $par_set_n = 0; 503 foreach $fsize (@size_of_files) { 504 set_params ($par_set_n); 505 mongo_x_process( $nproc ); # run n processes 506 $par_set_n++; 507 } 508 system("umount $TESTDIR"); 509 exit; 510 511 512