| #!/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 <filesystem> <device>"; |
| print " <mount_point> <log> <processes>\n"; |
| |
| print "<filesystem> - the name of filesystem [reiserfs|ext2]\n"; |
| print "<device> - the device for benchmark (e.g. /dev/hda9)\n"; |
| print "<mount_point> - mount-point for the filesystem"; |
| print " (e.g. /mnt/testfs)\n"; |
| print "<log> - the name prefix for benchmark results\n"; |
| print "<processes> - 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 <filesystem> <device> <mount_point> <log> <repeat>\n"; |
| exit(0); |
| } |
| |
| unless ( -b $DEVICE ) { |
| print "mongo.pl: not valid device: ${DEVICE} \n"; |
| print "Usage: mongo.pl <filesystem> <device> <mount_point> <log> <repeat>\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(<FIND_PIPE>) { |
| 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; |
| |
| |