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

Destroy TestCase object after its test was run #5861

Closed

Conversation

sebastianbergmann
Copy link
Owner

@sebastianbergmann sebastianbergmann commented Jun 12, 2024

I may have found a short-term solution (before more architectural changes have been implemented for the test runner) to reduce PHPUnit's memory usage.

With PHPUnit's own test suite, I see a memory usage reduction from 48.00 MB (778070d) to 44.00 MB (4df94e0).

I have tested this solution with a couple of test suites so far and 1) it does not break anything (good!) and 2) it reduces memory usage (also good!).

However, I am not comfortable shipping this without (a lot) more testing. So, if you want to help me out, then please test this change with your own test suite:

  • Does this change break your test suite (you get a different result with and without the change)?
  • Does this change reduce the memory usage of running your tests for you?

This change can be applied to PHPUnit 10.5 and PHPUnit 11.2.

@sebastianbergmann sebastianbergmann added the type/performance Issues related to resource consumption (time and memory) label Jun 12, 2024
@sebastianbergmann sebastianbergmann self-assigned this Jun 12, 2024
@sebastianbergmann
Copy link
Owner Author

This might be of interest to @staabm and @lolli42.

Copy link

codecov bot commented Jun 12, 2024

Codecov Report

Attention: Patch coverage is 92.85714% with 2 lines in your changes missing coverage. Please review.

Project coverage is 92.33%. Comparing base (778070d) to head (82a73f0).

Files Patch % Lines
src/Framework/TestSuite.php 94.73% 1 Missing ⚠️
src/Runner/Filter/GroupFilterIterator.php 85.71% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main    #5861      +/-   ##
============================================
- Coverage     92.34%   92.33%   -0.02%     
- Complexity     6554     6559       +5     
============================================
  Files           699      699              
  Lines         19772    19781       +9     
============================================
+ Hits          18259    18265       +6     
- Misses         1513     1516       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@talkinnl
Copy link

talkinnl commented Jun 12, 2024

The groups property still also holds the test instances, so tests which are part of group(s) will still not be destructed in this first commit.

@sebastianbergmann
Copy link
Owner Author

sebastianbergmann commented Jun 13, 2024

The groups property still also holds the test instances, so tests which are part of group(s) will still not be destructed in this first commit.

I am aware of that, but thank you for pointing it out.

@sebastianbergmann sebastianbergmann force-pushed the destroy-testcase-objects-after-execution branch from f11b51a to 4df94e0 Compare June 13, 2024 04:50
@sebastianbergmann
Copy link
Owner Author

With TYPO3's (unit) test suite (./bin/phpunit -c Build/phpunit/UnitTests.xml), I see a memory usage reduction from 375.02 MB (TYPO3/typo3@a4ba149, PHPUnit 11.2.1) to 311.01 MB (TYPO3/typo3@a4ba149, PHPUnit 11.2.1 with the changes from this PR).

@sebastianbergmann
Copy link
Owner Author

sebastianbergmann commented Jun 13, 2024

This change can be applied to PHPUnit 10.5 and PHPUnit 11.2:

$ wget https://github.com/sebastianbergmann/phpunit/pull/5861.patch
$ patch -p1 < 5861.patch

@sebastianbergmann sebastianbergmann added version/10 Something affects PHPUnit 10 version/11 Something affects PHPUnit 11 labels Jun 13, 2024
@rolfdenhartog
Copy link

@sebastianbergmann I've tested it on a (small) Laravel project containing 102 tests (mainly feature, few unit). Here are the results:

Before (11.1.3)

PHPUnit 11.1.3 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: .../phpunit.xml

...............................................................  63 / 102 ( 61%)
.......................................                         102 / 102 (100%)

Time: 00:02.992, Memory: 64.50 MB

OK (102 tests, 388 assertions)

After (destroy-testcase-objects-after-execution):

PHPUnit 11.3-dev by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: .../phpunit.xml

...............................................................  63 / 102 ( 61%)
.......................................                         102 / 102 (100%)

Time: 00:03.143, Memory: 64.50 MB

OK (102 tests, 388 assertions)

I'll try it later today on some other projects which largers test suites.

@talkinnl
Copy link

I did a full successful run on our project.

I started before your second commit, and I actually just did a $this->groups=[]; once before the loop to clear the groups. If we’re done making the tests selection, might just as well clear that property at once instead of slowly. :)

Patched v10.
Test outcomes isnt affected.
Tests: 10362, Assertions: 47147.
From: Time: 01:56:45.575, Memory: 614.82 MB
To, with patched: Time: 01:55:47.195, Memory: 504.83 MB

Note: Mosts tests already had a tearDown() for unsetting properties, and we unset all our own properties using reflection because we kept forgetting tear downs.
Without those tweaks, runs which keep the instances alive would be many GBs.
If this change lands, we can remove most tearDown and reflection logic, saving boilerplate code and also the 2 minutes of runtime used by the reflection trick.

exec summary: I’m quite hyped by this proposal, and only positive changes with a huge, old project!

@acelaya
Copy link

acelaya commented Jun 13, 2024

Just tested this in a project with three test suites: Unit tests, DB integration tests and REST API E2E tests.


Unit tests

Before:

PHPUnit 11.2.1 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /home/shlink/phpunit.xml.dist
Random Seed:   1718273510

.............................................................   61 / 1076 (  5%)
.............................................................  122 / 1076 ( 11%)
.............................................................  183 / 1076 ( 17%)
.............................................................  244 / 1076 ( 22%)
.............................................................  305 / 1076 ( 28%)
.............................................................  366 / 1076 ( 34%)
.............................................................  427 / 1076 ( 39%)
.............................................................  488 / 1076 ( 45%)
.............................................................  549 / 1076 ( 51%)
.............................................................  610 / 1076 ( 56%)
.............................................................  671 / 1076 ( 62%)
.............................................................  732 / 1076 ( 68%)
.............................................................  793 / 1076 ( 73%)
.............................................................  854 / 1076 ( 79%)
.............................................................  915 / 1076 ( 85%)
.............................................................  976 / 1076 ( 90%)
............................................................. 1037 / 1076 ( 96%)
.......................................                       1076 / 1076 (100%)

Time: 00:01.444, Memory: 60.00 MB

OK (1076 tests, 3062 assertions)

After:

PHPUnit 11.2.1 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /home/shlink/phpunit.xml.dist
Random Seed:   1718273576

.............................................................   61 / 1076 (  5%)
.............................................................  122 / 1076 ( 11%)
.............................................................  183 / 1076 ( 17%)
.............................................................  244 / 1076 ( 22%)
.............................................................  305 / 1076 ( 28%)
.............................................................  366 / 1076 ( 34%)
.............................................................  427 / 1076 ( 39%)
.............................................................  488 / 1076 ( 45%)
.............................................................  549 / 1076 ( 51%)
.............................................................  610 / 1076 ( 56%)
.............................................................  671 / 1076 ( 62%)
.............................................................  732 / 1076 ( 68%)
.............................................................  793 / 1076 ( 73%)
.............................................................  854 / 1076 ( 79%)
.............................................................  915 / 1076 ( 85%)
.............................................................  976 / 1076 ( 90%)
............................................................. 1037 / 1076 ( 96%)
.......................................                       1076 / 1076 (100%)

Time: 00:01.505, Memory: 54.00 MB

OK (1076 tests, 3062 assertions)

Integration tests

Before:

PHPUnit 11.2.1 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /home/shlink/phpunit-db.xml
Random Seed:   1718273498

................................................................. 65 / 85 ( 76%)
....................                                              85 / 85 (100%)

Time: 00:00.459, Memory: 30.00 MB

OK (85 tests, 593 assertions)

After:

PHPUnit 11.2.1 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /home/shlink/phpunit-db.xml
Random Seed:   1718273595

................................................................. 65 / 85 ( 76%)
....................                                              85 / 85 (100%)

Time: 00:00.453, Memory: 30.00 MB

OK (85 tests, 593 assertions)

API tests

Before:

PHPUnit 11.2.1 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /home/shlink/phpunit-api.xml
Random Seed:   1718273457

...............................................................  63 / 242 ( 26%)
............................................................... 126 / 242 ( 52%)
............................................................... 189 / 242 ( 78%)
.....................................................           242 / 242 (100%)

Time: 00:20.109, Memory: 32.00 MB

OK (242 tests, 903 assertions)

After:

PHPUnit 11.2.1 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.7
Configuration: /home/shlink/phpunit-api.xml
Random Seed:   1718273611

...............................................................  63 / 242 ( 26%)
............................................................... 126 / 242 ( 52%)
............................................................... 189 / 242 ( 78%)
.....................................................           242 / 242 (100%)

Time: 00:23.159, Memory: 32.00 MB

OK (242 tests, 903 assertions)

Everything worked transparently. Memory saving is more obvious the more tests the test suite has (which I guess is expected).

@sebastianbergmann
Copy link
Owner Author

I'll try it later today on some other projects which largers test suites.

The "base" needs to be the same, the only difference must be the changes from this PR. In other words: Testing PHPUnit 11.1 without these changes versus PHPUnit 11.3-dev with these changes does not help. Sorry!

@sebastianbergmann
Copy link
Owner Author

Memory saving is more obvious the more tests the test suite has (which I guess is expected).

Yes, that is expected. Thanks!

@sebastianbergmann
Copy link
Owner Author

If we’re done making the tests selection, might just as well clear that property at once instead of slowly. :)

