blob: 1f7b21ff3a179658ff9c95c92d8dd04923d242aa [file] [log] [blame]
#!/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;