Avoid generating duplicate conflict rules#3482
Conversation
|
Number of calls to createConflictRule() before: 191703 after: 75503 |
|
Looks good to me, will test quickly :) |
56b1d00 to
2059a08
Compare
|
quick test on the biggest project I have lying around: edit |
|
So no memory improvement for you, that's funny. Still a win CPU wise though. |
|
I think the memory improvement may depend on PHP version, potentially random influences on garbage collection, etc. as the objects were thrown away previously anyway, so you could get lucky and not have much of a memory impact through them, or unlucky and they'd use up a lot. |
|
I got similar results as seen @rwos: PHP 5.6.3 (cli) (built: Nov 17 2014 11:33:26) (DEBUG) |
|
Also getting major speed improvements for shopware/shopware with only slightly lower peak memory usage. Edit: Following runs: |
2059a08 to
83e0900
Compare
For each version of each package we create a conflict rule with each other version. These are then added to the rule set and skipped if duplicate so instead we can just generate them only once to begin with and avoid unnecessary memory allocation and duplication lookups.
83e0900 to
4a945da
Compare
|
Yup it depends on the workload / set of packages what kind of improvements you get, and possibly php version too, but it has at worst no effect so it's a win :) |
|
Rebased onto merged solver optimize branch |
Avoid generating duplicate conflict rules
|
This might indeed be a GC issue. If there are many objects created - all of which cannot be cleaned-up. PHP's GC will kick in frequently trying to clean-up, only to discover that it cannot clean-up anything, and just wastes time/CPU cycles. This might be the reason why you see the effect for big projects (= many objects), but not so much for small projects (= GC is not kicking in frequently). In these cases, disabling GC entirely is a lot faster (at the cost of some more memory consumption ofc). If no-one has checked yet, it might be worth to add |
|
This is what I got: |
|
@schmittjoh you are right, I've added gc_disable and the result look good ;) Memory usage: 227.76MB (peak: 591.29MB), time: 126.22s # before |
|
// php -v // before // after // php -d zend.enable_gc=0 ~/bin/composer update --dry-run --profile 😄 |
|
Hm the lack of peak increase with enable_gc=0 is making me curious what is going on there. This makes it sound as if we should just always do that? |
|
@naderman the GC in PHP is only used to be able to handle circular object graphs. For non-circular graphs, the refcount is enough to destroy values without needing the GC. So as long as you avoid circular object graphs in objects used a lot in Composer, you could indeed disable it. |
|
My results on a decent sized symfony2 application (45 dependencies in composer.json) before b23a3cd after 91dd999 It seems like the changes have made a big difference and disabling gc would further enhance the gains. |
|
Great Scot! that’s drastic, thanks a lot.
Before: Project 1: Project 2: After: Project 1: Project 2: Project 2 with GC disabled: Life changing. |
|
@stof well it certainly looks like composer itself would be fine. I'm just not sure what the impact on plugins/scripts would be, there may be some around that do create such graphs. |
|
@naderman, generally if you create many many objects, you pretty much want to always disable GC. This is because PHP has a hard-coded limit (compile-time) of root objects that it can track in its GC implementation (I believe it's set to 10000 by default). If you get close to this limit, GC kicks in. If it cannot clean-up, it will still keep trying in frequent intervals. If you go above the limit, any new root objects are not tracked anymore, and cannot be cleaned-up whether GC is enabled, or not. This might also be why the memory consumption for bigger projects does not vary. If GC is enabled, it's just not working anymore even if there is potentially something to clean-up. For smaller projects, you might see a memory difference. |
|
The difference is kinda crazy, thanks @schmittjoh for pointing this out! I did the change, we'll see how it goes but it seems unanimously better, and indeed here shaves off another ~50% of runtime. |
|
Should there be a |
|
@RSully Yup I've been wondering about this too. I'll check what the impact is to re-enable it. |
|
Impact seems to be low enough but I think I'll open a new issue for this because it requires more considerations. |
|
@Seldaek we could also call gc_collect_cycles() before gc_disable() in order to free up some memory :-) |
|
Having looked at the actual stats of what the garbage collector used to do, a composer update on packagist used to trigger the garabage collector 175 times, 174 times it did not collect anything, and one time it managed to collect 256 items, so a gc_collect_cycles() seems pretty unnecessary. |
|
For anyone playing around with the information @naderman just gave, you can do this by compiling QafooLabs/php-profiler-extension#2 - it adds two new keys to the result It is not possible at the moment to hook into how long the garbage collection takes. Evaluating right now what Zend Engine would need for that. |
|
@hadjedjvincent it's been done already :) |
|
I think this is causing some issues with my project. Currently I'm running symfony 2.1. After self-updating composer then running composer update, it started downloading symfony 2.7 components, which broke the project. After rolling back the composer self-update and running composer update again, the 2.7 packages were deleted and everything was fixed. Am I in the right place, or should I submit a general bug report? |
|
Please submit a general bug report. The GC disabling cannot be the cause for this, but other refactorings done yesterday could be |
|
I'm not referencing the garbage collection disabling. I'm referencing this pull request. I just confirmed that the commit naderman@4a945da is causing the problem. After changing line 244 in src/Composer/DependencyResolver/RuleSetGenerator.php to: The problem is fixed. |
|
Created pull request #3493 |
|
Lol, oh PHP you so crazy. |
|
Before: Memory usage: 127.39MB (peak: 280.46MB), time: 119.66s And I always thought composer was slow because I was in Australia lol |
Fixed dependency problem caused by pull request #3482
- Comment out reporting in phpunit.xml.dist : prevent Travis-CI from generating unneeded reports - Disable GC when running composer : composer/composer#3482 (comment)
- Comment out reporting in phpunit.xml.dist : prevent Travis-CI from generating unneeded reports - Disable GC when running composer : composer/composer#3482 (comment)
- Comment out reporting in phpunit.xml.dist : prevent Travis-CI from generating unneeded reports - Disable GC when running composer : composer/composer#3482 (comment)
- Comment out reporting in phpunit.xml.dist : prevent Travis-CI from generating unneeded reports - Disable GC when running composer : composer/composer#3482 (comment)
For each version of each package we create a conflict rule with each
other version of itself. These are then added to the rule set and skipped if
duplicate so instead we can just generate them only once to begin with
and avoid unnecessary memory allocation and duplication lookups.
Packagist
composer update --dry-run --profilebefore:and after: