C++ Program performs better when piped
- by ET1 Nerd
I haven't done any programming in a decade. I wanted to get back into it, so I made this little pointless program as practice.
The easiest way to describe what it does is with output of my --help codeblock:
./prng_bench --help
./prng_bench: usage: ./prng_bench $N $B [$T]
This program will generate an N digit base(B) random number until
all N digits are the same.
Once a repeating N digit base(B) number is found, the following statistics are displayed:
-Decimal value of all N digits.
-Time & number of tries taken to randomly find.
Optionally, this process is repeated T times.
When running multiple repititions, averages for all N digit base(B)
numbers are displayed at the end, as well as total time and total tries.
My "problem" is that when the problem is "easy", say a 3 digit base 10 number, and I have it do a large number of passes the "total time" is less when piped to grep. ie:
command ; command |grep took :
./prng_bench 3 10 999999 ; ./prng_bench 3 10 999999|grep took
....
Pass# 999999: All 3 base(10) digits = 3 base(10). Time: 0.00005 secs. Tries: 23
It took 191.86701 secs & 99947208 tries to find 999999 repeating 3 digit base(10) numbers.
An average of 0.00019 secs & 99 tries was needed to find each one.
It took 159.32355 secs & 99947208 tries to find 999999 repeating 3 digit base(10) numbers.
If I run the same command many times w/o grep time is always VERY close.
I'm using srand(1234) for now, to test. The code between my calls to clock_gettime() for start and stop do not involve any stream manipulation, which would obviously affect time. I realize this is an exercise in futility, but I'd like to know why it behaves this way.
Below is heart of the program. Here's a link to the full source on DB if anybody wants to compile and test. https://www.dropbox.com/s/6olqnnjf3unkm2m/prng_bench.cpp
clock_gettime() requires -lrt.
for (int pass_num=1; pass_num<=passes; pass_num++) { //Executes $passes # of times.
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &temp_time); //get time
start_time = timetodouble(temp_time); //convert time to double, store as start_time
for(i=1, tries=0; i!=0; tries++) { //loops until 'comparison for' fully completes. counts reps as 'tries'. <------------
for (i=0; i<Ndigits; i++) //Move forward through array. |
results[i]=(rand()%base); //assign random num of base to element (digit). |
/*for (i=0; i<Ndigits; i++) //---Debug Lines--------------- |
std::cout<<" "<<results[i]; //---a LOT of output.---------- |
std::cout << "\n"; //---Comment/decoment to disable/enable.*/ // |
for (i=Ndigits-1; i>0 && results[i]==results[0]; i--); //Move through array, != element breaks & i!=0, new digits drawn. -|
} //If all are equal i will be 0, nested for condition satisfied. -|
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &temp_time); //get time
draw_time = (timetodouble(temp_time) - start_time); //convert time to dbl, subtract start_time, set draw_time to diff.
total_time += draw_time; //add time for this pass to total.
total_tries += tries; //add tries for this pass to total.
/*Formated output for each pass:
Pass# ---: All -- base(--) digits = -- base(10) Time: ----.---- secs. Tries: ----- (LINE) */
std::cout<<"Pass# "<<std::setw(width_pass)<<pass_num<<": All "<<Ndigits<<" base("<<base<<") digits = "
<<std::setw(width_base)<<results[0]<<" base(10). Time: "<<std::setw(width_time)<<draw_time
<<" secs. Tries: "<<tries<<"\n";
}
if(passes==1) return 0; //No need for totals and averages of 1 pass.
/* It took ----.---- secs & ------ tries to find --- repeating -- digit base(--) numbers. (LINE)
An average of ---.---- secs & ---- tries was needed to find each one. (LINE)(LINE) */
std::cout<<"It took "<<total_time<<" secs & "<<total_tries<<" tries to find "
<<passes<<" repeating "<<Ndigits<<" digit base("<<base<<") numbers.\n"
<<"An average of "<<total_time/passes<<" secs & "<<total_tries/passes
<<" tries was needed to find each one. \n\n";
return 0;