#!/usr/bin/perl # # Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README # # # Mongo.pl is reiserfs benchmark. # # To run please use run_mongo script or : # # # ./mongo.pl reiserfs /dev/xxxx /testfs log1 5 # or # # ./mongo.pl ext2 /dev/xxxx /testfs log2 5 # # 5 - number of processes, you can set any number here # # Test will format partition /dev/xxxx by 'mkreiserfs' or 'mke2fs' # mount it and run given number of processes during each phase : # Create, Copy, Symlinks, Read, Stats, Rename and Delete. # # Also, the program calc fragmentations after Create and Copy phases: # Fragm = number_of_fragments / number_of_files # (Current version use the files more than 16KB to calc Fragm.) # # You can find the same results in files : log, log.tbl, log_table # # log - raw results # log.tbl - results for compare program # log_table - results in table form # $EXTENDED_STATISTICS = 1; use POSIX; use File::stat; sub print_usage { print "\nUsage: mongo.pl "; print " \n"; print " - the name of filesystem [reiserfs|ext2]\n"; print " - the device for benchmark (e.g. /dev/hda9)\n"; print " - mount-point for the filesystem"; print " (e.g. /mnt/testfs)\n"; print " - the name prefix for benchmark results\n"; print " - the number of benchmark processes\n"; print "\nexamples:\n"; print "mongo.pl reiserfs /dev/hda9 /testfs reiserfs_results 1\n"; print "mongo.pl ext2 /dev/hda9 /testfs ext2_results 1\n"; print "\nThe results will be put in ./results directory\n"; } #------- Subroutines declaration -------- sub make_fsys; sub mongo_x_process; sub mongo_launcher; sub set_params; #------- main() ------------------------- if ( $#{ARGV} != 4 ) { print_usage; exit(0); } #-------------------------------------------- # Set working directories #-------------------------------------------- $TOPDIR = "$ENV{PWD}"; $RESDIR = "${TOPDIR}/results"; $HTMLDIR = "${RESDIR}/html"; $FILESYSTEM = $ARGV[0]; $DEVICE = $ARGV[1]; $TESTDIR = $ARGV[2]; $PROCESSES = $ARGV[4]; $LOGFILE = "${RESDIR}/${ARGV[3]}"; $LOGFILE2 = "${LOGFILE}_table"; $LOGFILE3 = "${LOGFILE}.tbl"; $TMPFILE = "${RESDIR}/mongo_tmp"; $nproc = $PROCESSES; $READIT = "${TOPDIR}/mongo_read"; $SLINKS = "${TOPDIR}/mongo_slinks"; #-------- reiser_fract_tree parameters---------------- $x1mb = 1024 * 1024; $x2mb = 2 * $x1mb; $x3mb = 3 * $x1mb; $x5mb = 5 * $x1mb; $x50mb = 50 * $x1mb; $x100mb = 100 * $x1mb; # Total amount of bytes in all files on test partition #----------------------------------------------------- $small_bytes = $x50mb; $medium_bytes = $x100mb; $big_bytes = $x100mb; $large_bytes = $x100mb; # Median size of files in bytes for first tree to create #------------------------------------------------------- $small_size = 100; $medium_size = 1000; $big_size = 10000; $large_size = 100000; # Keep the largest file to one fifth (100 million bytes) # of the total tree size. #------------------------------------------------------- $max_file_size = 100000000; # Yuri Shevchuk says that 0 is the median size # in real life, so I believe him. #---------------------------------------------- $median_dir_nr_files = 0; # This should be larger, change once done testing. #------------------------------------------------- $bytes_to_consume = 10000000; $median_file_size = 100; $max_file_size = 1000000; $median_dir_nr_files = 100; $max_directory_nr_files = 10000; $median_dir_branching = 0; $max_dir_branching = 1; # This should be varying, someday.... #------------------------------------ $write_buffer_size = 4096; @numb_of_bytes = ($small_bytes, $medium_bytes, $big_bytes, $large_bytes); @size_of_files = ($small_size, $medium_size, $big_size, $large_size); $reiser_fract_tree_rep_counter = 3; $total_params = $#{numb_of_bytes}; #... Make directories for results #-------------------------------- unless (-e $RESDIR) { print "Creating dir: ${RESDIR} \n"; system("mkdir $RESDIR"); } unless ( -e $HTMLDIR ) { print "Creating dir: ${HTMLDIR} \n"; system("mkdir $HTMLDIR"); } #... Compile *.c files if it is necessary #---------------------------------------- sub compile { my $file = shift @_; my $opt = shift @_ if @_ ; my $cfile = $file . ".c"; die "source file \"${cfile}\" does not exist" unless (-e "$cfile"); if ( -e "$file" && (stat("$file")->mtime >= stat("$cfile")->mtime)) { print "$file is up to date ...\n"; } else { print "Compiling ${cfile} ...\n"; system ("gcc $cfile -o $file $opt"); } } compile("reiser_fract_tree", "-lm"); compile("mongo_slinks"); compile("mongo_read"); compile("map5"); compile("summ"); compile("mongo_compare"); #... Check the command string parameters #--------------------------------------- unless ( ($FILESYSTEM eq "reiserfs") or ($FILESYSTEM eq "ext2") ) { print "mongo.pl: not valid filesystem name: ${FILESYSTEM} \n"; print "Usage: mongo.pl \n"; exit(0); } unless ( -b $DEVICE ) { print "mongo.pl: not valid device: ${DEVICE} \n"; print "Usage: mongo.pl \n"; exit(0); } #------- Subroutines -------------------------------------- #---------------------------------------------------------- sub get_blocks_usage ($) { my ($mp) = @_; my $df = `df -k $mp | tail -n 1`; chomp $df; my @items = split / +/, $df; return $items[2]; } sub make_fsys { system ("umount $TESTDIR") ; if ( $FILESYSTEM eq "reiserfs" ) { system("echo y | mkreiserfs $DEVICE") ; system("mount -t reiserfs $DEVICE $TESTDIR") ; } if ( $FILESYSTEM eq "ext2" ) { system("mke2fs $DEVICE") ; system("mount $DEVICE $TESTDIR") ; } } #------------------------------------------------------------------ # Mongo Launcher #------------------------------------------------------------------ sub mongo_launcher { my ($phase_num, $phase_name, $cmd, $dir1, $dir2, $flag, $processes) = @_ ; print "$phase_num.$phase_name files of median size $median_file_size bytes ($p processes)...\n"; print LOG "********* Phase $phase_num: $phase_name files of median size $median_file_size bytes ($p processes) *********\n"; $i=0; $total=0; # eliminate the rep counter and the while while ( $i < $reiser_fract_tree_rep_counter ) { print "$phase_name : "; print LOG "$phase_name : "; $com = ""; $pp=$processes; $j=0; while ($pp > 0) { $pp--; # the fact that this if statement was necessary indicated you # attempted excessive generalization and abstraction where it was not # natural to the task that makes the code harder to understand. put # every command on one line to execute. I like it when I can read a # one line command and see what that phase of the test does instead of # looking in many places throughout the code. if ($phase_num == 1) { $com .= "$cmd $dir1-$i-$j $flag"; } elsif ($phase_num == 2) { $com .= "$cmd $dir1-$i-$j $dir2-$i-$j"; } elsif ($phase_num == 3) { $com .= "$cmd $dir1-$i-$j "."-type f | while read X; do echo \$X \$X.lnk ; done | $TOPDIR/mongo_slinks "; } elsif ($phase_num == 4) { $com .= "$cmd"; } elsif ($phase_num == 5) { $com .= "$cmd"; } elsif ($phase_num == 6) { $com .= "$cmd $dir1-$i-$j -type f | perl -e 'while (<>) { chomp; rename (\$_, \"\$_.r\"); };'"; #$com .= " & $cmd $dir2-$i-$j "."-type d -exec mv {} {}.r ';'"; } elsif ($phase_num == 7) { if ($processes > 1) { $com .= "$cmd $dir1-$i-$j & $cmd $dir2-$i-$j"; } else { $com .= "$cmd $dir1-$i-$j ; $cmd $dir2-$i-$j"; } } $com .= " & "; $j++; } $com .= " wait"; #print $com, "\n"; @t=`(time -p $com) 2>&1`; @tt = split ' ', $t[0]; $res = $tt[1]; unless ( $res =~ /\s*\d+/) { print @t , "\n"; print LOG @t, "\n"; } else { print LOG "$res sec.\n"; print "$res sec.\n"; } $total += $res; $i++; } print "total $phase_name time: $total sec.\n"; print LOG "total $phase_name time: $total sec.\n"; $ares[$phase_num]=$total; # ser array of results if ($EXTENDED_STATISTICS) { if( $phase_num < 3) { $used = get_blocks_usage($TESTDIR) - $used0; if ($phase_num == 1) { $used1=$used; }elsif($phase_num == 2){ $used2=$used; } print "Used disk space (df) : $used KB\n"; print LOG "Used disk space (df) : $used KB\n"; open (FIND_PIPE, "find $TESTDIR|") || die "cannnot open pipe from \"find\": $!\n"; $dirs = 0; $files = 0; $files16 = 0; while() { chomp; $st = lstat ($_); if (S_ISDIR($st->mode)) { $dirs ++; } elsif (S_ISREG($st->mode)) { $files ++; $files16 ++ if ($st->size > 16384); } } close (FIND_PIPE); print "Total dirs: $dirs\n"; print "Total files: $files\n"; print LOG "Total dirs: $dirs\n"; print LOG "Total files: $files\n"; #$f=$frag; $f16 = $files16; $fr16 =`find $TESTDIR -type f -size +16k | xargs $TOPDIR/map5 | $TOPDIR/summ | tail -n 1 2>&1`; @ff16= split ' ', $f16; @ffr16= split ' ', $fr16; $files16 = $ff16[0]; $frag = $ffr16[0]; $procent = $frag / $files16; print "Total fragments : $frag \n"; print LOG "Total fragments : $frag \n"; printf "Fragments / files :%.3f\n", $procent; printf LOG "Fragments / files :%.3f\n", $procent; $frag_res[$phase_num]=$procent; # ser array of results } } system("sync"); print "\n"; print LOG "\n"; } # and what is an x process? #------------------------------------------------------------------ # MONGO_X_PROCESS ( x is number of processes to run ) #------------------------------------------------------------------ sub mongo_x_process { my ($processes) = @_ ; $p = $processes; make_fsys; # make and mount the file system $used0 = get_blocks_usage($TESTDIR); open LOG, ">>$LOGFILE" or die "Can not open log file $LOGFILE\n"; open LOG2, ">>$LOGFILE2" or die "Can not open log file $LOGFILE2\n"; open LOG3, ">>$LOGFILE3" or die "Can not open log file $LOGFILE2\n"; print LOG "FILESYSTEM=$FILESYSTEM \n"; print "\n"; if($p == 1) { print "mongo_single_process, the_set_of_param.N=$par_set_n of $total_params \n"; print LOG "mongo_single_process, the_set_of_paramN=$par_set_n of $total_params \n"; } elsif ($p > 1) { print "mongo_multi_process ($p processes), the_set_of_param.N=$par_set_n of $total_params \n"; print LOG "mongo_multi_process ($p processes), the_set_of_paramN=$par_set_n of $total_params \n"; } print "Results in file : $LOGFILE \n"; print "\n"; $dir1 = "$TESTDIR/testdir1"; $dir2 = "$TESTDIR/testdir2"; $flag = 0; $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"; $cmd_2 = "cp -r"; $cmd_3 = "find"; $cmd_4 = "find $TESTDIR -type f | xargs $TOPDIR/mongo_read"; $cmd_5 = "find $TESTDIR -type f > /dev/null"; # it should be enough for stat all files. -zam $cmd_6 = "find"; #" $TESTDIR -type f -exec mv {} {}.r ';'"; $cmd_7 = "rm -r"; system("sync"); $frag = 0; mongo_launcher ( 1, "Create", $cmd_1, $dir1, $dir2, $flag, $p); # phase 1 mongo_launcher ( 2, "Copy ", $cmd_2, $dir1, $dir2, $flag, $p); # phase 2 mongo_launcher ( 3, "Slinks", $cmd_3, $dir1, $dir2, $flag, $p); # phase 3 mongo_launcher ( 4, "Read ", $cmd_4, $dir1, $dir2, $flag, $p); # phase 4 mongo_launcher ( 5, "Stats ", $cmd_5, $dir1, $dir2, $flag, $p); # phase 5 mongo_launcher ( 6, "Rename", $cmd_6, $dir1, $dir2, $flag, $p); # phase 6 mongo_launcher ( 7, "Delete", $cmd_7, $dir1, $dir2, $flag, $p); # phase 7 print LOG2 "\n"; if ($processes > 1) { print LOG2 "MONGO_MULTI_PROCESS ($processes processes) BENCHMARK RESULTS (time in sec.)\n"; }else { print LOG2 "MONGO_SINGLE_PROCESS BENCHMARK RESULTS (time in sec.)\n"; } print LOG2 " FILESYSTEM=$FILESYSTEM\n"; print LOG2 " parameters: files=$files, base_size=$median_file_size bytes, dirs=$dirs\n"; print LOG2 "--------------------------------------------------------------\n"; print LOG2 "Create\tCopy\tSlink\tRead\tStats\tRename\tDelete\n"; print LOG2 " time \ttime\ttime\ttime\ttime \t time \t time\n"; print LOG2 "--------------------------------------------------------------\n"; print LOG2 "$ares[1]\t$ares[2]\t$ares[3]\t$ares[4]\t$ares[5]\t$ares[6]\t$ares[7]\n"; print LOG2 "--------------------------------------------------------------\n"; print LOG2 "The size of files tree : \n"; print LOG2 " after create = $used1 kb\n"; print LOG2 " after copy = $used2 kb\n"; print LOG2 "\n"; print LOG3 "\n"; if ($processes > 1) { print LOG3 "MONGO_MULTI_PROCESS ($processes) \n"; }else { print LOG3 "MONGO_SINGLE_PROCESS \n"; } print LOG3 "parameters: \n"; print LOG3 "files=$files \n"; print LOG3 "base_size=$median_file_size bytes \n"; print LOG3 "dirs=$dirs \n"; print LOG3 "\n"; print LOG3 "FSYS=$FILESYSTEM \n"; print LOG3 "(time in sec.) \n"; print LOG3 "Create : $ares[1]\n"; print LOG3 "Fragm. : $frag_res[1]\n"; print LOG3 "df : $used1\n\n"; print LOG3 "Copy : $ares[2] \n"; print LOG3 "Fragm. : $frag_res[2]\n"; print LOG3 "df : $used2\n\n"; print LOG3 "Slinks : $ares[3]\n"; print LOG3 "Read : $ares[4]\n"; print LOG3 "Stats : $ares[5]\n"; print LOG3 "Rename : $ares[6] \n"; print LOG3 "Delete : $ares[7]\n"; print LOG3 "\n"; if($processes > 1) { print LOG "******* The end of mongo_multi_process *******"; }else { print LOG "******* The end of mongo_single_process *******"; } } #--------------------------------------------------- # Set parameters #--------------------------------------------------- sub set_params { my ($n) = @_ ; $bytes_to_consume = $numb_of_bytes[$n]; $median_file_size = $size_of_files[$n]; #$max_file_size = 1000000; #$median_dir_nr_files = 100; #$max_directory_nr_files = 10000; #$median_dir_branching = 0; #$max_dir_branching = 1; } #---------------------------------------------------------- # TEST START #---------------------------------------------------------- $par_set_n = 0; foreach $fsize (@size_of_files) { set_params ($par_set_n); mongo_x_process( $nproc ); # run n processes $par_set_n++; } system("umount $TESTDIR"); exit;