Appearance
| 1 | namespace Logging is | |
| 2 | use IO.Std; | |
| 3 | ||
| 4 | use System.Text.StringBuilder; | |
| 5 | ||
| 6 | use Collections.MAP; | |
| 7 | ||
| 8 | class TIMER is | |
| 9 | _name: string; | |
| 10 | _execute_time: System.TimeSpan; | |
| 11 | ||
| 12 | _started_at: System.DateTime; | |
| 13 | ||
| 14 | name: string => _name; | |
| 15 | ||
| 16 | valid: bool => execute_count > 0; | |
| 17 | execute_count: int; | |
| 18 | average_milliseconds: double => _execute_time.divide(cast double(execute_count)).total_milliseconds; | |
| 19 | moving_average_milliseconds: double; | |
| 20 | ||
| 21 | max_average_milliseconds: double is | |
| 22 | if !valid then | |
| 23 | return 0.0D; | |
| 24 | fi | |
| 25 | ||
| 26 | let result = average_milliseconds; | |
| 27 | ||
| 28 | if result > moving_average_milliseconds then | |
| 29 | return result | |
| 30 | else | |
| 31 | return moving_average_milliseconds | |
| 32 | fi | |
| 33 | si | |
| 34 | ||
| 35 | init(name: string) is | |
| 36 | _name = name; | |
| 37 | _execute_time = System.TimeSpan(0L); | |
| 38 | si | |
| 39 | ||
| 40 | start() is | |
| 41 | _started_at = System.DateTime.now; | |
| 42 | si | |
| 43 | ||
| 44 | // Count an occurrence without timing it. For names used only as | |
| 45 | // counters the report renders count with zero accumulated time. | |
| 46 | bump() is | |
| 47 | execute_count = execute_count + 1; | |
| 48 | si | |
| 49 | ||
| 50 | finish() is | |
| 51 | let elapsed = System.DateTime.now.subtract(_started_at); | |
| 52 | ||
| 53 | execute_count = execute_count + 1; | |
| 54 | _execute_time = _execute_time.add(elapsed); | |
| 55 | ||
| 56 | moving_average_milliseconds = moving_average_milliseconds * 0.8D + elapsed.total_milliseconds * 0.2D; | |
| 57 | si | |
| 58 | ||
| 59 | to_string() -> string => | |
| 60 | if execute_count > 0 then | |
| 61 | "{_name} count: {execute_count} total time: {_execute_time.total_milliseconds} average: {average_milliseconds} moving average: {moving_average_milliseconds:N3} ms"; | |
| 62 | else | |
| 63 | "{_name} count: 0"; | |
| 64 | fi; | |
| 65 | si | |
| 66 | ||
| 67 | class TIMERS is | |
| 68 | _timers: MAP[string,TIMER]; | |
| 69 | ||
| 70 | init() is | |
| 71 | _timers = MAP(); | |
| 72 | si | |
| 73 | ||
| 74 | [name: string]: TIMER is | |
| 75 | if !_timers.contains_key(name) then | |
| 76 | _timers[name] = TIMER(name); | |
| 77 | fi | |
| 78 | ||
| 79 | return _timers[name]; | |
| 80 | si | |
| 81 | ||
| 82 | all: Collections.Iterable[TIMER] => _timers.values; | |
| 83 | ||
| 84 | edit_timer: TIMER => | |
| 85 | self["edit"]; | |
| 86 | ||
| 87 | edit_single_timer: TIMER => | |
| 88 | self["edit-single"]; | |
| 89 | ||
| 90 | compile_timer: TIMER => | |
| 91 | self["compile"]; | |
| 92 | ||
| 93 | start(name: string) is | |
| 94 | self[name].start(); | |
| 95 | si | |
| 96 | ||
| 97 | finish(name: string) is | |
| 98 | self[name].finish(); | |
| 99 | si | |
| 100 | ||
| 101 | bump(name: string) is | |
| 102 | self[name].bump(); | |
| 103 | si | |
| 104 | ||
| 105 | // Create a counter without recording an occurrence, so a name | |
| 106 | // that has not fired still appears in the report at count zero. | |
| 107 | // The indexer creates on first read. | |
| 108 | declare(name: string) is | |
| 109 | let _ = self[name]; | |
| 110 | si | |
| 111 | ||
| 112 | to_string() -> string => val | |
| 113 | let result = StringBuilder(); | |
| 114 | ||
| 115 | for t in _timers.values do | |
| 116 | if t.execute_count > 0 then | |
| 117 | result | |
| 118 | .append(t) | |
| 119 | .append('\n'); | |
| 120 | fi | |
| 121 | od | |
| 122 | ||
| 123 | result.to_string(); | |
| 124 | lav; | |
| 125 | si | |
| 126 | si |