Profiler class. self.cur is always a tuple. Each such tuple corresponds to a stack frame that is currently active (self.cur[-2]). The following are the definitions of its members. We use this external "parallel stack" to avoid contaminating the program that we are profiling.
| 101 | |
| 102 | |
| 103 | class Profile: |
| 104 | """Profiler class. |
| 105 | |
| 106 | self.cur is always a tuple. Each such tuple corresponds to a stack |
| 107 | frame that is currently active (self.cur[-2]). The following are the |
| 108 | definitions of its members. We use this external "parallel stack" to |
| 109 | avoid contaminating the program that we are profiling. (old profiler |
| 110 | used to write into the frames local dictionary!!) Derived classes |
| 111 | can change the definition of some entries, as long as they leave |
| 112 | [-2:] intact (frame and previous tuple). In case an internal error is |
| 113 | detected, the -3 element is used as the function name. |
| 114 | |
| 115 | [ 0] = Time that needs to be charged to the parent frame's function. |
| 116 | It is used so that a function call will not have to access the |
| 117 | timing data for the parent frame. |
| 118 | [ 1] = Total time spent in this frame's function, excluding time in |
| 119 | subfunctions (this latter is tallied in cur[2]). |
| 120 | [ 2] = Total time spent in subfunctions, excluding time executing the |
| 121 | frame's function (this latter is tallied in cur[1]). |
| 122 | [-3] = Name of the function that corresponds to this frame. |
| 123 | [-2] = Actual frame that we correspond to (used to sync exception handling). |
| 124 | [-1] = Our parent 6-tuple (corresponds to frame.f_back). |
| 125 | |
| 126 | Timing data for each function is stored as a 5-tuple in the dictionary |
| 127 | self.timings[]. The index is always the name stored in self.cur[-3]. |
| 128 | The following are the definitions of the members: |
| 129 | |
| 130 | [0] = The number of times this function was called, not counting direct |
| 131 | or indirect recursion, |
| 132 | [1] = Number of times this function appears on the stack, minus one |
| 133 | [2] = Total time spent internal to this function |
| 134 | [3] = Cumulative time that this function was present on the stack. In |
| 135 | non-recursive functions, this is the total execution time from start |
| 136 | to finish of each invocation of a function, including time spent in |
| 137 | all subfunctions. |
| 138 | [4] = A dictionary indicating for each function name, the number of times |
| 139 | it was called by us. |
| 140 | """ |
| 141 | |
| 142 | bias = 0 # calibration constant |
| 143 | |
| 144 | def __init__(self, timer=None, bias=None): |
| 145 | self.timings = {} |
| 146 | self.cur = None |
| 147 | self.cmd = "" |
| 148 | self.c_func_name = "" |
| 149 | |
| 150 | if bias is None: |
| 151 | bias = self.bias |
| 152 | self.bias = bias # Materialize in local dict for lookup speed. |
| 153 | |
| 154 | if not timer: |
| 155 | self.timer = self.get_time = time.process_time |
| 156 | self.dispatcher = self.trace_dispatch_i |
| 157 | else: |
| 158 | self.timer = timer |
| 159 | t = self.timer() # test out timer function |
| 160 | try: |