-
-
Notifications
You must be signed in to change notification settings - Fork 150
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
Memory profiling and fixing memory leak #270
Conversation
@angelala3252 |
openadapt/record.py
Outdated
stat.size_diff / 1024, | ||
stat.size / 1024, | ||
stat.count_diff, | ||
stat.count)) |
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 do you think about:
new_KiB = stat.size_diff / 1024
total_KiB = stat.size / 1024
new_blocks = stat.count_diff
total_blocks = stat.count
logger.info(f"{new_KiB=} {total_KiB=} {new_blocks=} {total_blocks=}")
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.
openadapt/record.py
Outdated
for line in stat.traceback.format(): | ||
print(line) | ||
|
||
tr.print_diff() |
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 there a way to get the value as a string, e.g.:
trace_str = tr.get_diff_str()
logger.info(f"trace_str=\n{trace_str}")
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.
Excellent work @angelala3252 ! What else is required here in order to be ready for review? |
@abrichr The only thing left to do is plotting the memory usage over time |
openadapt/record.py
Outdated
@@ -32,12 +40,15 @@ | |||
"action": True, | |||
"window": True, | |||
} | |||
PLOT_PERFORMANCE = False | |||
|
|||
PLOT_PERFORMANCE = 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.
What do you think about moving this to config.py
?
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.
done in a9828dd
openadapt/record.py
Outdated
|
||
stats = performance_snapshots[-1].compare_to(performance_snapshots[-2], 'lineno') | ||
|
||
for stat in stats[:3]: |
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.
Why stats[:3]
and not just stats
?
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.
just stats
would show every single memory allocation and there are a lot, so it fills up the logging with a lot of insignificant memory allocations that only take a few bytes. I've defined a constant NUM_MEMORY_STATS
for the 3 in e96b942, so we could change that to 5 or 10 or however many stats we want to see.
Thanks @angelala3252 ! Can you please show an updated screenshot? Also please fix merge conflicts 🙏 |
@abrichr resolved merge conflicts and addressed comments |
openadapt/record.py
Outdated
PLOT_PERFORMANCE = False | ||
PLOT_PERFORMANCE = config.PLOT_PERFORMANCE | ||
BYTE_TO_MB = float(2**20) | ||
NUM_MEMORY_STATS = 3 |
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 just to limit the log output?
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.
Yeah, without it every single memory allocation would be displayed, even the tiny insignificant ones. If you want more output I could change it to something like 5 or 10.
@abrichr ready for review |
openadapt/models.py
Outdated
|
||
id = sa.Column(sa.Integer, primary_key=True) | ||
recording_timestamp = sa.Column(sa.Integer) | ||
memory_usage = sa.Column(ForceFloat) |
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.
@angelala3252 can you please rename this to something more descriptive, e.g. memory_usage_kb
(or similar)?
Also, I noticed in the migration that the type does not match:
sa.Column('memory_usage', sa.Integer(), nullable=True),
sa.Column('timestamp', sa.Integer(), nullable=True),
And when I try to run alembic upgrade head
I get:
KeyError: '3d3239ae4849'
This suggests to me that you created the revision off of a stale database state.
Can you please:
- delete openadapt.db
- check out main
alembic upgrade head
- check out this branch
alembic revision ...
- replace the current migration script with the new one
You may need to import the ForceFloat type.
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.
Thanks @angelala3252 ! I get this exception when creating a recording:
It looks like |
openadapt/record.py
Outdated
process = psutil.Process(record_pid) | ||
|
||
while not terminate_event.is_set(): | ||
mem_usage = getattr(process, "memory_info")()[0] / BYTE_TO_MB |
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.
@angelala3252 can you please clarify why it is necessary to use getattr
here instead of just process.memory_info
?
Also, why use index access instead of attribute access? It's a named tuple, so we should be able to say .rss
instead of [0]
.
Also, why is it necessary to divide by BYTE_TO_MB
? Isn't this value already in bytes?
openadapt/utils.py
Outdated
timestamps = [] | ||
mem_usages = [] | ||
for mem_stat in mem_stats: | ||
mem_usages.append(mem_stat.memory_usage) |
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.
2023-07-02 11:06:12.633 | INFO | __mp_main__:memory_writer:525 - Memory writer done
Traceback (most recent call last):
File "/usr/local/Cellar/[email protected]/3.10.11/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
File "/usr/local/Cellar/[email protected]/3.10.11/Frameworks/Python.framework/Versions/3.10/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/Users/abrichr/oa/OpenAdapt/openadapt/record.py", line 764, in <module>
fire.Fire(record)
File "/Users/abrichr/Library/Caches/pypoetry/virtualenvs/openadapt-VBXg4jpm-py3.10/lib/python3.10/site-packages/fire/core.py", line 141, in Fire
component_trace = _Fire(component, args, parsed_flag_args, context, name)
File "/Users/abrichr/Library/Caches/pypoetry/virtualenvs/openadapt-VBXg4jpm-py3.10/lib/python3.10/site-packages/fire/core.py", line 466, in _Fire
component, remaining_args = _CallAndUpdateTrace(
File "/Users/abrichr/Library/Caches/pypoetry/virtualenvs/openadapt-VBXg4jpm-py3.10/lib/python3.10/site-packages/fire/core.py", line 681, in _CallAndUpdateTrace
component = fn(*varargs, **kwargs)
File "/Users/abrichr/oa/OpenAdapt/openadapt/record.py", line 90, in wrapper_logging
result = func(*args, **kwargs)
File "/Users/abrichr/oa/OpenAdapt/openadapt/record.py", line 753, in record
utils.plot_performance(recording_timestamp)
File "/Users/abrichr/oa/OpenAdapt/openadapt/utils.py", line 482, in plot_performance
mem_usages.append(mem_stat.memory_usage)
AttributeError: 'MemoryStat' object has no attribute 'memory_usage'
What kind of change does this PR introduce?
Bugfix and add memory profiling.
Checklist
Summary
This PR responds to Issue #5. The goal is to add memory profiling to
record.py
, add memory usage to performance plots, and fix the memory leak caused by the screenshots described here.How can your code be run and tested?