-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Improves timer to track mean and std #3233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Improves timer to track mean and std #3233
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, mostly NITs
""" | ||
|
||
def update_welford(self, value: float): | ||
"""Update the welford's algorithm with a new value.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add args to docstring.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is a private method, please start it with "_" and move it to the end of the file.
Would be good to link to the Welford's algorithm description to make it easier for new user.
|
||
@staticmethod | ||
def get_timer_statistics(name: str) -> dict[str, float]: | ||
"""Retrieves the time logged in the global dictionary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please add args to docstring.
# Check if the format is valid | ||
assert format in ["s", "ms", "us", "ns"], f"Invalid format, {format} is not in [s, ms, us, ns]" | ||
# Convert the format to a multiplier | ||
self._multiplier = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT:
self._multiplier = { | |
self._unit_multiplier = { |
@AntoineRichard Thanks this seems very useful out of curious, |
@@ -60,36 +63,68 @@ class Timer(ContextDecorator): | |||
Reference: https://gist.github.com/sumeet/1123871 | |||
""" | |||
|
|||
timing_info: ClassVar[dict[str, float]] = dict() | |||
timing_info: ClassVar[dict[str, dict[str, float]]] = dict() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the second dict
for? Can you update the docstring for it?
"""Dictionary for storing the elapsed time per timer instances globally. | ||
|
||
This dictionary logs the timer information. The keys are the names given to the timer class | ||
at its initialization. If no :attr:`name` is passed to the constructor, no time | ||
is recorded in the dictionary. | ||
""" | ||
|
||
def __init__(self, msg: str | None = None, name: str | None = None): | ||
enable = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a class variable?
enable = True | |
enable: ClassVar[bool] = True |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I need to rename it. I'll do a pass now to address all the comments! Thanks :)
""" | ||
self._msg = msg | ||
self._name = name | ||
self._start_time = None | ||
self._stop_time = None | ||
self._elapsed_time = None | ||
self._enable = enable if Timer.enable else False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems a bit unintuitive. If a user sets the flag as input, I would have assumed that they want the timer to be enabled?
Also, maybe it is better to rename the global enable
flag to something more dinstinctful to avoid confusion with local _enable
variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The global flag is here to allow to toggle these off when running trainings, but toggle them on when running benchmarks. The idea is that we can have permanent probing points in the code that are only enabled when running the benchmarks. Alternatively we could create groups, and toggle on or off some specific groups. So the idea with the enable override is to allow killing the timers when we want from a global flag. But I guess an argument could be made to use a global variable as the input of these timers?
self._format = format | ||
|
||
# Check if the format is valid | ||
assert format in ["s", "ms", "us", "ns"], f"Invalid format, {format} is not in [s, ms, us, ns]" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm using ValueError is better than assertion error here.
"s": 1.0, | ||
"ms": 1000.0, | ||
"us": 1000000.0, | ||
"ns": 1000000000.0, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"s": 1.0, | |
"ms": 1000.0, | |
"us": 1000000.0, | |
"ns": 1000000000.0, | |
"s": 1.0, | |
"ms": 1.0e3, | |
"us": 1.0e6, | |
"ns": 1.0e9, |
Easier to follow than counting zeros ;)
} | ||
|
||
""" | ||
Online welford's algorithm to compute the mean and std of the elapsed time |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Online welford's algorithm to compute the mean and std of the elapsed time | |
Internal Helpers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you update the usage of the class in the docstrings to use these new features? Otherwise they get burried :)
Also now, is it going over per-line of code to get statistics or you had other timers as well in the codebase to log?
Pre physics step took: Last: 13.959998 us, Mean: 16.989330 us, Std: 16.355029 us, N: 97
Apply action took: Last: 57.998001 us, Mean: 70.876819 us, Std: 17.586332 us, N: 193
Newton simulation step took: Last: 2361.953000 us, Mean: 2410.160786 us, Std: 184.928652 us, N: 192
Apply action took: Last: 73.888001 us, Mean: 70.892340 us, Std: 17.542273 us, N: 194
Newton simulation step took: Last: 2274.202998 us, Mean: 2409.456342 us, Std: 184.707038 us, N: 193
Get dones took: Last: 503.935000 us, Mean: 3176.439361 us, Std: 25855.625066 us, N: 97
Get rewards took: Last: 100.394001 us, Mean: 785.672928 us, Std: 6466.543603 us, N: 97
Reset idx took: Last: 1173.642002 us, Mean: 2392.515064 us, Std: 9785.688885 us, N: 62
Get observations took: Last: 78.683999 us, Mean: 107.013663 us, Std: 201.971979 us, N: 98
You also need to update the timer test: https://github.com/isaac-sim/IsaacLab/blob/main/source/isaaclab/test/utils/test_timer.py
Thanks Octi! It's not in yet. But I want to rework the benchmarking to set this global flag to True and add some probing points, in the code. We could add some default args to enable the timer and its display. |
I had a bunch of timers where I wanted to measure the time in the direct locomotion envs. |
67ac7c3
to
6d19bdd
Compare
We could make the decorator one a no-op, but the context manager is trickier. Here is some early tests with 1e6 function calls, decorated, or within a timer context:
The decorator method with no-op works well, but the context one is more painful because the object gets created every time we hit the context block. |
…or context managers and group enable / disable rather than an ugly global flag.
@AntoineRichard are you anticipating more changes for this or is it ready for merge? |
Description
Improved the timer to track mean and standard deviation. Also added some options to enable or disable it, as well as display different units.
Fixes #3232
We can now toggle the timers on or off using global flags:
They support different typer of display units:
s
for secondsms
for millisecondsus
for microsecondsns
for nanosecondsIt supports local flags to turn it on or off:
Type of change
Sample output:
Checklist
pre-commit
checks with./isaaclab.sh --format
config/extension.toml
fileCONTRIBUTORS.md
or my name already exists there