-
Notifications
You must be signed in to change notification settings - Fork 19
More benchmarks #177
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
More benchmarks #177
Conversation
pytest-benchmark benchmark() function returns the results, so we can assert within the same test.
7905447 to
7c43ee4
Compare
|
|
||
| def test_find_shortest_chain(large_graph, benchmark): | ||
| result = benchmark(large_graph.find_shortest_chain, DEEP_LAYERS[0], DEEP_LAYERS[1]) | ||
| assert result is not None and len(result) == 5 |
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.
I think we don't need to assert against the exact result here. This file is intended for benchmarks, not full tests, so a quick sanity check seems fine to me.
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.
Another option could be to use snapshots, so that we can assert the exact results but they are not cluttering the benchmarks https://github.com/syrupy-project/syrupy
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.
It would be helpful to have it somewhere, at some point (to check feature parity between this and the Rust graph implementation) but I take your point, it could go somewhere else. Don't feel strongly about syrupy either way.
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.
I tried asserting against the exact result here, but it doesn't seem possible - find_shortest_chain/find_shortest_chains seem to return different results between runs? I guess there must be multiple chains of equal length?
73e089a to
303e910
Compare
| containers=("mypackage",), | ||
| ) | ||
| ) | ||
| assert result == { |
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.
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.
I'd rather we didn't remove these - we don't actually assert on the exact results of a large graph like this anywhere else and it does give me more confidence that things are happening correctly. Happy for it to be moved out of benchmarks if you feel strongly, but maybe we should leave that for a separate PR.
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.
Okay - put this back
CodSpeed Performance ReportMerging #177 will degrade performances by 66.81%Comparing Summary
Benchmarks breakdown
|
seddonym
left a comment
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 for looking at this, great addition.
For some reason the layer checks have become a lot slower though, any idea why? Maybe it's worth separating out commits adding the new benchmarks so we can add ASAP, then keep the other changes separate. Maybe it's a blip.
| graph = ImportGraph() | ||
|
|
||
| for importer, importeds in graph_dict.items(): | ||
| graph.add_module(importer) |
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.
Do we know why this changes the result? Adding the import should add any modules as per https://grimp.readthedocs.io/en/stable/usage.html#ImportGraph.add_import
To me this looks like we may have found a bug.
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.
I'm not entirely sure I understand why this changed the results and caused the performance slowdown.
One thing that is happening - the graph is now bigger. E.g. consider
{
"pkg.a": ["pkg.b"],
"pkg.c": []
}In the above JSON, the pkg.c module would not have been added before (since it has no imports, and nothing is importing it).
I've reordered the commits, so that the changes caused e.g. in number of modules becomes more obvious now.
Even though I don't fully understand why this happens entirely, I am entirely confident in this change to the benchmarks file. I.e. we certainly should be calling graph.add_module(importer), and the import path that we now find is correct (agrees with pyimports). So I think there's no harm to avoid merging this.
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.
Okay I understand it now.
result = large_graph.find_illegal_dependencies_for_layers(
layers=(
# mypackage.foo and mypackage.bar do not exist!!!
"foo",
"bar",
),
containers=("mypackage",),
)
assert result == set()The above passes ☝️ So it looks like find_illegal_dependencies_for_layers does not error if the layer modules cannot be found in the graph. Presumably this is by design?
If we look at large graph JSON we have e.g.
"mypackage.domain": [],This is the only occurence of "mypackage.domain" in that file. So - mypackage.domain is not importing anything, and nothing is importing it - hence the module is not added to the graph.
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.
So sadly the test_top_level_large_graph was not doing anything before 😅 Hence why it is now slower - because it actually does some work!
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.
Ha ok, makes sense.
The silent failure is by design only to the point of feature parity, but I think it would be worth changing it at some point. Not now though.
| containers=("mypackage",), | ||
| ) | ||
| ) | ||
| assert result == { |
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.
I'd rather we didn't remove these - we don't actually assert on the exact results of a large graph like this anywhere else and it does give me more confidence that things are happening correctly. Happy for it to be moved out of benchmarks if you feel strongly, but maybe we should leave that for a separate PR.
| benchmark(fn) | ||
|
|
||
|
|
||
| def test_find_descendants(large_graph, benchmark): |
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.
Might be worth using benchmark.pedantic for each of these, like with the others, so we get to average out the runs. That will only apply to a local run.
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 it.
🐼 I'm not fully sure what this does. Even without pedantic pytest-benchmark will run many iterations and take an average. What's the difference between between iterations and rounds here?
|
|
||
| def test_find_shortest_chain(large_graph, benchmark): | ||
| result = benchmark(large_graph.find_shortest_chain, DEEP_LAYERS[0], DEEP_LAYERS[1]) | ||
| assert result is not None and len(result) == 5 |
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.
It would be helpful to have it somewhere, at some point (to check feature parity between this and the Rust graph implementation) but I take your point, it could go somewhere else. Don't feel strongly about syrupy either way.
| assert result is None | ||
|
|
||
|
|
||
| def test_find_shortest_chains(large_graph, benchmark): |
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.
Mind grouping these tests for the same method into a TestFindShortestChains class?
303e910 to
e8c064a
Compare
| def test_find_descendants(large_graph, benchmark): | ||
| result = _run_benchmark(benchmark, large_graph.find_descendants, "mypackage") | ||
| assert len(result) == 17348 | ||
| assert len(result) == 28222 |
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.
FYI @seddonym - see here that fixing the graph increases the number of modules. I.e. we were missing many modules before.
| ) | ||
| assert result is not None | ||
|
|
||
| @pytest.mark.xfail("grimp.exceptions.ModuleNotPresent") |
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.
FYI @seddonym - see here that fixing the graph means that the module mypackage.data.vendors.4053192739.6373932949 now exists, as it should!
We should still add modules, even if they have no imports.
e8c064a to
455fed2
Compare
seddonym
left a comment
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.
Great stuff
This PR adds some more benchmarks. I'm making some progress on the rust graph here, but it would be helpful to have a few more benchmarks in place so that we can measure more things. Currently we only have building the graph and illegal layers - there's quite a lot of ground inbetween and the gap feels a bit daunting!
It also adds a fix for the existing benchmarks, when building the large graph.