Good idea, thanks!

@sebastianbergmann
Copy link
Owner Author

sebastianbergmann commented Jun 13, 2024

If we’re done making the tests selection, might just as well clear that property at once instead of slowly. :)
Good idea, thanks!

Does not work, though. With these changes ...

diff --git a/src/Framework/TestSuite.php b/src/Framework/TestSuite.php
index c663aec88..6492c1207 100644
--- a/src/Framework/TestSuite.php
+++ b/src/Framework/TestSuite.php
@@ -359,6 +359,8 @@ public function run(): void
             return;
         }

+        $this->groups = [];
+
         foreach ($this as $test) {
             if (TestResultFacade::shouldStop()) {
                 $emitter->testRunnerExecutionAborted();
@@ -375,22 +377,6 @@ public function run(): void
                     break;
                 }
             }
-
-            if ($test instanceof TestCase || $test instanceof self) {
-                foreach ($test->groups() as $group) {
-                    if (!isset($this->groups[$group])) {
-                        continue;
-                    }
-
-                    foreach (array_keys($this->groups[$group]) as $key) {
-                        if ($test === $this->groups[$group][$key]) {
-                            unset($this->groups[$group][$key]);
-
-                            break;
-                        }
-                    }
-                }
-            }
         }

         $this->invokeMethodsAfterLastTest($emitter);

... the tests for group-based filtering of PHPUnit's own test suite fail because the filters are applied while iterating for execution. I am afraid that this cannot be addressed without making more significant changes which are outside the scope of this short-term solution.

@talkinnl
Copy link

Ah, pity. Didn’t knew the filtering was during the loop.
I’ll read a bit into how the iterator and filter is implemented.

@sebastianbergmann
Copy link
Owner Author

I’ll read a bit into how the iterator and filter is implemented.

As of 52d2488, the TestCase objects are no longer stored in the $groups property.

@rolfdenhartog
Copy link

rolfdenhartog commented Jun 13, 2024

I'll try it later today on some other projects which largers test suites.

The "base" needs to be the same, the only difference must be the changes from this PR. In other words: Testing PHPUnit 11.1 without these changes versus PHPUnit 11.3-dev with these changes does not help. Sorry!

Don't feel sorry 😊 I've checked it again, but I was using the correct PHPUnit changes. FYI: I've updated composer.json with "phpunit/phpunit": "dev-destroy-testcase-objects-after-execution" and that did it for me. I've also checked the source code in the vendor directory just be sure 😉

Output for memory usage was the same after a second run.

@omnicolor
Copy link

For one of my personal projects:

mordor commlink-dev(6+0 subversion) /$ ./vendor/bin/phpunit
PHPUnit 11.2.0 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.8
Configuration: /mnt/sys/www/commlink-dev/phpunit.xml
Random Seed:   1718284972

.............................................................   61 / 2553 (  2%)
.............................................................  122 / 2553 (  4%)
.............................................................  183 / 2553 (  7%)
.............................................................  244 / 2553 (  9%)
.............................................................  305 / 2553 ( 11%)
.............................................................  366 / 2553 ( 14%)
.............................................................  427 / 2553 ( 16%)
.............................................................  488 / 2553 ( 19%)
.............................................................  549 / 2553 ( 21%)
.............................................................  610 / 2553 ( 23%)
.............................................................  671 / 2553 ( 26%)
.............................................................  732 / 2553 ( 28%)
.............................................................  793 / 2553 ( 31%)
.............................................................  854 / 2553 ( 33%)
.............................................................  915 / 2553 ( 35%)
.............................................................  976 / 2553 ( 38%)
............................................................. 1037 / 2553 ( 40%)
............................................................. 1098 / 2553 ( 43%)
............................................................. 1159 / 2553 ( 45%)
............................................................. 1220 / 2553 ( 47%)
............................................................. 1281 / 2553 ( 50%)
............................................................. 1342 / 2553 ( 52%)
............................................................. 1403 / 2553 ( 54%)
............................................................. 1464 / 2553 ( 57%)
............................................................. 1525 / 2553 ( 59%)
............................................................. 1586 / 2553 ( 62%)
............................................................. 1647 / 2553 ( 64%)
............................................................. 1708 / 2553 ( 66%)
............................................................. 1769 / 2553 ( 69%)
............................................................. 1830 / 2553 ( 71%)
............................................................. 1891 / 2553 ( 74%)
............................................................. 1952 / 2553 ( 76%)
............................................................. 2013 / 2553 ( 78%)
............................................................. 2074 / 2553 ( 81%)
............................................................. 2135 / 2553 ( 83%)
............................................................. 2196 / 2553 ( 86%)
............................................................. 2257 / 2553 ( 88%)
............................................................. 2318 / 2553 ( 90%)
............................................................. 2379 / 2553 ( 93%)
............................................................. 2440 / 2553 ( 95%)
............................................................. 2501 / 2553 ( 97%)
....................................................          2553 / 2553 (100%)

