Rate counter
You are encouraged to solve this task according to the task description, using any language you may know.
Counting the frequency at which something occurs is a common activity in measuring performance and managing resources. In this task, we assume that there is some job which we want to perform repeatedly, and we want to know how quickly these jobs are being performed.
Of interest is the code that performs the actual measurements. Any other code (such as job implementation or dispatching) that is required to demonstrate the rate tracking is helpful, but not the focus.
Multiple approaches are allowed (even preferable), so long as they can accomplish these goals:
- Run N seconds worth of jobs and/or Y jobs.
- Report at least three distinct times.
Be aware of the precision and accuracy limitations of your timing mechanisms, and document them if you can.
See also: System time, Time a function
Ada
Launch 6 jobs in parallel and record the elapsed time for each job. A variant
to get CPU times would use the package Ada.Execution_Time (Ada05).
The precision of measure is given by the value of System.Tick; on Windows value is 10 ms.
<lang Ada>with System; use System;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Unchecked_Deallocation; use Ada;
with Interfaces;
procedure Rate_Counter is
pragma Priority (Max_Priority);
package Duration_IO is new Fixed_IO (Duration);
Job_Nbr : constant := 6; -- adjust to your need subtype Job_Index is Natural range 1 .. Job_Nbr;
task type Job (ID : Job_Index) is pragma Priority (Default_Priority); entry Start; end Job;
type Job_Ptr is access Job; procedure Free is new Unchecked_Deallocation (Job, Job_Ptr);
Jobs : array (Job_Index) of Job_Ptr;
Done : Natural := 0; Completed : array (Job_Index) of Boolean := (others => False);
type Timings is array (Job_Index) of Calendar.Time; Start_T, Stop_T : Timings;
task body Job is Anchor : Interfaces.Integer_32; pragma Volatile (Anchor); -- necessary to avoid compiler optimization. begin accept Start;
for I in Interfaces.Integer_32'Range loop -- the job to do Anchor := I; end loop; end Job;
begin
for J in Job_Index'Range loop Jobs (J) := new Job (ID => J); -- create the jobs first, sync later end loop; for J in Job_Index'Range loop -- launch the jobs in parallel Start_T (J) := Calendar.Clock; -- get the start time Jobs (J).Start; -- priority settings necessary to regain control. end loop; -- Polling for the results / also possible to use a protected type. while not (Done = Job_Nbr) loop for J in Job_Index'Range loop if not Completed (J) and then Jobs (J)'Terminated then Stop_T (J) := Calendar.Clock; -- get the end time Put ("Job #" & Job_Index'Image (J) & " is finished. It took "); Duration_IO.Put (Stop_T (J) - Start_T (J), Fore => 3, Aft => 2); Put_Line (" seconds."); Completed (J) := True; Done := Done + 1; end if; end loop; delay System.Tick; -- according to the precision of the system clock end loop; Duration_IO.Put (System.Tick, Fore => 1, Aft => 6); Put_Line (" seconds is the precision of System clock.");
for J in Job_Index'Range loop Free (Jobs (J)); -- no GC in Ada, clean-up is explicit end loop;
end Rate_Counter;</lang>
Output on a Linux 64 bits system:
Job # 1 is finished. It took 57.93 seconds. Job # 5 is finished. It took 58.27 seconds. Job # 6 is finished. It took 58.27 seconds. Job # 4 is finished. It took 60.42 seconds. Job # 3 is finished. It took 60.98 seconds. Job # 2 is finished. It took 61.12 seconds. 0.000001 seconds is the precision of System clock.
BBC BASIC
<lang bbcbasic> PRINT "Method 1: Calculate reciprocal of elapsed time:"
FOR trial% = 1 TO 3 start% = TIME PROCtasktomeasure finish% = TIME PRINT "Rate = "; 100 / (finish%-start%) " per second" NEXT trial% PRINT '"Method 2: Count completed tasks in one second:" FOR trial% = 1 TO 3 cont% = TRUE *TIMER 1000 ON TIME ERROR 123, "Abort" ON ERROR LOCAL PRINT "Rate = ";runs% " per second" : cont% = FALSE IF cont% THEN runs% = 0 REPEAT PROCtasktomeasure runs% += 1 UNTIL FALSE ENDIF NEXT trial% END REM This is an example, replace with the task you want to measure DEF PROCtasktomeasure LOCAL i% FOR i% = 1 TO 1000000 NEXT ENDPROC</lang>
Sample output:
Method 1: Calculate reciprocal of elapsed time: Rate = 9.09090909 per second Rate = 9.09090909 per second Rate = 9.09090909 per second Method 2: Count completed tasks in one second: Rate = 9 per second Rate = 9 per second Rate = 9 per second
C
This code stores all of the data of the rate counter and its configuration in an instance of a struct named rate_state_s, and a function named tic_rate is called on that struct instance every time we complete a job. If a configured time has elapsed, tic_rate calculates and reports the tic rate, and resets the counter.
<lang c>#include <stdio.h>
- include <time.h>
// We only get one-second precision on most systems, as // time_t only holds seconds. struct rate_state_s {
time_t lastFlush; time_t period; size_t tickCount;
};
void tic_rate(struct rate_state_s* pRate) {
pRate->tickCount += 1;
time_t now = time(NULL);
if((now - pRate->lastFlush) >= pRate->period) { //TPS Report size_t tps = 0.0; if(pRate->tickCount > 0) tps = pRate->tickCount / (now - pRate->lastFlush);
printf("%u tics per second.\n", tps);
//Reset pRate->tickCount = 0; pRate->lastFlush = now; }
}
// A stub function that simply represents whatever it is // that we want to multiple times. void something_we_do() {
// We use volatile here, as many compilers will optimize away // the for() loop otherwise, even without optimizations // explicitly enabled. // // volatile tells the compiler not to make any assumptions // about the variable, implying that the programmer knows more // about that variable than the compiler, in this case. volatile size_t anchor = 0; size_t x = 0; for(x = 0; x < 0xffff; ++x) { anchor = x; }
}
int main() {
time_t start = time(NULL);
struct rate_state_s rateWatch; rateWatch.lastFlush = start; rateWatch.tickCount = 0; rateWatch.period = 5; // Report every five seconds.
time_t latest = start; // Loop for twenty seconds for(latest = start; (latest - start) < 20; latest = time(NULL)) { // Do something. something_we_do();
// Note that we did something. tic_rate(&rateWatch); }
return 0;
}</lang>
C++
This code defines the counter as a class, CRateState. The counter's period is configured as an argument to its constructor, and the rest of the counter state is kept as class members. A member function Tick() manages updating the counter state, and reports the tic rate if the configured period has elapsed.
<lang cpp>#include <iostream>
- include <ctime>
// We only get one-second precision on most systems, as // time_t only holds seconds. class CRateState { protected:
time_t m_lastFlush; time_t m_period; size_t m_tickCount;
public:
CRateState(time_t period); void Tick();
};
CRateState::CRateState(time_t period) : m_lastFlush(std::time(NULL)),
m_period(period), m_tickCount(0)
{ }
void CRateState::Tick() {
m_tickCount++;
time_t now = std::time(NULL);
if((now - m_lastFlush) >= m_period) { //TPS Report size_t tps = 0.0; if(m_tickCount > 0) tps = m_tickCount / (now - m_lastFlush);
std::cout << tps << " tics per second" << std::endl;
//Reset m_tickCount = 0; m_lastFlush = now; }
}
// A stub function that simply represents whatever it is // that we want to multiple times. void something_we_do() {
// We use volatile here, as many compilers will optimize away // the for() loop otherwise, even without optimizations // explicitly enabled. // // volatile tells the compiler not to make any assumptions // about the variable, implying that the programmer knows more // about that variable than the compiler, in this case. volatile size_t anchor = 0; for(size_t x = 0; x < 0xffff; ++x) { anchor = x; }
}
int main() {
time_t start = std::time(NULL);
CRateState rateWatch(5);
// Loop for twenty seconds for(time_t latest = start; (latest - start) < 20; latest = std::time(NULL)) { // Do something. something_we_do();
// Note that we did something. rateWatch.Tick(); }
return 0;
}</lang>
Common Lisp
Common Lisp already has a time
macro.
<lang lisp>(time (do some stuff))</lang> will give a timing report about "stuff" on the trace output. We can define something similar with repeats:
<lang lisp>(defmacro time-this (cnt &rest body)
(let ((real-t (gensym)) (run-t (gensym))) `(let (,real-t ,run-t) (setf ,real-t (get-internal-real-time)
,run-t (get-internal-run-time))
(loop repeat ,cnt do ,@body) (list (/ (- (get-internal-real-time) ,real-t)
(coerce internal-time-units-per-second 'float)) (/ (- (get-internal-run-time) ,run-t) (coerce internal-time-units-per-second 'float))))))</lang>
Call the time-this
macro to excute a loop 99 times:
<lang lisp>(print (time-this 99 (loop for i below 10000 sum i)))</lang>which gives a pair of numbers, the real time and the run time, both in seconds:<lang>(0.023 0.022)</lang>
E
<lang e>def makeLamportSlot := <import:org.erights.e.elib.slot.makeLamportSlot>
The rate counter:
/** Returns a function to call to report the event being counted, and an
EverReporter slot containing the current rate, as a float64 in units of events per millisecond. */
def makeRateCounter(timer, reportPeriod) {
var count := 0 var start := timer.now() def &rate := makeLamportSlot(nullOk[float64], null) def signal() { def time := timer.now() count += 1 if (time >= start + reportPeriod) { rate := count / (time - start) start := time count := 0 } } return [signal, &rate]
}</lang>
The test code:
<lang e>/** Dummy task: Retrieve http://localhost/ and return the content. */ def theJob() {
return when (def text := <http://localhost/> <- getText()) -> { text }
}
/** Repeatedly run 'action' and wait for it until five seconds have elapsed. */ def repeatForFiveSeconds(action) {
def stopTime := timer.now() + 5000 def loop() { if (timer.now() < stopTime) { when (action <- ()) -> { loop() } } } loop()
}
def whenever := <import:org.erights.e.elib.slot.whenever>
def [signal, &rate] := makeRateCounter(timer, 1000)
- Prepare to report the rate info.
whenever([&rate], fn {
println(`Rate: ${rate*1000} requests/sec`)
}, fn {true})
- Do some stuff to be counted.
repeatForFiveSeconds(fn {
signal() theJob()
})</lang>
Go
<lang go>package main
import (
"fmt" "math/rand" "time"
)
// representation of time.Time is nanosecond, actual resolution system specific type rateStateS struct {
lastFlush time.Time period time.Duration tickCount int
}
func ticRate(pRate *rateStateS) {
pRate.tickCount++ now := time.Now() if now.Sub(pRate.lastFlush) >= pRate.period { // TPS Report tps := 0. if pRate.tickCount > 0 { tps = float64(pRate.tickCount) / now.Sub(pRate.lastFlush).Seconds() } fmt.Println(tps, "tics per second.")
// Reset pRate.tickCount = 0 pRate.lastFlush = now }
}
func somethingWeDo() {
time.Sleep(time.Duration(9e7 + rand.Int63n(2e7))) // sleep about .1 second.
}
func main() {
start := time.Now()
rateWatch := rateStateS{ lastFlush: start, period: 5 * time.Second, }
// Loop for twenty seconds latest := start for latest.Sub(start) < 20*time.Second { somethingWeDo() ticRate(&rateWatch) latest = time.Now() }
}</lang> Output:
9.941784884430728 tics per second. 10.01399996465647 tics per second. 9.848572291869138 tics per second.
HicEst
The script opens a modeless dialog with 3 buttons: "Hits++" to increase Hits, "Count 5 sec" to reset Hits and initialize a delayed call to F5 after 5 sec, "Rate" to display the current rate on the status bar. <lang HicEst>CHARACTER prompt='Count "Hits++" for 5 sec, get current rate'
DLG(Button="1:&Hits++", CALL="cb", B="2:&Count 5sec", B="3:&Rate", RC=retcod, TItle=prompt, WIN=hdl)
SUBROUTINE cb ! callback after dialog buttons
IF(retcod == 1) THEN ! "Hits++" button Hits = Hits + 1 ELSEIF(retcod == 2) THEN ! "Count 5 sec" button Hits = 0 ALARM(5, 5) ! call F5 in 5 seconds t_start = TIME() ELSE ! "Rate" button sec = TIME() - t_start WRITE(StatusBar) 'Average rate since last "5 sec" button = ', hits/sec, " Hz" ENDIF
END
SUBROUTINE F5 ! called 5 sec after button "5 sec"
WRITE(StatusBar) Hits, "hits last 5 sec"
END</lang>
J
Solution
<lang j> x (6!:2) y</lang>
The foreign conjunction 6!:2
will execute the code y
(right argument), x
times (left argument) and report the average time in seconds required for one execution.
Example: <lang j> list=: 1e6 ?@$ 100 NB. 1 million random integers from 0 to 99
freqtable=: ~. ,. #/.~ NB. verb to calculate and build frequency table 20 (6!:2) 'freqtable list' NB. calculate and build frequency table for list, 20 times
0.00994106</lang>
Note, if instead we want distinct times instead of averaged times we can use a repeated counter for the number of times to execute the code
<lang j> 1 1 1 (6!:2) 'freqtable list' 0.0509995 0.0116702 0.0116266</lang>
JavaScript
The benchmark function below executes a given function n times, calling it with the specified arguments. After execution of all functions, it returns an array with the execution time of each execution, in milliseconds.
<lang javascript>function millis() { // Gets current time in milliseconds.
return (new Date()).getTime();
}
/* Executes function 'func' n times, returns array of execution times. */ function benchmark(n, func, args) {
var times = []; for (var i=0; i<n; i++) { var m = millis(); func.apply(func, args); times.push(millis() - m); } return times;
}</lang>
Liberty BASIC
precision depends on OS. It is 16 (sometines cames as 15) ms for XP and 10 ms for Win2000. <lang lb> Print "Rate counter" print "Precision: system clock, ms "; t0=time$("ms") while time$("ms")=t0 'busy loop till click ticks wend print time$("ms")-t0 print
Print "Run jobs N times, report every time" Print "After that, report average time" N=10 t00=time$("ms") for i = 1 to 10
scan t0=time$("ms") 'any code we want to measure goes here res = testFunc() 'end of measured code t1=time$("ms") ElapsedTime = t1-t0 print "Job #";i;" Elapsed time, ms ";ElapsedTime, 1000/ElapsedTime; " ticks per second"
next print "---------------------------------" print "Average time, ms, is ";(t1-t00)/N, 1000/((t1-t00)/N); " ticks per second"
print
print "Run jobs for not less then N seconds (if time up, it'll finish last job)"
print "After that, report average time"
NSec=5 i = 0 t00=time$("ms") while time$("ms")<t00+NSec*1000
scan i = i+1 t0=time$("ms") 'any code we want to measure goes here res = testFunc() 'end of measured code t1=time$("ms") ElapsedTime = t1-t0 print "Job #";i;" Elapsed time, ms ";ElapsedTime, 1000/ElapsedTime; " ticks per second"
wend print "---------------------------------" print "Average time, ms, is ";(t1-t00)/i, 1000/((t1-t00)/i); " ticks per second"
end
function testFunc()
s=0 for i = 1 to 30000 s=s+sin(i)/30000 next testFunc = s
end function </lang>
OxygenBasic
Rate Counter Deluxe, giving start and finish times + duration. The duration is measured in seconds using the system performance counter, resolved to the nearest microsecond. <lang oxygenbasic> '======== 'TIME API '========
'http://msdn.microsoft.com/en-us/library/windows/desktop/ms724950(v=vs.85).aspx
extern lib "kernel32.dll"
type SYSTEMTIME
WORD wYear WORD wMonth WORD wDayOfWeek WORD wDay WORD wHour WORD wMinute WORD wSecond WORD wMilliseconds
end type
void GetSystemTime(SYSTEMTIME*t) void GetLocalTime(SYSTEMTIME*t) void QueryPerformanceCounter(quad*c) void QueryPerformanceFrequency(quad*freq) void Sleep(sys millisecods)
end extern
String WeekDay[7]={"Sunday","Monday","Tuesday","Wednesday", "Thursday","Friday","Saturday"}
String MonthName[12]={"January","February","March","April","May","June", "July","August","September","October","November","December"}
'==============
Class Jobrecord
'==============
has SYSTEMTIME stt has SYSTEMTIME fin quad countA quad CountB quad freq sys serial
method pad(string s) as string method=s if len(method)<2 then method="0"+method end method
method ShowDateTime(sys a,f) as string
SYSTEMTIME *t
if a then @t=@fin else @t=@stt end if ' String month=pad(str t.wMonth) String day=pad(str t.wDay) if f=0 then return "" t.wYear "-" month "-" day " "+ pad(t.wHour) ":" pad(t.wMinute) ":" pad(t.wSecond) ":" t.wMilliSeconds elseif f=1 return WeekDay[t.wDayOfWeek+1 and 7 ] " " + MonthName[t.wMonth and 31] " " day " " t.wYear end if end method
method Start() QueryPerformanceCounter countA QueryPerformanceFrequency freq serial++ GetLocalTime stt end method
method Finish() GetLocalTime fin QueryPerformanceCounter countB end method
method ShowDuration() as string return str((countB-countA)/freq,6) 'seconds with microsecond resolution end method
method report() as string string tab=chr(9), cr=chr(13)+chr(10) method="Job:" tab serial cr + "Duration:" tab ShowDuration() cr + "Start: " tab ShowDateTime(0,0) cr + "Finish:" tab ShowDateTime(1,0) cr + ShowDateTime(1,1) cr end method
end class
'#recordof JobRecord
'==== 'TEST '====
JobRecord JR JR.start sleep 100 'JOB! JR.finish print JR.Report 'putfile "s.txt",JR.Report ' 'Job: 1 'Duration: 0.099026 'Start: 2012-07-01 00:52:36:874 'Finish: 2012-07-01 00:52:36:974 'Sunday July 01 2012 </lang>
PARI/GP
<lang parigp>a=0; b=0; for(n=1,20000000,
a=a+gettime(); if(a>60000,print(b);a=0;b=0);
code to test
b=b+1; a=a+gettime(); if(a>60000,print(b);a=0;b=0)
)</lang>
Perl
The Benchmark module can rate code per time, or per loops executed: <lang perl>use Benchmark;
timethese COUNT,{ 'Job1' => &job1, 'Job2' => &job2 };
sub job1
{
...job1 code...
}
sub job2
{
...job2 code...
}</lang>
A negative COUNT will run each job for at least COUNT seconds.
A positive COUNT will run each job COUNT times.
PicoLisp
usec returns a relative time in microseconds. This can be used, for example, to measure the time between two key strokes <lang PicoLisp>(prin "Hit a key ... ") (key) (prinl) (let Usec (usec)
(prin "Hit another key ... ") (key) (prinl) (prinl "This took " (format (- (usec) Usec) 6) " seconds") )</lang>
Output:
Hit a key ... Hit another key ... This took 3.132058 seconds
The bench benchmark function could also be used. Here we measure the time until a key is pressed <lang PicoLisp>(bench (key))</lang>
1.761 sec -> "a"
PureBasic
Counting frequence of an event
<lang PureBasic>Procedure.d TimesPSec(Reset=#False)
Static starttime, cnt Protected Result.d, dt If Reset starttime=ElapsedMilliseconds(): cnt=0 Else cnt+1 dt=(ElapsedMilliseconds()-starttime) If dt Result=cnt/(ElapsedMilliseconds()-starttime) EndIf EndIf ProcedureReturn Result*1000
EndProcedure
If OpenWindow(0,#PB_Ignore,#PB_Ignore,220,110,"",#PB_Window_SystemMenu)
Define Event, r.d, GadgetNumber ButtonGadget(0,10, 5,200,35,"Click me!") ButtonGadget(1,10,70,100,35,"Reset") TextGadget (2,10,45,200,25,"") TimesPSec(1) Repeat Event=WaitWindowEvent() If Event=#PB_Event_Gadget GadgetNumber =EventGadget() If GadgetNumber=0 r=TimesPSec() SetGadgetText(2,"You are clicking at "+StrD(r,5)+" Hz.") ElseIf GadgetNumber=1 TimesPSec(1) SetGadgetText(2,"Counter zeroed.") EndIf EndIf Until Event=#PB_Event_CloseWindow
EndIf</lang>
Counting events for a time period
<lang PureBasic>Procedure DummyThread(arg)
Define.d dummy=#PI*Pow(arg,2)/4
EndProcedure
start=ElapsedMilliseconds() Repeat
T=CreateThread(@DummyThread(),Random(100)) WaitThread(T) cnt+1
Until start+10000<=ElapsedMilliseconds(); Count for 10 sec
msg$="We got "+Str(cnt)+" st."+Chr(10)+StrF(cnt/10,2)+" threads per sec." MessageRequester("Counting threads in 10 sec",msg$)</lang>
Python
<lang python>import subprocess import time
class Tlogger(object):
def __init__(self): self.counts = 0 self.tottime = 0.0 self.laststart = 0.0 self.lastreport = time.time()
def logstart(self): self.laststart = time.time()
def logend(self): self.counts +=1 self.tottime += (time.time()-self.laststart) if (time.time()-self.lastreport)>5.0: # report once every 5 seconds self.report()
def report(self): if ( self.counts > 4*self.tottime): print "Subtask execution rate: %f times/second"% (self.counts/self.tottime); else: print "Average execution time: %f seconds"%(self.tottime/self.counts); self.lastreport = time.time()
def taskTimer( n, subproc_args ):
logger = Tlogger()
for x in range(n): logger.logstart() p = subprocess.Popen(subproc_args) p.wait() logger.logend() logger.report()
import timeit
import sys
def main( ):
# for accurate timing of code segments s = """j = [4*n for n in range(50)]""" timer = timeit.Timer(s) rzlts = timer.repeat(5, 5000) for t in rzlts: print "Time for 5000 executions of statement = ",t # subprocess execution timing print "#times:",sys.argv[1] print "Command:",sys.argv[2:] print "" for k in range(3): taskTimer( int(sys.argv[1]), sys.argv[2:])
main()</lang> Usage Example: First argument is the number of times to iterate. Additional arguments are command to execute.
C:>rateCounter.py 20 md5.exe
REXX
<lang rexx>/*REXX program reports on the time 4 different tasks take (wall clock)*/
time.= /*nullify times for all tasks. */
/*----------------------------------------------------------------------*/ call time 'Reset' /*reset the REXX timer. */
/*show pi in hexadecimal to */ /*2,000 decimal places. */ task.1='base(pi,16)' call '$CALC' task.1 /*perform task number one. */
time.1=time('Elapsed') /*save the time used by task 1. */ /*----------------------------------------------------------------------*/ call time 'Reset' /*reset the REXX timer. */
/*get primes # 40000-->40800 and */ /*show their differences. */ task.2='diffs[prime(40k,40.8k)] ;;; group 20' call '$CALC' task.2 /*perform task number two. */
time.2=time('Elapsed') /*save the time used by task 2. */ /*----------------------------------------------------------------------*/ call time 'Reset' /*reset the REXX timer. */
/*show the Collatz sequence for */ /*a stupidly big number. */ task.3='collatz(38**8) ;;; Horizontal' call '$CALC' task.3 /*perform task number three. */
time.3=time('Elapsed') /*save the time used by task 3. */ /*----------------------------------------------------------------------*/ call time 'Reset' /*reset the REXX timer. */
/*plot SIN in ½ degree increments*/ /*using 9 decimal digits (¬ 60).*/ task.4='sind(-180,+180,0.5) ;;; Plot DIGits 9' call '$CALC' task.4 /*perform task number four. */
time.4=time('Elapsed') /*save the time used by task 4. */ /*----------------------------------------------------------------------*/
say
do j=1 while time.j\== say 'time used for task' j "was" right(format(time.j,,0),4) 'seconds.' end
say</lang> Output (of the tasks as well as the above REXX timer program):
╔═════════════╗ ║ base(pi,16) ║ ╚═════════════╝ 3.243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89452821E638D01 377BE5466CF34E90C6CC0AC29B7C97C50DD3F84D5B5B54709179216D5D98979FB1BD1310BA698DF B5AC2FFD72DBD01ADFB7B8E1AFED6A267E96BA7C9045F12C7F9924A19947B3916CF70801F2E2858 EFC16636920D871574E69A458FEA3F4933D7E0D95748F728EB658718BCD5882154AEE7B54A41DC2 5A59B59C30D5392AF26013C5D1B023286085F0CA417918B8DB38EF8E79DCB0603A180E6C9E0E8BB 01E8A3ED71577C1BD314B2778AF2FDA55605C60E65525F3AA55AB945748986263E8144055CA396A 2AAB10B6B4CC5C341141E8CEA15486AF7C72E993B3EE1411636FBC2A2BA9C55D741831F6CE5C3E1 69B87931EAFD6BA336C24CF5C7A325381289586773B8F48986B4BB9AFC4BFE81B6628219361D809 CCFB21A991487CAC605DEC8032EF845D5DE98575B1DC262302EB651B8823893E81D396ACC50F6D6 FF383F442392E0B4482A484200469C8F04A9E1F9B5E21C66842F6E96C9A670C9C61ABD388F06A51 A0D2D8542F68960FA728AB5133A36EEF0B6C137A3BE4BA3BF0507EFB2A98A1F1651D39AF017666C A593E82430E888CEE8619456F9FB47D84A5C33B8B5EBEE06F75D885C12073401A449F56C16AA64E D3AA62363F77061BFEDF72429B023D37D0D724D00A1248DB0FEAD349F1C09B075372C980991B7B2 5D479D8F6E8DEF7E3FE501AB6794C3B976CE0BD04C006BAC1A94FB6409F60C45E5C9EC2196A2463 68FB6FAF3E6C53B51339B2EB3B52EC6F6DFC511F9B30952CCC814544AF5EBD09BEE3D004DE334AF D660F2807192E4BB3C0CBA85745C8740FD20B5F39B9D3FBDB5579C0BD1A60320AD6A100C6402C72 79679F25FEFB1FA3CC8EA5E9F8DB3222F83C7516DFFD616B152F501EC8AD0552AB323DB5FAFD238 76053317B483E00DF829E5C57BBCA6F8CA01A87562EDF1769DBD542A8F6287EFFC3AC6732C68C4F 5573695B27B0BBCA58C8E1FFA35DB8F011A010FA3D98FD2183B84AFCB56C2DD1D35B9A53E479B6F 84565D28E49BC4BFB9790E1DDF2DAA4CB7E3362FB1341CEE4C6E8EF20CADA36774C01D07E9EFE2B F11FB495DBDA4DAE909198EAAD8E716B93D5A0D08ED1D0AFC725E08E3C5B2F8E7594B78FF6E2FBF 2122B648CB209FDA49D89455E99887A81CF7DC407E83568CDC24FD608C80225F7ADA98BABF283A8 E1B06BBDBB6E99F6B4BC3E795E7BE1C57B21085778AB866F897578CEC3600FB01B0789912575FEF DC4595BF054658D676F6323CD6DB1584BC6747713A2A431395D62DE6646642E9A995FB71811B93A F99E6EB7B169C96740AA3A0F9EA3244AB192F10B595DC3E27CFEC33F1341A2830A7A30CC356B0A1 3AA06A5CFFB2B87F9AE0DAC27C0F649D4B5F0339 ╔═════════════════════════╗ ║ diffs[prime(40k,40.8k)] ║ ╚═════════════════════════╝ 1► 30 12 2 4 14 42 4 2 4 20 4 2 10 2 10 20 10 6 6 20 21► 10 14 10 2 34 6 78 12 18 12 12 2 6 18 6 6 4 8 18 10 41► 8 22 2 10 2 36 4 6 8 4 6 6 8 12 10 6 14 4 60 14 61► 46 6 18 6 12 12 12 14 16 24 12 14 28 30 8 10 8 4 18 8 81► 12 10 12 2 6 12 22 8 16 6 14 6 4 12 14 10 8 6 6 4 101► 14 6 4 18 8 4 20 18 48 4 2 4 36 20 10 6 8 22 8 16 121► 14 22 20 12 12 18 18 22 6 12 30 14 6 12 16 6 8 12 4 2 141► 22 30 2 16 18 14 6 6 24 6 4 2 12 6 12 4 26 30 24 34 161► 20 4 8 4 6 12 20 22 6 2 16 6 56 10 14 10 14 4 2 10 181► 20 18 28 14 24 4 8 12 16 6 6 2 6 6 10 14 4 42 18 6 201► 2 4 6 8 12 30 24 4 24 6 6 8 18 4 20 4 2 18 4 6 221► 2 12 12 10 6 8 6 16 14 16 8 10 24 2 10 24 2 18 24 6 241► 10 14 46 14 30 10 26 30 12 24 4 12 30 2 10 8 4 6 8 4 261► 30 8 28 6 14 10 20 10 12 8 10 2 24 10 24 14 10 8 4 20 281► 18 10 6 6 14 34 8 10 14 6 22 26 12 10 8 6 18 6 4 6 301► 6 14 22 2 16 2 10 14 10 6 14 24 22 8 16 18 20 28 8 10 321► 24 6 12 12 20 6 6 6 22 2 18 10 12 8 6 22 14 16 24 18 341► 2 24 12 22 8 4 24 14 6 22 8 10 2 28 2 4 38 12 34 20 361► 10 2 4 8 18 4 48 12 24 6 18 12 6 8 10 42 24 14 60 24 381► 36 12 22 8 12 12 6 4 18 20 12 10 8 6 24 6 4 30 6 2 401► 54 48 36 4 12 8 12 6 22 6 6 14 10 32 18 12 10 24 24 20 421► 6 10 6 38 10 14 18 12 16 12 2 22 24 42 8 4 2 60 6 10 441► 14 18 18 18 16 30 14 4 2 10 8 10 20 12 16 14 6 24 16 2 461► 12 10 18 2 24 34 12 14 6 10 6 2 10 8 28 2 10 2 6 10 481► 26 10 6 32 10 12 6 2 16 12 20 10 14 6 12 16 20 4 2 10 501► 14 4 6 2 4 14 16 8 36 10 2 12 16 20 4 12 6 30 38 16 521► 6 14 4 2 22 6 14 16 6 8 28 2 6 16 6 14 6 12 22 44 541► 6 4 24 2 6 28 14 22 20 4 6 36 14 18 6 4 6 26 4 2 561► 18 10 6 6 2 6 4 8 18 54 28 12 2 4 30 12 2 6 24 10 581► 12 6 8 10 6 8 16 12 14 6 4 18 8 10 2 12 30 16 2 6 601► 36 10 30 6 18 6 6 2 10 30 6 12 50 24 6 4 8 10 26 6 621► 4 2 18 4 2 6 10 12 2 24 16 6 2 6 4 8 4 6 8 6 641► 28 18 2 6 10 2 22 18 14 30 10 26 28 6 30 8 6 10 6 6 661► 2 10 36 2 12 10 6 6 6 14 6 10 20 12 6 24 6 6 28 18 681► 14 4 12 12 26 12 22 12 8 10 8 24 10 8 40 8 4 14 6 24 701► 4 18 12 6 20 22 2 16 6 20 16 30 8 6 18 6 22 18 2 18 721► 4 8 10 8 22 8 6 36 10 12 2 4 14 42 18 22 6 14 4 2 741► 10 2 42 10 18 30 2 6 4 14 6 10 14 4 18 2 16 14 10 2 761► 28 2 16 2 16 12 12 2 16 12 2 24 40 6 8 6 4 30 8 10 781► 14 18 6 16 18 6 2 18 4 6 6 26 4 26 28 26 24 4 32 6 ╔════════════════╗ ║ collatz(38**8) ║ ╚════════════════╝ 4347792138496 2173896069248 1086948034624 543474017312 271737008656 135868504328 67934252164 33967126082 16983563041 50950689124 25475344562 12737672281 38213016844 19106508422 9553254211 28659762634 14329881317 42989643952 21494821976 10747410988 5373705494 2686852747 8060558242 4030279121 12090837364 6045418682 3022709341 9068128024 4534064012 2267032006 1133516003 3400548010 1700274005 5100822016 2550411008 1275205504 637602752 318801376 159400688 79700344 39850172 19925086 9962543 29887630 14943815 44831446 22415723 67247170 33623585 100870756 50435378 25217689 75653068 37826534 18913267 56739802 28369901 85109704 42554852 21277426 10638713 31916140 15958070 7979035 23937106 11968553 35905660 17952830 8976415 26929246 13464623 40393870 20196935 60590806 30295403 90886210 45443105 136329316 68164658 34082329 102246988 51123494 25561747 76685242 38342621 115027864 57513932 28756966 14378483 43135450 21567725 64703176 32351588 16175794 8087897 24263692 12131846 6065923 18197770 9098885 27296656 13648328 6824164 3412082 1706041 5118124 2559062 1279531 3838594 1919297 5757892 2878946 1439473 4318420 2159210 1079605 3238816 1619408 809704 404852 202426 101213 303640 151820 75910 37955 113866 56933 170800 85400 42700 21350 10675 32026 16013 48040 24020 12010 6005 18016 9008 4504 2252 1126 563 1690 845 2536 1268 634 317 952 476 238 119 358 179 538 269 808 404 202 101 304 152 76 38 19 58 29 88 44 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 │1 ∙∙∙∙∙∙ │ ∙∙∙ ∙∙∙ │ ∙∙ ∙∙ │ ∙∙ ∙∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙∙ ∙∙ │ ∙∙ ∙∙ │ ∙ ∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙ ∙∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙ ∙ │ ∙∙ ∙ │ ∙ ∙∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙ ∙ │0 ∙∙ ∙∙ ∙──────────────────────────────────────∙──────────────────────────────────────∙ ∙∙ ∙∙ 721 │∙ ∙ │ ∙ ∙∙ │ ∙ ∙ │ ∙ ∙∙ │ ∙∙ ∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙∙ ∙ │ ∙ ∙ │ ∙∙ ∙∙ │ ∙∙ ∙ │ ∙ ∙∙ │ ∙∙ ∙∙ │ ∙∙ ∙∙ │ ∙∙ ∙∙ │ ∙∙ ∙ │ ∙∙ ∙∙∙ │ ∙∙ ∙∙ │ ∙∙∙ ∙∙∙ │-1 ∙∙∙∙∙∙ time used for task 1 was 0 seconds. time used for task 2 was 11 seconds. time used for task 3 was 0 seconds. time used for task 4 was 1 seconds.
Run BASIC
<lang runbasic>html "
Rate Counter | |
Run Job Times | "
textbox #runTimes,"10",3html " |
"
button #r,"Run", [runIt] html " " button #a, "Average", [ave]html " |
"
wait
[runIt] runTimes = min(10,val(#runTimes contents$())) count = count + 1 print "-------- Run Number ";count;" ----------------" print "Run jobs";runTimes;" times, reporting each"
for i = 1 to runTimes
' ----------------------------------------------------------------- ' Normally we use a RUN() command to run another program ' but for test pruporse we have a routine that simply loops a bunch ' ----------------------------------------------------------------- begTime = time$("ms") theRun = bogusProg()
endTime = time$("ms") lapsTime = endTime - begTime print "Job #";i;" Elapsed time, ms ";lapsTime;" ";1000/lapsTime; " ticks per second"
next aveTime = (endTime-startTime)/runTimes totAveTime = totAveTime + aveTime print "Average time, ms, is ";aveTime;" "; 1000/((endTime-startTime)/runTimes); " ticks per second" wait
[ave] print "---------------------------------" print "Total average time:";aveTime/count
function bogusProg()
for i = 1 to 10000 sini = sini + sin(i) tani = tani + tan(i) cpsi = cosi + cos(i) next
end function </lang> Output:
Rate Counter | |
Run Job Times | 10 |
<button value="Run"/> <button value="Average"/> |
.-------- Run Number 1 ----------------
Run jobs 2 times, reporting each
Job #1 Elapsed time, ms 50 20 ticks per second
Job #2 Elapsed time, ms 48 20.8333349 ticks per second
Average time, ms, is 1754768605184 5.69875717e-10 ticks per second
.-------- Run Number 2 ----------------
Run jobs 3 times, reporting each
Job #1 Elapsed time, ms 47 21.2765955 ticks per second
Job #2 Elapsed time, ms 47 21.2765955 ticks per second
Job #3 Elapsed time, ms 47 21.2765955 ticks per second
Average time, ms, is 1169845780480 8.54813575e-10 ticks per second
.---------------------------------
Total average time:584922890240
Scala
The solution below measures the number of tasks run in 5, 10 and 15 seconds. The tasks, however, run multithreaded, not sequentially. It also does not stop the remaining tasks once the time is up.
<lang scala>def task(n: Int) = Thread.sleep(n * 1000) def rate(fs: List[() => Unit]) = {
val jobs = fs map (f => scala.actors.Futures.future(f())) val cnt1 = scala.actors.Futures.awaitAll(5000, jobs: _*).count(_ != None) val cnt2 = scala.actors.Futures.awaitAll(5000, jobs: _*).count(_ != None) val cnt3 = scala.actors.Futures.awaitAll(5000, jobs: _*).count(_ != None) println("%d jobs in 5 seconds" format cnt1) println("%d jobs in 10 seconds" format cnt2) println("%d jobs in 15 seconds" format cnt3)
} rate(List.fill(30)(() => task(scala.util.Random.nextInt(10)+1))) </lang>
The solution below runs a task repeatedly, for at most N seconds or Y times. The precision available is milliseconds, though the sampling was limited to seconds. It will wait until the current execution of the task is finished before announcing the result, if the time runs out.
<lang scala>def rate(n: Int, y: Int)(task: => Unit) {
val startTime = System.currentTimeMillis var currTime = startTime var loops = 0 do { task currTime = System.currentTimeMillis loops += 1 } while (currTime - startTime < n * 1000 && loops < y) if (currTime - startTime > n * 1000) println("Rate %d times per %d seconds" format (loops - 1, n)) else println("Rate %d times in %.3f seconds" format (y, (currTime - startTime).toDouble / 1000))
} rate(5, 20)(task(2))</lang>
Smalltalk
<lang smalltalk>|times| times := Bag new. 1 to: 10 do: [:n| times add:
(Time millisecondsToRun: [3000 factorial])].
Transcript show: times average asInteger.</lang> Output:
153
Tcl
The standard Tcl mechanism to measure how long a piece of code takes to execute is the time
command. The first word of the string returned (which is also always a well-formed list) is the number of microseconds taken (in absolute time, not CPU time). Tcl uses the highest performance calibrated time source available on the system to compute the time taken; on Windows, this is derived from the system performance counter and not the (poor quality) standard system time source.
<lang tcl>set iters 10
- A silly example task
proc theTask {} {
for {set a 0} {$a < 100000} {incr a} { expr {$a**3+$a**2+$a+1} }
}
- Measure the time taken $iters times
for {set i 1} {$i <= $iters} {incr i} {
set t [lindex [time { theTask }] 0] puts "task took $t microseconds on iteration $i"
}</lang> When tasks are are very quick, a more accurate estimate of the time taken can be gained by repeating the task many times between time measurements. In this next example, the task (a simple assignment) is repeated a million times between measures (this is very useful when performing performance analysis of the Tcl implementation itself). <lang tcl>puts [time { set aVar 123 } 1000000]</lang>
UNIX Shell
This code stores the number of times the program task can complete in 20 seconds. It is two parts.
Part 1: file "foo.sh"
This script spins, executing task as many times as possible.
<lang bash>#!/bin/bash
while : ; do task && echo >> .fc done</lang>
Part 2:
This script runs foo.sh in the background, and checks the rate count file every five seconds. After four such checks, twenty seconds will have elapsed.
<lang bash>./foo.sh &
sleep 5
mv .fc .fc2 2>/dev/null
wc -l .fc2 2>/dev/null
rm .fc2
sleep 5
mv .fc .fc2 2>/dev/null
wc -l .fc2 2>/dev/null
sleep 5
mv .fc .fc2 2>/dev/null
wc -l .fc2 2>/dev/null
sleep 5
killall foo.sh
wc -l .fc 2>/dev/null
rm .fc</lang>
XPL0
<lang XPL0>include c:\cxpl\codes; \intrinsic 'code' declarations int N, I, T0, Time; [for N:= 1, 3 do
[T0:= GetTime; for I:= 1 to 100 do [while port($3DA) & $08 do []; \wait for vertical retrace to go away repeat until port($3DA) & $08; \wait for vertical retrace signal ]; Time:= GetTime - T0; IntOut(0, Time); Text(0, " microseconds for 100 samples = "); RlOut(0, 100.0e6/float(Time)); Text(0, "Hz"); CrLf(0); ];
]</lang>
Example output of vertical blanking (screen refresh) rates:
These measurements were taken while running under DOS 5.0 with the output redirected to a file. When the output is instead displayed on the screen, the second two readings consistently match for the first five digits. The first reading varies because the program (purposely) does not sync up on the retrace signal before starting the measurements. 1682024 microseconds for 100 samples = 59.45218Hz 1683980 microseconds for 100 samples = 59.38313Hz 1689918 microseconds for 100 samples = 59.17447Hz These measurements were taken on a Windows XP machine running in windowed mode: 1384184 microseconds for 100 samples = 72.24473Hz 1355413 microseconds for 100 samples = 73.77825Hz 1326029 microseconds for 100 samples = 75.41313Hz These measurements were taken on the same Windows machine in full-screen mode: 1418413 microseconds for 100 samples = 70.50133Hz 1424391 microseconds for 100 samples = 70.20544Hz 1395069 microseconds for 100 samples = 71.68104Hz