X-Git-Url: http://deadsoftware.ru/gitweb?a=blobdiff_plain;f=src%2Fshared%2Fxprofiler.pas;h=5e6212b921b5b7ddc04784ad9d601503b3d93483;hb=0e101bd452c40da601236aaa2dd4106be47ddce1;hp=083704863848142f8e7f8342f3c57a260d1e9959;hpb=7869ee331ead2e3f765af47eeca1566ed97faa19;p=d2df-sdl.git diff --git a/src/shared/xprofiler.pas b/src/shared/xprofiler.pas index 0837048..5e6212b 100644 --- a/src/shared/xprofiler.pas +++ b/src/shared/xprofiler.pas @@ -1,9 +1,8 @@ -(* Copyright (C) DooM 2D:Forever Developers +(* Copyright (C) Doom 2D: Forever Developers * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 3 of the License ONLY. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,18 +14,35 @@ *) // stopwatch timer to measure short periods (like frame rendering phases) {$INCLUDE a_modes.inc} +{.$DEFINE XPROFILER_SLOW_AVERAGE} unit xprofiler; interface -uses - SysUtils, - {$IF DEFINED(LINUX)} +{$IFNDEF IN_TOOLS} + uses + {$IFDEF USE_SDL} + SDL, + {$ENDIF} + {$IFDEF USE_SDL2} + SDL2, + {$ENDIF} + SysUtils; + + {$DEFINE STOPWATCH_IS_HERE} + +{$ELSE} + uses + SysUtils + {$IF DEFINED(LINUX) OR DEFINED(ANDROID)} {$DEFINE STOPWATCH_IS_HERE} - unixtype, linux + , unixtype, linux {$ELSEIF DEFINED(WINDOWS)} {$DEFINE STOPWATCH_IS_HERE} - Windows + , Windows + {$ELSEIF DEFINED(HAIKU)} + {$DEFINE STOPWATCH_IS_HERE} + , unixtype {$ELSE} {$IFDEF STOPWATCH_IS_HERE} {$UNDEF STOPWATCH_IS_HERE} @@ -34,6 +50,12 @@ uses {$WARNING You suck!} {$ENDIF} ; +{$ENDIF} // IN_TOOLS + +{$IFDEF USE_SDL} + type + UInt64 = QWord; (* !!! *) +{$ENDIF} {$IF DEFINED(STOPWATCH_IS_HERE)} type @@ -69,22 +91,24 @@ type const - TProfHistorySize = 100; + TProfHistorySize = 1000; type TProfilerBar = record private - const FilterFadeoff = 0.05; // 5% + //const FilterFadeoff = 0.05; // 5% private - history: array [0..TProfHistorySize-1] of Integer; // circular buffer - hisHead: Integer; - curval: Single; + history: array of Integer; // circular buffer + hisLast: Integer; + //curval: Single; + curAccum: UInt64; + curAccumCount: Integer; mName: AnsiString; mLevel: Integer; private - procedure initialize (); inline; + procedure initialize (aHistSize: Integer); inline; function getvalue (): Integer; inline; function getvalat (idx: Integer): Integer; inline; function getcount (): Integer; inline; @@ -121,9 +145,10 @@ type public bars: array of TProfilerBar; // 0: total time name: AnsiString; + histSize: Integer; public - constructor Create (aName: AnsiString); + constructor Create (aName: AnsiString; aHistSize: Integer); destructor Destroy (); override; // call this on frame start @@ -131,16 +156,24 @@ type // call this on frame end procedure mainEnd (); - procedure sectionBegin (name: AnsiString); + procedure sectionBegin (aName: AnsiString); procedure sectionEnd (); // this will reuse the section with the given name (if there is any); use `sectionEnd()` to end it as usual - procedure sectionBeginAccum (name: AnsiString); + procedure sectionBeginAccum (aName: AnsiString); end; +function getTimeMicro (): UInt64; inline; +function getTimeMilli (): UInt64; inline; + + implementation +{$IFNDEF IN_TOOLS} +type + THPTimeType = Int64; +{$ELSE} {$IF DEFINED(LINUX)} type THPTimeType = TTimeSpec; {$ELSE} @@ -150,13 +183,17 @@ type THPTimeType = Int64; var mFrequency: Int64 = 0; mHasHPTimer: Boolean = false; +{$ENDIF} // ////////////////////////////////////////////////////////////////////////// // procedure initTimerIntr (); +{$IFDEF IN_TOOLS} var r: THPTimeType; +{$ENDIF} begin +{$IFDEF IN_TOOLS} if (mFrequency = 0) then begin {$IF DEFINED(LINUX)} @@ -165,28 +202,56 @@ begin if not mHasHPTimer then raise Exception.Create('profiler error: hires timer is not available'); mFrequency := 1; // just a flag if (r.tv_nsec <> 0) then mFrequency := 1000000000000000000 div r.tv_nsec; -{$ELSE} +{$ELSEIF DEFINED(WINDOWS)} mHasHPTimer := QueryPerformanceFrequency(r); if not mHasHPTimer then raise Exception.Create('profiler error: hires timer is not available'); mFrequency := r; {$ENDIF} end; +{$ENDIF} + (* init sdl timers? *) end; -function curTimeMicro (): UInt64; inline; +{$IF DEFINED(IN_TOOLS)} +function getTimeMicro (): UInt64; inline; var r: THPTimeType; begin - if (mFrequency = 0) then initTimerIntr(); + //if (mFrequency = 0) then initTimerIntr(); {$IF DEFINED(LINUX)} clock_gettime(CLOCK_MONOTONIC, @r); result := UInt64(r.tv_sec)*1000000+UInt64(r.tv_nsec) div 1000; // microseconds - {$ELSE} + {$ELSEIF DEFINED(WINDOWS)} QueryPerformanceCounter(r); result := UInt64(r)*1000000 div mFrequency; {$ENDIF} end; +(* !!! +{$ELSEIF DEFINED(USE_SDL)} +function getTimeMicro: UInt64; inline; +begin + {$WARNING use inaccurate profiling timer} + result := SDL_GetTicks() * 1000 +end; +*) +{$ELSEIF DEFINED(USE_SDL2)} +function getTimeMicro (): UInt64; inline; +begin + Result := SDL_GetPerformanceCounter() * 1000000 div SDL_GetPerformanceFrequency() +end; +{$ELSE} +function getTimeMicro: UInt64; inline; +begin + {$WARNING use stub profiling timer} +end; +{$ENDIF} + + +function getTimeMilli (): UInt64; inline; +begin + result := getTimeMicro() div 1000; +end; // ////////////////////////////////////////////////////////////////////////// // @@ -207,7 +272,7 @@ procedure TStopWatch.updateElapsed (); var e: UInt64; begin - e := curTimeMicro(); + e := getTimeMicro(); if (mStartPosition > e) then mStartPosition := e; Inc(mElapsed, e-mStartPosition); mStartPosition := e; @@ -239,7 +304,7 @@ end; procedure TStopWatch.start (reset: Boolean=true); begin if mRunning and not reset then exit; // nothing to do - mStartPosition := curTimeMicro(); + mStartPosition := getTimeMicro(); mRunning := true; if (reset) then mElapsed := 0; end; @@ -267,44 +332,53 @@ end; // ////////////////////////////////////////////////////////////////////////// // -procedure TProfilerBar.initialize (); begin hisHead := -1; curval := 0; end; +procedure TProfilerBar.initialize (aHistSize: Integer); begin SetLength(history, aHistSize); hisLast := -1; curAccum := 0; curAccumCount := 0; end; procedure TProfilerBar.update (val: Integer); var idx: Integer; begin if (val < 0) then val := 0; //else if (val > 1000000) val := 1000000; - if (hisHead = -1) then begin hisHead := 0; curval := 0; for idx := 0 to TProfHistorySize-1 do history[idx] := val; end; - history[hisHead] := val; - Inc(hisHead); - if (hisHead = TProfHistorySize) then hisHead := 0; - curval := FilterFadeoff*val+(1.0-FilterFadeoff)*curval; + if (hisLast = -1) then begin hisLast := High(history); curAccum := 0; curAccumCount := 0; for idx := 0 to High(history) do history[idx] := val; end; + if (curAccumCount = Length(history)) then Dec(curAccum, UInt64(history[(hisLast+1) mod Length(history)])) else Inc(curAccumCount); + Inc(hisLast); + if (hisLast >= Length(history)) then hisLast := 0; + Inc(curAccum, UInt64(val)); + history[hisLast] := val; + //curval := FilterFadeoff*val+(1.0-FilterFadeoff)*curval; end; function TProfilerBar.getvalue (): Integer; -//var idx: Integer; +{$IFDEF XPROFILER_SLOW_AVERAGE} +var idx: Integer; +{$ENDIF} begin - result := round(curval); - { + {$IFDEF XPROFILER_SLOW_AVERAGE} result := 0; - for idx := 0 to TProfHistorySize-1 do Inc(result, history[idx]); - result := result div TProfHistorySize; - } + for idx := 0 to High(history) do Inc(result, history[idx]); + result := result div Length(history); + {$ELSE} + //result := round(curval); + if curAccumCount > 0 then result := Integer(curAccum div curAccumCount) else result := 0; + {$ENDIF} end; -function TProfilerBar.getcount (): Integer; begin result := TProfHistorySize; end; +function TProfilerBar.getcount (): Integer; begin result := Length(history); end; function TProfilerBar.getvalat (idx: Integer): Integer; begin - if (idx < 0) or (idx >= TProfHistorySize) then result := 0 else result := history[(hisHead-idx-1+TProfHistorySize*2) mod TProfHistorySize]; + if (idx < 0) or (idx >= Length(history)) then result := 0 else result := history[(hisLast-idx+Length(history)*2) mod Length(history)]; end; // ////////////////////////////////////////////////////////////////////////// // -constructor TProfiler.Create (aName: AnsiString); +constructor TProfiler.Create (aName: AnsiString; aHistSize: Integer); begin name := aName; bars := nil; + if (aHistSize < 10) then aHistSize := 10; + if (aHistSize > 10000) then aHistSize := 10000; + histSize := aHistSize; {$IF DEFINED(STOPWATCH_IS_HERE)} xptimer.clear(); xpsecs := nil; @@ -315,7 +389,10 @@ end; destructor TProfiler.Destroy (); +var + idx: Integer; begin + for idx := 0 to High(bars) do bars[idx].history := nil; bars := nil; {$IF DEFINED(STOPWATCH_IS_HERE)} xpsecs := nil; @@ -369,11 +446,11 @@ begin SetLength(bars, xpsused+1); for idx := 1 to xpsused do begin - bars[idx].initialize(); + bars[idx].initialize(histSize); bars[idx].mName := xpsecs[idx-1].name; bars[idx].mLevel := xpsecs[idx-1].level+1; end; - bars[0].initialize(); + bars[0].initialize(histSize); bars[0].mName := name; bars[0].mLevel := 0; end; @@ -392,7 +469,7 @@ begin if (length(bars) <> 1) then begin SetLength(bars, 1); - bars[0].initialize(); + bars[0].initialize(histSize); bars[0].mName := name; bars[0].mLevel := 0; end; @@ -401,7 +478,7 @@ begin {$ENDIF} end; -procedure TProfiler.sectionBegin (name: AnsiString); +procedure TProfiler.sectionBegin (aName: AnsiString); {$IF DEFINED(STOPWATCH_IS_HERE)} var sid: Integer; @@ -415,7 +492,7 @@ begin sid := xpsused; Inc(xpsused); pss := @xpsecs[sid]; - pss.name := name; + pss.name := aName; pss.timer.clear(); pss.prevAct := xpscur; // calculate level @@ -425,7 +502,7 @@ begin {$ENDIF} end; -procedure TProfiler.sectionBeginAccum (name: AnsiString); +procedure TProfiler.sectionBeginAccum (aName: AnsiString); {$IF DEFINED(STOPWATCH_IS_HERE)} var idx: Integer; @@ -437,10 +514,10 @@ begin begin for idx := 0 to xpsused-1 do begin - if (xpsecs[idx].name = name) then + if (xpsecs[idx].name = aName) then begin - if (idx = xpscur) then raise Exception.Create('profiler error(0): dobule resume: "'+name+'"'); - if (xpsecs[idx].prevAct <> -1) then raise Exception.Create('profiler error(1): dobule resume: "'+name+'"'); + if (idx = xpscur) then raise Exception.Create('profiler error(0): double resume: "'+aName+'"'); + if (xpsecs[idx].prevAct <> -1) then raise Exception.Create('profiler error(1): double resume: "'+aName+'"'); xpsecs[idx].prevAct := xpscur; xpscur := idx; xpsecs[idx].timer.resume(); @@ -448,7 +525,7 @@ begin end; end; end; - sectionBegin(name); + sectionBegin(aName); {$ENDIF} end; @@ -470,4 +547,6 @@ begin end; +begin + initTimerIntr(); end.