cengal.time_management.repeat_for_a_time.versions.v_0.repeat_for_a_time__python

  1#!/usr/bin/env python
  2# coding=utf-8
  3
  4# Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>
  5# 
  6# Licensed under the Apache License, Version 2.0 (the "License");
  7# you may not use this file except in compliance with the License.
  8# You may obtain a copy of the License at
  9# 
 10#     http://www.apache.org/licenses/LICENSE-2.0
 11# 
 12# Unless required by applicable law or agreed to in writing, software
 13# distributed under the License is distributed on an "AS IS" BASIS,
 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15# See the License for the specific language governing permissions and
 16# limitations under the License.
 17
 18import time
 19from enum import Enum
 20from time import time
 21from typing import Optional, Union
 22perf_counter = process_time = time
 23
 24try:
 25    from cengal.time_management.cpu_clock_cycles import perf_counter
 26except ImportError:
 27    try:
 28        from time import perf_counter
 29    except ImportError:
 30        pass
 31
 32try:
 33    from time import process_time
 34except ImportError:
 35    pass
 36
 37"""
 38Module Docstring
 39Docstrings: http://www.python.org/dev/peps/pep-0257/
 40"""
 41
 42__author__ = "ButenkoMS <gtalk@butenkoms.space>"
 43__copyright__ = "Copyright © 2012-2024 ButenkoMS. All rights reserved. Contacts: <gtalk@butenkoms.space>"
 44__credits__ = ["ButenkoMS <gtalk@butenkoms.space>", ]
 45__license__ = "Apache License, Version 2.0"
 46__version__ = "4.4.1"
 47__maintainer__ = "ButenkoMS <gtalk@butenkoms.space>"
 48__email__ = "gtalk@butenkoms.space"
 49# __status__ = "Prototype"
 50__status__ = "Development"
 51# __status__ = "Production"
 52
 53
 54class TimeLimitIsTooSmall(Exception):
 55    def __init__(self, min_time: Optional[Union[float, int]], *args: object) -> None:
 56        super().__init__(*args)
 57        self.min_time: Optional[Union[float, int]] = min_time
 58
 59
 60# TODO: add support for cpu_ticks_count
 61class ClockType(Enum):
 62    fake = 0
 63    clock = 1
 64    perf_counter = 2
 65    process_time = 3
 66
 67
 68def _fake():
 69    return 0
 70
 71
 72class BaseTracer:
 73    """
 74    Base class of all tracers
 75
 76    Lets assume you have a tracer:
 77
 78        tr = Tracer(10.0)
 79
 80    Or a fake tracer:
 81
 82        tr = TracerCounter(10000, 10.0)
 83
 84    As result you can use next interfaces
 85
 86        tr()  # Will return True if tracer has finished it's counting and as a result, the specified time was passed.
 87
 88        tr.iter_per_time_unit  # Will return counted time of iterations per second (if time() function uses second
 89            as a time unit)
 90
 91        tr.iterations_made  # Will return number of all iterations made (not including those that were produced after 
 92            the end of the counting)
 93
 94        tr.total_number_of_iterations_made  # Will return number of all iterations made (including those that were 
 95            produced after the end of the counting)
 96
 97        tr.time_spent  # Will return time spent (not including time that were used after the end of the counting)
 98
 99        tr.total_amount_of_time_spent  # Will return time spent (including time that were used after the end of the 
100            counting)
101
102        tr.clock_type  # Will return used time function type (ClockType enum)
103
104    """
105
106    def __init__(self, run_time: float, clock_type: ClockType=ClockType.perf_counter):
107        self.iter = None
108        self._number_of_iterations = 0
109        self._last_tracked_number_of_iterations = 0
110        self._start_time = None
111        self._end_time = None
112        self._relevant_stop_time = None
113        self._last_run_was_made = False
114        self._clock_type = clock_type
115        self._clock = None
116        self._init_clock()
117        self._run_time = run_time
118        if 0.0 == self._run_time:
119            raise TimeLimitIsTooSmall(None)
120
121    def __call__(self, *args, **kwargs):
122        return self._last_run_was_made
123    
124    def _init_clock(self):
125        if ClockType.fake == self._clock_type:
126            self._clock = _fake
127        elif ClockType.clock == self._clock_type:
128            self._clock = time
129        elif ClockType.perf_counter == self._clock_type:
130            self._clock = perf_counter
131        elif ClockType.process_time == self._clock_type:
132            self._clock = process_time
133
134    @property
135    def iter_per_time_unit(self):
136        raise NotImplemented()
137
138    @property
139    def iterations_made(self):
140        return self._last_tracked_number_of_iterations
141
142    @property
143    def total_number_of_iterations_made(self):
144        return self._number_of_iterations
145
146    @property
147    def time_spent(self):
148        return self._relevant_stop_time - self._start_time
149
150    @property
151    def total_amount_of_time_spent(self):
152        return self._end_time - self._start_time
153
154    @property
155    def clock_type(self) -> ClockType:
156        return self._clock_type
157
158    @clock_type.setter
159    def clock_type(self, value: ClockType):
160        self._clock_type = value
161        self._init_clock()
162
163
164class Tracer(BaseTracer):
165    """
166    Main tracer.
167    Its task is to find out the speed of code execution, and to stop the counting at about the specified time.
168
169    Example of use:
170
171        tr = Tracer(10.0)
172        while tr.iter():
173            i = '456'
174            k = int('1243' + i)
175
176        print('{} iter/s; {} seconds; {} iterations'.format(tr.iter_per_time_unit, tr.time_spent, tr.iterations_made))
177
178    """
179
180    def __init__(self, run_time: float, clock_type: ClockType=ClockType.perf_counter):
181        super().__init__(run_time, clock_type)
182        self._testing_worker = self._test_runs
183        self._half_of_the_run_time = self._run_time / 2
184        if 0.0 == self._half_of_the_run_time:
185            raise TimeLimitIsTooSmall(None)
186        self._relevant_start_time = None
187        self._relevant_number_of_iterations_at_start = 0
188        self._relevant_number_of_iterations_at_end = 0
189        self._next_test_stop_on = 1
190        self.iter = self._first_run
191
192    @property
193    def iter_per_time_unit(self) -> float:
194        if self._last_run_was_made:
195            divider = self._relevant_stop_time - self._relevant_start_time
196            if 0 != divider:
197                return (self._relevant_number_of_iterations_at_end - self._relevant_number_of_iterations_at_start) \
198                       / divider
199            return 0
200        else:
201            divider = self._end_time - self._start_time
202            if 0 != divider:
203                return self._last_tracked_number_of_iterations / divider
204            return 0
205
206    def _first_run(self) -> bool:
207        self._number_of_iterations += 1
208        self._relevant_start_time = self._start_time = self._clock()
209        self.iter = self._subsequent_runs
210        return self._test_sub_runs(self._start_time)
211
212    def _subsequent_runs(self) -> bool:
213        self._number_of_iterations += 1
214        if self._number_of_iterations >= self._next_test_stop_on:
215            return self._testing_worker()
216        return True
217
218    def _test_runs(self) -> bool:
219        return self._test_sub_runs(self._clock())
220
221    def _test_sub_runs(self, current_time) -> bool:
222        self._relevant_stop_time = self._end_time = current_time
223        self._last_tracked_number_of_iterations = self._number_of_iterations
224        delta_time = current_time - self._start_time
225        if delta_time >= self._half_of_the_run_time:
226            time_left = self._run_time - delta_time
227            # No need to:
228            # if time_left < 0:
229            #     time_left = 0
230            iterations_per_second = self._number_of_iterations / delta_time
231            iterations_left = iterations_per_second * time_left
232            if iterations_left > 0:
233                self._next_test_stop_on = self._number_of_iterations + round(iterations_left)
234                self._testing_worker = self._last_run
235                self._relevant_start_time = current_time
236                self._relevant_number_of_iterations_at_start = self._number_of_iterations
237                return True
238            else:
239                return self._last_sub_run(current_time)
240        self._next_test_stop_on *= 2
241        return True
242
243    def _last_run(self) -> bool:
244        return self._last_sub_run(self._clock())
245
246    def _last_sub_run(self, current_time) -> bool:
247        self._end_time = current_time
248        self._last_tracked_number_of_iterations = self._number_of_iterations
249        self._relevant_stop_time = self._end_time
250        self._relevant_number_of_iterations_at_end = self._number_of_iterations
251        self._testing_worker = self._after_last_runs
252        self._last_run_was_made = True
253        return False
254
255    def _after_last_runs(self) -> bool:
256        self._end_time = self._clock()
257        return False
258
259
260class GreedyTracer(BaseTracer):
261    """
262    Greedy Main tracer.
263    Its task is to find out the speed of code execution, and to stop the counting at about the specified time.
264    The difference is that he checks time every single iteration.
265
266    Example of use is the same as for the Tracer()
267
268    """
269
270    def __init__(self, run_time: float, clock_type=ClockType.perf_counter):
271        super().__init__(run_time, clock_type)
272        self.iter = self._first_run
273
274    def _first_run(self) -> bool:
275        self._start_time = self._clock()
276        self.iter = self._subsequent_runs
277        return self._subsequent_runs()
278
279    def _subsequent_runs(self) -> bool:
280        self._relevant_stop_time = self._end_time = self._clock()
281        self._number_of_iterations += 1
282        self._last_tracked_number_of_iterations = self._number_of_iterations
283        
284        if (self._relevant_stop_time - self._start_time) < self._run_time:
285            return True
286        else:
287            self._last_run_was_made = True
288            self.iter = self._after_last_runs
289            return False
290
291    def _after_last_runs(self) -> bool:
292        self._number_of_iterations += 1
293        self._end_time = self._clock()
294        return False
295
296    @property
297    def iter_per_time_unit(self) -> float:
298        divider = self._relevant_stop_time - self._start_time
299        if 0 != divider:
300            return self._last_tracked_number_of_iterations / divider
301        return 0
302
303
304class TracerCounter(BaseTracer):
305    """
306    Counting tracer. Pseudo-tracer.
307    Its don't have an overhead of periodic calling time() function.
308    Its task is to count down within a given time, using the speed information already counted by the real tracer
309    (by the Tracer class).
310
311    Example of use:
312
313        trc = TracerCounter(10000, 10.0)
314        while trc.iter():
315            i = '456'
316            k = int('1243' + i)
317
318        print('{} iter/s; {} seconds; {} iters'.format(trc.iter_per_time_unit, trc.time_spent, trc.iterations_made))
319
320    or:
321        def made_tests() -> Tracer:
322            tr = Tracer(0.1)  # Run for about 0.1 of second.
323            while tr.iter():
324                some_my_code()
325            return tr
326
327        def run(run_time: float, tests_result: Tracer):
328            trc = TracerCounter(tests_result.iter_per_time_unit, run_time)
329            while trc.iter():
330                some_my_code()
331
332            print('{} iter/s; {} seconds; {} iterations'.format(trc.iter_per_time_unit, trc.time_spent,
333                    trc.iterations_made))
334
335        def main():
336            tests_result = made_tests()
337            ...
338            while True:
339                time_to_rur_str = input('Enter run time: ')
340                if not time_to_run_str:
341                    break
342                run(float(time_to_rur_str), tests_result)
343
344    """
345
346    def __init__(self, iter_per_time_unit: float, run_time: float, clock_type=ClockType.fake):
347        super().__init__(run_time, clock_type)
348        self._iter_per_time_unit = iter_per_time_unit
349        self._number_of_iterations_needed = round(self._iter_per_time_unit * self._run_time)
350        self.iter = self._first_run
351
352    def _first_run(self) -> bool:
353        self._start_time = self._clock()
354        self.iter = self._subsequent_runs
355        return self._subsequent_runs()
356
357    def _subsequent_runs(self) -> bool:
358        self._number_of_iterations += 1
359        self._last_tracked_number_of_iterations = self._number_of_iterations
360        if self._number_of_iterations < self._number_of_iterations_needed:
361            return True
362        else:
363            self._relevant_stop_time = self._end_time = self._clock()
364            self._last_run_was_made = True
365            self.iter = self._after_last_runs
366            return False
367
368    def _after_last_runs(self) -> bool:
369        self._number_of_iterations += 1
370        self._end_time = self._clock()
371        return False
372
373    @property
374    def iter_per_time_unit(self) -> float:
375        if self._last_run_was_made:
376            divider = self._relevant_stop_time - self._start_time
377            if 0 != divider:
378                return self._last_tracked_number_of_iterations / divider
379            return 0
380        else:
381            return self._iter_per_time_unit
382
383
384class TracerIterator:
385    """
386    An iterator class. It converts any type of given tracer into an iterator.
387
388    As result you have an option to use constructions like this:
389
390        for i in TracerIterator(Tracer(20.0)):
391            k = int('1243')
392
393    But keep in mind that in this case there will be a bigger overhead. And there will be less CPU time for the payload.
394
395    """
396
397    def __init__(self, tracer: BaseTracer):
398        self._tracer = tracer
399
400    def __iter__(self):
401        return self
402
403    def __next__(self):
404        if self._tracer.iter():
405            return self._tracer.iterations_made
406        else:
407            raise StopIteration()
408
409    next = __next__
410
411    @property
412    def tracer(self):
413        return self._tracer
class TimeLimitIsTooSmall(builtins.Exception):
55class TimeLimitIsTooSmall(Exception):
56    def __init__(self, min_time: Optional[Union[float, int]], *args: object) -> None:
57        super().__init__(*args)
58        self.min_time: Optional[Union[float, int]] = min_time

