Skip to content
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

Performance improvements related to best_effort_copy #57

Merged
merged 2 commits into from
Dec 1, 2023

Conversation

JamesHutchison
Copy link
Owner

@JamesHutchison JamesHutchison commented Dec 1, 2023

This updates the best_effort_copy logic to do less copying. I noticed when running a large group of tests, that there was a substantial delay before testing actually started. Digging into it and randomly pausing during this period, I added whatever was being copied to a list to not copy until the time was reduced by quite a bit. The only exception seemed to be _request which would result in errors after a couple reruns. Since _request was a deep object, I added a code path for forcing a limited depth copy.

It's been a while since I worked on this, but the background, if I remember correctly:

  • The most expensive part of pytest start-up, outside of things like one-time database operations, is the session and test creation.
  • Test sessions are cached and re-used based on what tests are ran
  • You can't simply reference the session object because there's things inside that mutate. The session gets in a state of "I'm done", then pytest complains if you attempt to use it again. IIRC this state information becomes nested in sub-objects as well. For example, fixtures complaining that they were already cleaned up.
  • You can't simply copy a session because of the nested state information
  • You can't simply deep copy a session because it references modules and things that are non-serializable
  • Best effort copy was created to try the copy the minimum needed to re-use sessions.
  • I didn't realize how large these objects were when I wrote this earlier

Testing the performance, the improvement is substantial. Using the tests in this repo as a reference:

  • Running without the plugin results in a failing test and execution is about 7.5 seconds
  • Running with the plugin and daemon gets 5.6 seconds
  • Re-running with the daemon gets 3.1 seconds

The failing test invokes more logic, exception handling, and introspection (errors are slow...) so it taking longer makes sense in this case. I disabled the check logic and its getting 6.6 seconds. I wouldn't expect an initial run with the daemon to be faster than without, so its worth calling out this is curious behavior and may indicate something is not quite right.

@JamesHutchison JamesHutchison added the enhancement New feature or request label Dec 1, 2023
@JamesHutchison JamesHutchison merged commit 2cb7654 into main Dec 1, 2023
3 checks passed
@JamesHutchison JamesHutchison deleted the perf-improvements branch December 1, 2023 01:45
@JamesHutchison
Copy link
Owner Author

I wouldn't expect an initial run with the daemon to be faster than without, so its worth calling out this is curious behavior and may indicate something is not quite right.

This can be explained by xdist set-up time and other logic that isn't shortcut when you use the client, so actually this makes sense. When you disable xdist on this repo the time difference is smaller

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant