3. Loops

3.1. Non-Unique Stamps

time.sleep(0.1)
gt.stamp('first')
for i in [1, 2, 3]:
    time.sleep(0.1)
    gt.stamp('loop', unique=False)
time.sleep(0.1)
gt.stamp('second')
print gt.report()
>> ---Begin Timer Report (root)---
>> Timer Name:          root
>> Total Time (s):      0.5031
>> Stamps Sum:          0.5026
>> Self Time (Agg.):    0.0001128
>>  
>>  
>> Intervals
>> ---------
>> first .............. 0.1017
>> loop ............... 0.3006
>> second ............. 0.1002
>>  
>> ---End Timer Report (root)---

Setting the unique flag of a stamp to False allows it to accumulate time at every iteration. Use of the unique flag also allows times from disjoint segments of code to be assigned to the same stamp name. (In general, enforcing uniqueness helps prevent accidental mishandling of measurements–G-Timer uses the names of stamps and timers as identifiers.)

3.2. Timed For

time.sleep(0.1)
gt.stamp('first')
for i in gt.timed_for([1, 2, 3]):
    time.sleep(0.1)
    gt.stamp('loop_1')
    if i > 1:
        time.sleep(0.1)
        gt.stamp('loop_2')
time.sleep(0.1)
gt.stamp('second')
print gt.report()
>> ---Begin Timer Report (root)---
>> Timer Name:          root
>> Total Time (s):      0.7037
>> Stamps Sum:          0.703
>> Self Time (Agg.):    0.0002031
>>  
>>  
>> Intervals
>> ---------
>> first .............. 0.1017
>> loop_1 ............. 0.3006
>> loop_2 ............. 0.2004
>> second ............. 0.1003
>>  
>>  
>> Loop Iterations
>> ---------------
>>  
>> Timer:       root
>>  
>>                Total    Mean     Max     Min     Num
>>               ------  ------  ------  ------  ------
>> loop_1          0.30    0.10    0.10    0.10       3
>> loop_2          0.20    0.10    0.10    0.10       2
>>  
>>  
>> Iter.        loop_1        loop_2
>> -----       -------       -------
>> 0              0.10          0.10
>> 1              0.10          0.10
>> 2              0.10              
>>  
>>  
>> ---End Timer Report (root)---

The loop in this example is termed an “anonymous” loop, since the intervals within it are recorded flat in the hierarchy of the surrounding code.

3.3. Timed While

time.sleep(0.1)
gt.stamp('first')
loop = gt.timed_loop('named_loop')
x = 0
while x < 3:
    next(loop)
    time.sleep(0.1)
    x += 1
    gt.stamp('loop')
loop.exit()
time.sleep(0.1)
gt.stamp('second')
print gt.report(include_itrs=False)
>> ---Begin Timer Report (root)---
>> Timer Name:          root
>> Total Time (s):      0.5035
>> Stamps Sum:          0.5028
>> Self Time (Agg.):    0.0001996
>>  
>>  
>> Intervals
>> ---------
>> first .............. 0.1016
>> named_loop ......... 0.3008
>>   (named_loop)
>>   loop ............... 0.3007
>> second ............. 0.1003
>>  
>>  
>> Loop Iterations
>> ---------------
>>  
>> Timer:       root
>>
>>                Total    Mean     Max     Min     Num
>>               ------  ------  ------  ------  ------
>> named_loop      0.30    0.10    0.10    0.10       3
>>  
>>  
>> Timer:       named_loop
>> Lineage:     root (named_loop)
>>
>>                Total    Mean     Max     Min     Num
>>               ------  ------  ------  ------  ------
>> loop            0.30    0.10    0.10    0.10       3
>>  
>>  
>> ---End Timer Report (root)---

The timed_loop() command returns a timed loop object which can be iterated using either the built-in next(loop) or loop.next(). Place this as the first line inside the loop. At the first line past the loop, call loop.exit() to finish loop recording. The optional name provided to the loop is used in two places: as a stamp name in the surrounding timer and as the timer name for a subdivision that exists only within the loop. (In this case, with only one stamp inside the loop, that data is redundant.)

3.4. Timed Loop Details

timed_loop() and timed_for() both return objects that can be used as context managers:

with gt.timed_loop('named_loop') as loop:
    while x < 3:
        next(loop)
        do_unto_x()
        gt.stamp('loop')

When a timed_for loop used without context management needs to be broken, the loop’s exit() must be called explicitly. Redundant exits do no harm. The timed_loop object can be used in both for and while loops.

Each timed loop must use a new instance. This means an inner loop object must be (re-)instantiated within the outer loop. Due to name-checking, anonymous inner loops are not supported–all inner timed loops must be named (plain inner loops using non-unique stamps are OK).

3.4.1. Registered Stamps

Registering stamps (using the rgstr_stamps timed loop keyword) will cause a 0 to be listed in any iteration in which the stamp was not encountered. This would change the report for loop_2 in example 2. The option to register stamps is also available for subdivisions, in case of conditional stamps in subfunctions called repeatedly.