Common base class for all non-exit exceptions.

TimeLimitIsTooSmall(min_time: Union[int, float, NoneType], *args: object)
56    def __init__(self, min_time: Optional[Union[float, int]], *args: object) -> None:
57        super().__init__(*args)
58        self.min_time: Optional[Union[float, int]] = min_time
min_time: Union[int, float, NoneType]
Inherited Members
builtins.BaseException
with_traceback
args
class ClockType(enum.Enum):
62class ClockType(Enum):
63    fake = 0
64    clock = 1
65    perf_counter = 2
66    process_time = 3

An enumeration.

fake = <ClockType.fake: 0>
clock = <ClockType.clock: 1>
perf_counter = <ClockType.perf_counter: 2>
process_time = <ClockType.process_time: 3>
Inherited Members
enum.Enum
name
value
class BaseTracer:
 73class BaseTracer:
 74    """
 75    Base class of all tracers
 76
 77    Lets assume you have a tracer:
 78
 79        tr = Tracer(10.0)
 80
 81    Or a fake tracer:
 82
 83        tr = TracerCounter(10000, 10.0)
 84
 85    As result you can use next interfaces
 86
 87        tr()  # Will return True if tracer has finished it's counting and as a result, the specified time was passed.
 88
 89        tr.iter_per_time_unit  # Will return counted time of iterations per second (if time() function uses second
 90            as a time unit)
 91
 92        tr.iterations_made  # Will return number of all iterations made (not including those that were produced after 
 93            the end of the counting)
 94
 95        tr.total_number_of_iterations_made  # Will return number of all iterations made (including those that were 
 96            produced after the end of the counting)
 97
 98        tr.time_spent  # Will return time spent (not including time that were used after the end of the counting)
 99
100        tr.total_amount_of_time_spent  # Will return time spent (including time that were used after the end of the 
101            counting)
102
103        tr.clock_type  # Will return used time function type (ClockType enum)
104
105    """
106
107    def __init__(self, run_time: float, clock_type: ClockType=ClockType.perf_counter):
108        self.iter = None
109        self._number_of_iterations = 0
110        self._last_tracked_number_of_iterations = 0
111        self._start_time = None
112        self._end_time = None
113        self._relevant_stop_time = None
114        self._last_run_was_made = False
115        self._clock_type = clock_type
116        self._clock = None
117        self._init_clock()
118        self._run_time = run_time
119        if 0.0 == self._run_time:
120            raise TimeLimitIsTooSmall(None)
121
122    def __call__(self, *args, **kwargs):
123        return self._last_run_was_made
124    
125    def _init_clock(self):
126        if ClockType.fake == self._clock_type:
127            self._clock = _fake
128        elif ClockType.clock == self._clock_type:
129            self._clock = time
130        elif ClockType.perf_counter == self._clock_type:
131            self._clock = perf_counter
132        elif ClockType.process_time == self._clock_type:
133            self._clock = process_time
134
135    @property
136    def iter_per_time_unit(self):
137        raise NotImplemented()
138
139    @property
140    def iterations_made(self):
141        return self._last_tracked_number_of_iterations
142
143    @property
144    def total_number_of_iterations_made(self):
145        return self._number_of_iterations
146
147    @property
148    def time_spent(self):
149        return self._relevant_stop_time - self._start_time
150
151    @property
152    def total_amount_of_time_spent(self):
153        return self._end_time - self._start_time
154
155    @property
156    def clock_type(self) -> ClockType:
157        return self._clock_type
158
159    @clock_type.setter
160    def clock_type(self, value: ClockType):
161        self._clock_type = value
162        self._init_clock()

Base class of all tracers

Lets assume you have a tracer:

tr = Tracer(10.0)

Or a fake tracer:

tr = TracerCounter(10000, 10.0)

As result you can use next interfaces

tr()  # Will return True if tracer has finished it's counting and as a result, the specified time was passed.

tr.iter_per_time_unit  # Will return counted time of iterations per second (if time() function uses second
    as a time unit)

tr.iterations_made  # Will return number of all iterations made (not including those that were produced after 
    the end of the counting)

tr.total_number_of_iterations_made  # Will return number of all iterations made (including those that were 
    produced after the end of the counting)

tr.time_spent  # Will return time spent (not including time that were used after the end of the counting)

tr.total_amount_of_time_spent  # Will return time spent (including time that were used after the end of the 
    counting)

tr.clock_type  # Will return used time function type (ClockType enum)
BaseTracer( run_time: float, clock_type: ClockType = <ClockType.perf_counter: 2>)
107    def __init__(self, run_time: float, clock_type: ClockType=ClockType.perf_counter):
108        self.iter = None
109        self._number_of_iterations = 0
110        self._last_tracked_number_of_iterations = 0
111        self._start_time = None
112        self._end_time = None
113        self._relevant_stop_time = None
114        self._last_run_was_made = False
115        self._clock_type = clock_type
116        self._clock = None
117        self._init_clock()
118        self._run_time = run_time
119        if 0.0 == self._run_time:
120            raise TimeLimitIsTooSmall(None)
iter
iter_per_time_unit
135    @property
136    def iter_per_time_unit(self):
137        raise NotImplemented()
iterations_made
139    @property
140    def iterations_made(self):
141        return self._last_tracked_number_of_iterations
total_number_of_iterations_made
143    @property
144    def total_number_of_iterations_made(self):
145        return self._number_of_iterations
time_spent
147    @property
148    def time_spent(self):
149        return self._relevant_stop_time - self._start_time
total_amount_of_time_spent
151    @property
152    def total_amount_of_time_spent(self):
153        return self._end_time - self._start_time
clock_type: ClockType
155    @property
156    def clock_type(self) -> ClockType:
157        return self._clock_type
class Tracer(BaseTracer):
165class Tracer(BaseTracer):
166    """
167    Main tracer.
168    Its task is to find out the speed of code execution, and to stop the counting at about the specified time.
169
170    Example of use:
171
172        tr = Tracer(10.0)
173        while tr.iter():
174            i = '456'
175            k = int('1243' + i)
176
177        print('{} iter/s; {} seconds; {} iterations'.format(tr.iter_per_time_unit, tr.time_spent, tr.iterations_made))
178
179    """
180
181    def __init__(self, run_time: float, clock_type: ClockType=ClockType.perf_counter):
182        super().__init__(run_time, clock_type)
183        self._testing_worker = self._test_runs
184        self._half_of_the_run_time = self._run_time / 2
185        if 0.0 == self._half_of_the_run_time:
186            raise TimeLimitIsTooSmall(None)
187        self._relevant_start_time = None
188        self._relevant_number_of_iterations_at_start = 0
189        self._relevant_number_of_iterations_at_end = 0
190        self._next_test_stop_on = 1
191        self.iter = self._first_run
192
193    @property
194    def iter_per_time_unit(self) -> float:
195        if self._last_run_was_made:
196            divider = self._relevant_stop_time - self._relevant_start_time
197            if 0 != divider:
198                return (self._relevant_number_of_iterations_at_end - self._relevant_number_of_iterations_at_start) \
199                       / divider
200            return 0
201        else:
202            divider = self._end_time - self._start_time
203            if 0 != divider:
204                return self._last_tracked_number_of_iterations / divider
205            return 0
206
207    def _first_run(self) -> bool:
208        self._number_of_iterations += 1
209        self._relevant_start_time = self._start_time = self._clock()
210        self.iter = self._subsequent_runs
211        return self._test_sub_runs(self._start_time)
212
213    def _subsequent_runs(self) -> bool:
214        self._number_of_iterations += 1
215        if self._number_of_iterations >= self._next_test_stop_on:
216            return self._testing_worker()
217        return True
218
219    def _test_runs(self) -> bool:
220        return self._test_sub_runs(self._clock())
221
222    def _test_sub_runs(self, current_time) -> bool:
223        self._relevant_stop_time = self._end_time = current_time
224        self._last_tracked_number_of_iterations = self._number_of_iterations
225        delta_time = current_time - self._start_time
226        if delta_time >= self._half_of_the_run_time:
227            time_left = self._run_time - delta_time
228            # No need to:
229            # if time_left < 0:
230            #     time_left = 0
231            iterations_per_second = self._number_of_iterations / delta_time
232            iterations_left = iterations_per_second * time_left
233            if iterations_left > 0:
234                self._next_test_stop_on = self._number_of_iterations + round(iterations_left)
235                self._testing_worker = self._last_run
236                self._relevant_start_time = current_time
237                self._relevant_number_of_iterations_at_start = self._number_of_iterations
238                return True
239            else:
240                return self._last_sub_run(current_time)
241        self._next_test_stop_on *= 2
242        return True
243
244    def _last_run(self) -> bool:
245        return self._last_sub_run(self._clock())
246
247    def _last_sub_run(self, current_time) -> bool:
248        self._end_time = current_time
249        self._last_tracked_number_of_iterations = self._number_of_iterations
250        self._relevant_stop_time = self._end_time
251        self._relevant_number_of_iterations_at_end = self._number_of_iterations
252        self._testing_worker = self._after_last_runs
253        self._last_run_was_made = True
254        return False
255
256    def _after_last_runs(self) -> bool:
257        self._end_time = self._clock()
258        return False

Main tracer. Its task is to find out the speed of code execution, and to stop the counting at about the specified time.

Example of use:

tr = Tracer(10.0)
while tr.iter():
    i = '456'
    k = int('1243' + i)

print('{} iter/s; {} seconds; {} iterations'.format(tr.iter_per_time_unit, tr.time_spent, tr.iterations_made))
Tracer( run_time: float, clock_type: ClockType = <ClockType.perf_counter: 2>)
181    def __init__(self, run_time: float, clock_type: ClockType=ClockType.perf_counter):
182        super().__init__(run_time, clock_type)
183        self._testing_worker = self._test_runs
184        self._half_of_the_run_time = self._run_time / 2
185        if 0.0 == self._half_of_the_run_time:
186            raise TimeLimitIsTooSmall(None)
187        self._relevant_start_time = None
188        self._relevant_number_of_iterations_at_start = 0
189        self._relevant_number_of_iterations_at_end = 0
190        self._next_test_stop_on = 1
191        self.iter = self._first_run
iter
iter_per_time_unit: float
193    @property
194    def iter_per_time_unit(self) -> float:
195        if self._last_run_was_made:
196            divider = self._relevant_stop_time - self._relevant_start_time
197            if 0 != divider:
198                return (self._relevant_number_of_iterations_at_end - self._relevant_number_of_iterations_at_start) \
199                       / divider
200            return 0
201        else:
202            divider = self._end_time - self._start_time
203            if 0 != divider:
204                return self._last_tracked_number_of_iterations / divider
205            return 0
class GreedyTracer(BaseTracer):
261class GreedyTracer(BaseTracer):
262    """
263    Greedy Main tracer.
264    Its task is to find out the speed of code execution, and to stop the counting at about the specified time.
265    The difference is that he checks time every single iteration.
266
267    Example of use is the same as for the Tracer()
268
269    """
270
271    def __init__(self, run_time: float, clock_type=ClockType.perf_counter):
272        super().__init__(run_time, clock_type)
273        self.iter = self._first_run
274
275    def _first_run(self) -> bool:
276        self._start_time = self._clock()
277        self.iter = self._subsequent_runs
278        return self._subsequent_runs()
279
280    def _subsequent_runs(self) -> bool:
281        self._relevant_stop_time = self._end_time = self._clock()
282        self._number_of_iterations += 1
283        self._last_tracked_number_of_iterations = self._number_of_iterations
284        
285        if (self._relevant_stop_time - self._start_time) < self._run_time:
286            return True
287        else:
288            self._last_run_was_made = True
289            self.iter = self._after_last_runs
290            return False
291
292    def _after_last_runs(self) -> bool:
293        self._number_of_iterations += 1
294        self._end_time = self._clock()
295        return False
296
297    @property
298    def iter_per_time_unit(self) -> float:
299        divider = self._relevant_stop_time - self._start_time
300        if 0 != divider:
301            return self._last_tracked_number_of_iterations / divider
302        return 0