Time: 01:20.281, Memory: 175.00 MB

OK (2553 tests, 5239 assertions)

After:

mordor commlink-dev(8+0 subversion) /$ ./vendor/bin/phpunit
PHPUnit 11.3-dev by Sebastian Bergmann and contributors.

Runtime:       PHP 8.3.8
Configuration: /mnt/sys/www/commlink-dev/phpunit.xml
Random Seed:   1718285442

.............................................................   61 / 2553 (  2%)
.............................................................  122 / 2553 (  4%)
.............................................................  183 / 2553 (  7%)
.............................................................  244 / 2553 (  9%)
.............................................................  305 / 2553 ( 11%)
.............................................................  366 / 2553 ( 14%)
.............................................................  427 / 2553 ( 16%)
.............................................................  488 / 2553 ( 19%)
.............................................................  549 / 2553 ( 21%)
.............................................................  610 / 2553 ( 23%)
.............................................................  671 / 2553 ( 26%)
.............................................................  732 / 2553 ( 28%)
.............................................................  793 / 2553 ( 31%)
.............................................................  854 / 2553 ( 33%)
.............................................................  915 / 2553 ( 35%)
.............................................................  976 / 2553 ( 38%)
............................................................. 1037 / 2553 ( 40%)
............................................................. 1098 / 2553 ( 43%)
............................................................. 1159 / 2553 ( 45%)
............................................................. 1220 / 2553 ( 47%)
............................................................. 1281 / 2553 ( 50%)
............................................................. 1342 / 2553 ( 52%)
............................................................. 1403 / 2553 ( 54%)
............................................................. 1464 / 2553 ( 57%)
............................................................. 1525 / 2553 ( 59%)
............................................................. 1586 / 2553 ( 62%)
............................................................. 1647 / 2553 ( 64%)
............................................................. 1708 / 2553 ( 66%)
............................................................. 1769 / 2553 ( 69%)
............................................................. 1830 / 2553 ( 71%)
............................................................. 1891 / 2553 ( 74%)
............................................................. 1952 / 2553 ( 76%)
............................................................. 2013 / 2553 ( 78%)
............................................................. 2074 / 2553 ( 81%)
............................................................. 2135 / 2553 ( 83%)
............................................................. 2196 / 2553 ( 86%)
............................................................. 2257 / 2553 ( 88%)
............................................................. 2318 / 2553 ( 90%)
............................................................. 2379 / 2553 ( 93%)
............................................................. 2440 / 2553 ( 95%)
............................................................. 2501 / 2553 ( 97%)
....................................................          2553 / 2553 (100%)

Time: 01:18.143, Memory: 167.00 MB

OK (2553 tests, 5239 assertions)

@fisharebest
Copy link

please test this change with your own test suite:

Works OK!

778070d - 194.5MB
4df94e0 - 188.5MB

@maksimovic
Copy link

Works fine, no issues.

Runtime:       PHP 8.1.27 with Xdebug 3.2.2

Before: Memory: 500.61 MB
After: Memory: 498.61 MB

@maksimovic
Copy link

Works fine, no issues.

Runtime:       PHP 8.1.27 with Xdebug 3.2.2

Before: Memory: 500.61 MB
After: Memory: 498.61 MB

⬆️ The above was with xdebug & code coverage. Without it:

Before: Memory: 498.61 MB
After: 470.11 MB

@sebastianbergmann
Copy link
Owner Author

Merged into 10.5, 11.2, and main.

@sebastianbergmann sebastianbergmann deleted the destroy-testcase-objects-after-execution branch June 14, 2024 16:33
@talkinnl
Copy link

@sebastianbergmann This PR means #4705 is fixed :)

@lolli42
Copy link
Contributor

lolli42 commented Jun 17, 2024

Late feedback, but feedback:

This works very well: I confirm the numbers with TYPO3 core v13 (phpunit v11) unit test suite, "functional" test suite is even better, and core v12 (phpunit v10) is confirmed to work and shows similar numbers.
Also, "big" data provider data sets (like 1MB of data) showed 3MB memory usage since phpunit 10 and 11, and this is the "expcted" 1MB now.
Great job. Thank you so much!

@rr-it
Copy link

rr-it commented Jun 17, 2024

TYPO3 core v13 functional test are down to 1.37 GB from > 2 GB before.

@manuelmeister
Copy link

In our project ecamp/ecamp3 this resulted in our tests taking ~3min instead of ~13min. 🤯

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/performance Issues related to resource consumption (time and memory) version/10 Something affects PHPUnit 10 version/11 Something affects PHPUnit 11
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants