Compile function SRP_Stopwatch(Service, Param1, Param2, Param3) /*********************************************************************************************************************** This program is proprietary and is not to be used by or disclosed to others, nor is it to be copied without written permission from SRP Computer Solutions, Inc. Name : SRP_Stopwatch Description : Service module for benchmarking. Notes : SRP_Stopwatch simplifies benchmarking by tracking multiple benchmarks and displaying them for you at the end. You need nothing other than the source code below. There are no dependencies on any other DLLs, OCXs, or RDKs. It uses only that which ships with OpenInsight. Parameters : Service [in] -- The stopwatch service. Param1 [in] -- The service specific parameter. Ans [out] -- Response from the service, usually benchmark results. Metadata: @@DEFINE_SERVICES_SIGNATURE(@SERVICE, @PARAMS) History : (Date, Initials, Notes) 01/22/13 krf Original programmer 05/09/16 krf Updated code to allow Start/Stop to be called multiple times for same name, accumulating a total time. 11/30/16 dmb Fix support for single character stopwatch names in the GetAll and Reset services by changing the GE operator to GT. 11/30/16 dmb If the Name argument is empty, use "". This makes it easier to create a simple one-off stopwatch. 08/17/17 krf Added Count and Average related services 08/30/17 krf Fixed formatting issues; added secret TEST service ***********************************************************************************************************************/ If Assigned(Service) else Service = "" If Assigned(Param1) else Param1 = "" Ans = "" Declare function SRP_Stopwatch, GetTickCount, Max, Index Declare subroutine Msg // global common Common /SRPStopwatch/ Names@, Total@ Convert @Lower.Case to @Upper.Case in Service // benchmark specific commons (Param1 = Name for these services) Locate Service in "GETAVERAGE,GETBENCHMARK,GETCOUNT,GETDATA,SHOW,START,STOP,TEST" using "," setting Pos then Name = Param1 If Name EQ '' then Name = "" end If Len(Name) then // Load the commons StopWatchName = "SRP_Stopwatch_":Name Common //StopWatchName// StartTime@, ElapsedTime@, Count@ // Branch to the service Begin Case Case Service _EQC "GETAVERAGE" ; GoSub GetAverage Case Service _EQC "GETBENCHMARK" ; GoSub GetBenchmark Case Service _EQC "GETCOUNT" ; GoSub GetCount Case Service _EQC "GETDATA" ; GoSub GetData Case Service _EQC "SHOW" ; GoSub Show Case Service _EQC "START" ; GoSub Start Case Service _EQC "STOP" ; GoSub Stop Case Service _EQC "TEST" ; GoSub Test End Case end end else // Non-benchmark specific services Begin Case Case Service _EQC "GETALL" ; GoSub GetAll Case Service _EQC "GETTOTALBENCHMARK" ; GoSub GetTotalBenchmark Case Service _EQC "RESET" ; GoSub Reset Case Service _EQC "SHOWALL" ; GoSub ShowAll End Case end Return Ans /////////////////////////////////////////////////////////////////////////////////////////////////// // SERVICES /////////////////////////////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------------------------------------------- // Returns the elapsed time for a benchmark. // @@DEFINE_SERVICE(GetAll) //------------------------------------------------------------------------------------------------- GetAll: // Loop through all the benchmarks and get their results LenNames = Len(Names@) If LenNames then Benchmarks = "" Pos = 1 Loop Until Pos GT LenNames Name = Names@[Pos, @FM] Pos = Col2() + 1 Benchmarks<-1> = Name:@VM:SRP_Stopwatch("GetData", Name, @VM) Repeat Ans = Benchmarks end return //------------------------------------------------------------------------------------------------- // Returns the average elapsed time for a benchmark. // @@DEFINE_SERVICE(GetAverage, Name) //------------------------------------------------------------------------------------------------- GetAverage: If Len(StartTime@) then If Len(ElapsedTime@) then Count = If Count@ GT 0 then Count@ else 1 WorkingTime = Int(ElapsedTime@ / Count) GoSub FormatWorkingTime end end return //------------------------------------------------------------------------------------------------- // Returns the elapsed time for a benchmark. // @@DEFINE_SERVICE(GetBenchmark, Name) //------------------------------------------------------------------------------------------------- GetBenchmark: If Len(StartTime@) then If Len(ElapsedTime@) then WorkingTime = ElapsedTime@ GoSub FormatWorkingTime end end return //------------------------------------------------------------------------------------------------- // Returns the average elapsed time for a benchmark. // @@DEFINE_SERVICE(GetAverage, Name) //------------------------------------------------------------------------------------------------- GetCount: If Len(StartTime@) then If Len(ElapsedTime@) then Ans = Count@ end end return //------------------------------------------------------------------------------------------------- // Returns the elapsed time for a benchmark. // @@DEFINE_SERVICE(GetData, Name, Delim) //------------------------------------------------------------------------------------------------- GetData: // The delimiter Delim = If Assigned(Param2) then Param2 else @FM // Format and return the data WorkingTime = ElapsedTime@ GoSub FormatWorkingTime Benchmark = Ans Count = If Count@ GT 0 then Count@ else 1 WorkingTime = Int(ElapsedTime@ / Count) GoSub FormatWorkingTime Average = Ans Ans = Benchmark : Delim : Count : Delim : Average return //------------------------------------------------------------------------------------------------- // Returns the elapsed time for all benchmarks. // @@DEFINE_SERVICE(GetTotalBenchmark) //------------------------------------------------------------------------------------------------- GetTotalBenchmark: If Len(Total@) then WorkingTime = Total@ GoSub FormatWorkingTime end return //------------------------------------------------------------------------------------------------- // Resets the stopwatch. This should be called at the beginning of a benchmark. // @@DEFINE_SERVICE(Reset) //------------------------------------------------------------------------------------------------- Reset: // Release all the commons, if any LenNames = Len(Names@) If LenNames then Pos = 1 Loop Until Pos GT LenNames Name = Names@[Pos, @FM] Pos = Col2() + 1 StopWatchName = "SRP_Stopwatch_":Name FreeCommon StopWatchName Repeat end // Clear the names Names@ = "" Total@ = 0 return //------------------------------------------------------------------------------------------------- // Shows the benchmark in a message box // @@DEFINE_SERVICE(Show, Name) //------------------------------------------------------------------------------------------------- Show: GoSub GetData Text = "" Benchmark = Ans<1> Count = Ans<2> Average = Ans<3> // Format the benchmark If (Index(Benchmark, "00h", 1) EQ 0) else Benchmark[1, 4] = "" end If (Index(Benchmark, "00m", 1) EQ 0) else Benchmark[1, 4] = "" end If (Index(Benchmark, "00s", 1) EQ 0) else Benchmark[1, 4] = "" end Text = Name:" : ":Benchmark // Format the count and average If Count GT 1 then If (Index(Average, "00h", 1) EQ 0) else Average[1, 4] = "" end If (Index(Average, "00m", 1) EQ 0) else Average[1, 4] = "" end If (Index(Average, "00s", 1) EQ 0) else Average[1, 4] = "" end Text := " : ":Count:" times : ":Average:" avg" end // Show it MsgStruct = "" MsgStruct<1> = Text MsgStruct<12> = "SRP Stopwatch Results" MsgStruct<18> = "Consolas":@SVM:"-13" Msg(@Window, MsgStruct) Ans = 1 return //------------------------------------------------------------------------------------------------- // Shows the results for all benchmarks in a message box // @@DEFINE_SERVICE(ShowAll) //------------------------------------------------------------------------------------------------- ShowAll: GoSub GetAll Text = "" LenAns = Len(Ans) NumBenchmarks = DCount(Ans, @FM) If LenAns then // Loop throught the results to determine the best way to format MaxNameLen = 5 MaxCountLen = 1 HasHours = 0 HasMinutes = 0 HasSeconds = 0 HasCounts = 0 HasAveHours = 0 HasAveMinutes = 0 HasAveSeconds = 0 Pos = 1 Loop Until Pos GE LenAns Result = Ans[Pos, @FM] Pos = Col2() + 1 Name = Result[1, @VM] Time = Result[Col2() + 1, @VM] Count = Result[Col2() + 1, @VM] Average = Result[Col2() + 1, @VM] MaxNameLen = Max(MaxNameLen, Len(Name)) If HasHours else HasHours = (Index(Time, "00h", 1) EQ 0) end If HasMinutes else HasMinutes = (Index(Time, "00m", 1) EQ 0) end If HasSeconds else HasSeconds = (Index(Time, "00s", 1) EQ 0) end //If Count GT 1 OR HasCounts EQ 1 then HasCounts = 1 MaxCountLen = Max(MaxCountLen, Len(Count)) If HasAveHours else HasAveHours = (Index(Average, "00h", 1) EQ 0) end If HasAveMinutes else HasAveMinutes = (Index(Average, "00m", 1) EQ 0) end If HasAveSeconds else HasAveSeconds = (Index(Average, "00s", 1) EQ 0) end //end Repeat // Check how long the total time will be If NumBenchmarks GT 1 then TotalTime = SRP_Stopwatch("GetTotalBenchmark") If HasHours else HasHours = (Index(TotalTime, "00h", 1) EQ 0) end If HasMinutes else HasMinutes = (Index(TotalTime, "00m", 1) EQ 0) end If HasSeconds else HasSeconds = (Index(TotalTime, "00s", 1) EQ 0) end end // Loop through the results to build the message text MaxLine = 0 Pos = 1 Loop Until Pos GE LenAns Result = Ans[Pos, @FM] Pos = Col2() + 1 Name = Result[1, @VM] Time = Result[Col2() + 1, @VM] Count = Result[Col2() + 1, @VM] Average = Result[Col2() + 1, @VM] If HasHours then Swap "00h" with " " in Time end else Time[1, 4] = "" end If HasMinutes then Swap "00m" with " " in Time end else Time[1, 4] = "" end If HasSeconds then Swap "00s" with " " in Time end else Time[1, 4] = "" end Line = Fmt(Name, "L( )#":(MaxNameLen + 1)):": ":Time If HasCounts then If HasAveHours then Swap "00h" with " " in Average end else Average[1, 4] = "" end If HasAveMinutes then Swap "00m" with " " in Average end else Average[1, 4] = "" end If HasAveSeconds then Swap "00s" with " " in Average end else Average[1, 4] = "" end Line := " : ":Fmt(Count, "R( )#":MaxCountLen):" times : ":Average:" avg" end MaxLine = Max(MaxLine, Len(Line)) Text := Line:"|" Repeat If NumBenchmarks GT 1 then // Divider line Text := Str("-", MaxLine):"|" // Total line If HasHours then Swap "00h" with " " in TotalTime end else TotalTime[1, 4] = "" end If HasMinutes then Swap "00m" with " " in TotalTime end else TotalTime[1, 4] = "" end If HasSeconds then Swap "00s" with " " in TotalTime end else TotalTime[1, 4] = "" end Text := Fmt("Total", "L( )#":(MaxNameLen + 1)):": ":TotalTime end else Text[-1, 1] = "" end end // Show it If Len(Text) then MsgStruct = "" MsgStruct<1> = Text MsgStruct<12> = "SRP Stopwatch Results" MsgStruct<18> = "Consolas":@SVM:"-13" Msg(@Window, MsgStruct) Ans = 1 end else Ans = 0 end return //------------------------------------------------------------------------------------------------- // Starts a benchmark. // @@DEFINE_SERVICE(Start, Name) //------------------------------------------------------------------------------------------------- Start: // Add the benchmark name if it doesn't exist Locate Name in Names@ using @FM setting Pos else Names@<-1> = Name ElapsedTime@ = 0 Count@ = 0 end StartTime@ = GetTickCount() return //------------------------------------------------------------------------------------------------- // Stops a benchmark. // @@DEFINE_SERVICE(Stop, Name) //------------------------------------------------------------------------------------------------- Stop: CurrElapsedTime = GetTickCount() - StartTime@ ElapsedTime@ += CurrElapsedTime Total@ += CurrElapsedTime Count@ += 1 return //------------------------------------------------------------------------------------------------- // Let's me add test data, so I'm not going to advertise this service. Param2 is the elapsed time, // and Param3 is the count for the given name. //------------------------------------------------------------------------------------------------- Test: // Add the benchmark name if it doesn't exist Locate Name in Names@ using @FM setting Pos else Names@<-1> = Name ElapsedTime@ = Param2 Count@ = Param3 Total@ += Param2 end return /////////////////////////////////////////////////////////////////////////////////////////////////// // INTERNAL GOSUBS /////////////////////////////////////////////////////////////////////////////////////////////////// FormatWorkingTime: // Hours NumHours = Int(WorkingTime / 3600000) WorkingTime = Mod(WorkingTime, 3600000) // Minutes NumMinutes = Int(WorkingTime / 60000) WorkingTime = Mod(WorkingTime, 60000) // Seconds and Millseconds NumSeconds = Int(WorkingTime / 1000) NumMilliseconds = Mod(WorkingTime, 1000) // Format Ans = Fmt(NumHours, "R(0)#2"):"h ":Fmt(NumMinutes, "R(0)#2"):"m ":Fmt(NumSeconds, "R(0)#2"):"s ":Fmt(NumMilliseconds, "R(0)#3"):"ms" return