Greedy Main tracer. Its task is to find out the speed of code execution, and to stop the counting at about the specified time. The difference is that he checks time every single iteration.

Example of use is the same as for the Tracer()

GreedyTracer(run_time: float, clock_type=<ClockType.perf_counter: 2>)
271    def __init__(self, run_time: float, clock_type=ClockType.perf_counter):
272        super().__init__(run_time, clock_type)
273        self.iter = self._first_run
iter
iter_per_time_unit: float
297    @property
298    def iter_per_time_unit(self) -> float:
299        divider = self._relevant_stop_time - self._start_time
300        if 0 != divider:
301            return self._last_tracked_number_of_iterations / divider
302        return 0
class TracerCounter(BaseTracer):
305class TracerCounter(BaseTracer):
306    """
307    Counting tracer. Pseudo-tracer.
308    Its don't have an overhead of periodic calling time() function.
309    Its task is to count down within a given time, using the speed information already counted by the real tracer
310    (by the Tracer class).
311
312    Example of use:
313
314        trc = TracerCounter(10000, 10.0)
315        while trc.iter():
316            i = '456'
317            k = int('1243' + i)
318
319        print('{} iter/s; {} seconds; {} iters'.format(trc.iter_per_time_unit, trc.time_spent, trc.iterations_made))
320
321    or:
322        def made_tests() -> Tracer:
323            tr = Tracer(0.1)  # Run for about 0.1 of second.
324            while tr.iter():
325                some_my_code()
326            return tr
327
328        def run(run_time: float, tests_result: Tracer):
329            trc = TracerCounter(tests_result.iter_per_time_unit, run_time)
330            while trc.iter():
331                some_my_code()
332
333            print('{} iter/s; {} seconds; {} iterations'.format(trc.iter_per_time_unit, trc.time_spent,
334                    trc.iterations_made))
335
336        def main():
337            tests_result = made_tests()
338            ...
339            while True:
340                time_to_rur_str = input('Enter run time: ')
341                if not time_to_run_str:
342                    break
343                run(float(time_to_rur_str), tests_result)
344
345    """
346
347    def __init__(self, iter_per_time_unit: float, run_time: float, clock_type=ClockType.fake):
348        super().__init__(run_time, clock_type)
349        self._iter_per_time_unit = iter_per_time_unit
350        self._number_of_iterations_needed = round(self._iter_per_time_unit * self._run_time)
351        self.iter = self._first_run
352
353    def _first_run(self) -> bool:
354        self._start_time = self._clock()
355        self.iter = self._subsequent_runs
356        return self._subsequent_runs()
357
358    def _subsequent_runs(self) -> bool:
359        self._number_of_iterations += 1
360        self._last_tracked_number_of_iterations = self._number_of_iterations
361        if self._number_of_iterations < self._number_of_iterations_needed:
362            return True
363        else:
364            self._relevant_stop_time = self._end_time = self._clock()
365            self._last_run_was_made = True
366            self.iter = self._after_last_runs
367            return False
368
369    def _after_last_runs(self) -> bool:
370        self._number_of_iterations += 1
371        self._end_time = self._clock()
372        return False
373
374    @property
375    def iter_per_time_unit(self) -> float:
376        if self._last_run_was_made:
377            divider = self._relevant_stop_time - self._start_time
378            if 0 != divider:
379                return self._last_tracked_number_of_iterations / divider
380            return 0
381        else:
382            return self._iter_per_time_unit

Counting tracer. Pseudo-tracer. Its don't have an overhead of periodic calling time() function. Its task is to count down within a given time, using the speed information already counted by the real tracer (by the Tracer class).

Example of use:

trc = TracerCounter(10000, 10.0)
while trc.iter():
    i = '456'
    k = int('1243' + i)

print('{} iter/s; {} seconds; {} iters'.format(trc.iter_per_time_unit, trc.time_spent, trc.iterations_made))

or: def made_tests() -> Tracer: tr = Tracer(0.1) # Run for about 0.1 of second. while tr.iter(): some_my_code() return tr

def run(run_time: float, tests_result: Tracer):
    trc = TracerCounter(tests_result.iter_per_time_unit, run_time)
    while trc.iter():
        some_my_code()

    print('{} iter/s; {} seconds; {} iterations'.format(trc.iter_per_time_unit, trc.time_spent,
            trc.iterations_made))

def main():
    tests_result = made_tests()
    ...
    while True:
        time_to_rur_str = input('Enter run time: ')
        if not time_to_run_str:
            break
        run(float(time_to_rur_str), tests_result)
TracerCounter( iter_per_time_unit: float, run_time: float, clock_type=<ClockType.fake: 0>)
347    def __init__(self, iter_per_time_unit: float, run_time: float, clock_type=ClockType.fake):
348        super().__init__(run_time, clock_type)
349        self._iter_per_time_unit = iter_per_time_unit
350        self._number_of_iterations_needed = round(self._iter_per_time_unit * self._run_time)
351        self.iter = self._first_run
iter
iter_per_time_unit: float
374    @property
375    def iter_per_time_unit(self) -> float:
376        if self._last_run_was_made:
377            divider = self._relevant_stop_time - self._start_time
378            if 0 != divider:
379                return self._last_tracked_number_of_iterations / divider
380            return 0
381        else:
382            return self._iter_per_time_unit
class TracerIterator:
385class TracerIterator:
386    """
387    An iterator class. It converts any type of given tracer into an iterator.
388
389    As result you have an option to use constructions like this:
390
391        for i in TracerIterator(Tracer(20.0)):
392            k = int('1243')
393
394    But keep in mind that in this case there will be a bigger overhead. And there will be less CPU time for the payload.
395
396    """
397
398    def __init__(self, tracer: BaseTracer):
399        self._tracer = tracer
400
401    def __iter__(self):
402        return self
403
404    def __next__(self):
405        if self._tracer.iter():
406            return self._tracer.iterations_made
407        else:
408            raise StopIteration()
409
410    next = __next__
411
412    @property
413    def tracer(self):
414        return self._tracer

An iterator class. It converts any type of given tracer into an iterator.

As result you have an option to use constructions like this:

for i in TracerIterator(Tracer(20.0)):
    k = int('1243')

But keep in mind that in this case there will be a bigger overhead. And there will be less CPU time for the payload.

TracerIterator( tracer: BaseTracer)
398    def __init__(self, tracer: BaseTracer):
399        self._tracer = tracer
def next(self):
404    def __next__(self):
405        if self._tracer.iter():
406            return self._tracer.iterations_made
407        else:
408            raise StopIteration()
tracer
412    @property
413    def tracer(self):
414        return self._tracer