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
Add test with valgrind using the ruby_memcheck gem and use it in CI #2954
Conversation
95eb37d
to
50dc651
Compare
.github/workflows/tests.yaml
Outdated
- uses: actions/cache@v1 | ||
with: | ||
path: vendor/bundle | ||
key: ${{ runner.os }}-gems-${{ hashFiles('Gemfile') }} | ||
restore-keys: ${{ runner.os }}-gems- | ||
- run: bundle install --jobs=3 --retry=3 --path=vendor/bundle |
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.
You can let setup-ruby both run bundle install
and cache: https://github.com/ruby/setup-ruby#caching-bundle-install-automatically
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 made the changes you suggested.
Gemfile
Outdated
@@ -27,3 +27,4 @@ end | |||
|
|||
gem 'm' | |||
gem "localhost", require: false | |||
gem "ruby_memcheck", "~> 1.0" |
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 this should be guarded similar to rubocop
above (PUMA_NO_RUBOCOP
) with PUMA_NO_MEMCHECK
so we can avoid installing it for regular CI runs
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 added PUMA_NO_MEMCHECK
.
@dentarg |
@kos31de First of all, good idea, and thanks for working on it. In general, not sure changes to the test or lib folders will require this to be run. Or, only changes to the ext folder are what should be checked? It might be better to either add this to the ragel workflow file (which is filtered on the ext path), or make it a separate file with path filtering. Secondly, based on @dentarg's comments, if EDIT: Got it running locally, although tests are running twice. Not.sure.why But, there are some things reported, making changes , mostly to minissl.c... |
Thank you so much for taking this up @kos31de ! |
Thanks for working on this @kos31de! Feel free to reach out if you need any help! |
50dc651
to
c0b764a
Compare
Thank you all for your comments. |
a5adc55
to
3566c84
Compare
I have found a problem of the test being run twice. log
# Running:
...........S......................S...............EEEEEES.SSS......................................................................................................E...................................................................................................SS...SSS.S.S....S...S..SS.....SS..S...................................../usr/lib/ruby/3.0.0/uri/common.rb:286:in `chr': Interrupt
from /usr/lib/ruby/3.0.0/uri/common.rb:286:in `block in <module:URI>'
from /usr/lib/ruby/3.0.0/uri/common.rb:284:in `times'
from /usr/lib/ruby/3.0.0/uri/common.rb:284:in `<module:URI>'
from /usr/lib/ruby/3.0.0/uri/common.rb:15:in `<top (required)>'
from /usr/lib/ruby/3.0.0/uri.rb:95:in `require_relative'
from /usr/lib/ruby/3.0.0/uri.rb:95:in `<top (required)>'
from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
from /usr/lib/ruby/vendor_ruby/rubygems/specification_policy.rb:408:in `validate_lazy_metadata'
from /usr/lib/ruby/vendor_ruby/rubygems/specification_policy.rb:89:in `validate_required!'
from /usr/lib/ruby/vendor_ruby/rubygems/specification_policy.rb:44:in `validate'
from /usr/lib/ruby/vendor_ruby/rubygems/specification.rb:2583:in `validate'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/rubygems_integration.rb:68:in `block in validate'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/ui/shell.rb:136:in `with_level'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/ui/shell.rb:88:in `silence'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/rubygems_integration.rb:68:in `validate'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/source/path.rb:168:in `validate_spec'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/source/path.rb:182:in `block in load_spec_files'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/source/path.rb:176:in `each'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/source/path.rb:176:in `load_spec_files'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/source/path.rb:107:in `local_specs'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/source/path.rb:115:in `specs'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:615:in `specs_for_source_changed?'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:600:in `specs_changed?'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:644:in `block in converge_paths'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:643:in `any?'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:643:in `converge_paths'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:135:in `initialize'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/dsl.rb:219:in `new'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/dsl.rb:219:in `to_definition'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/dsl.rb:13:in `evaluate'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/definition.rb:38:in `build'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler.rb:208:in `definition'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler.rb:156:in `setup'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/setup.rb:20:in `block in <top (required)>'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/ui/shell.rb:136:in `with_level'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/ui/shell.rb:88:in `silence'
from /var/lib/gems/3.0.0/gems/bundler-2.3.22/lib/bundler/setup.rb:20:in `<top (required)>'
from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
from <internal:/usr/lib/ruby/vendor_ruby/rubygems/core_ext/kernel_require.rb>:85:in `require'
#<Thread:0x000000000babe7c0 /home/ubuntu/puma/test/helpers/integration.rb:340 run> terminated with exception (report_on_exception is true):
/home/ubuntu/puma/test/helpers/integration.rb:136:in `gets': stream closed in another thread (IOError)
from /home/ubuntu/puma/test/helpers/integration.rb:136:in `wait_for_server_to_boot'
from /home/ubuntu/puma/test/helpers/integration.rb:349:in `block in hot_restart_does_not_drop_connections'
/home/ubuntu/puma/test/helpers/integration.rb:136:in `gets': stream closed in another thread (IOError)
from /home/ubuntu/puma/test/helpers/integration.rb:136:in `wait_for_server_to_boot'
from /home/ubuntu/puma/test/helpers/integration.rb:349:in `block in hot_restart_does_not_drop_connections'
E.......E..................EEEE.EE.......SS.....SS...S.S..S.S....S.S..SSS.....S..E...S.E.../home/ubuntu/puma/lib/puma/log_writer.rb:61:in `write': deadlock; recursive locking (ThreadError) |
Thanks for working on this. It might be better to have a positive ENV variable like Locally, I threw something together, I used I was only running tests with |
AFAIK |
Thanks for helping, and also for
forked vs sub-process? Not sure. I'll check a bit later. Some tests also restart Puma with a different Gemfile, these may need to be skipped. The extension code in Puma is for the request http parser and ssl connections. Everything else is Ruby. |
3566c84
to
a520cf9
Compare
a520cf9
to
5455c36
Compare
The below: puma/.github/workflows/tests.yaml Lines 186 to 190 in 5455c36
should have two changes (lines 186 & 190): - uses: ruby/setup-ruby-pkgs@v1
with:
ruby-version: '3.0'
bundler-cache: true
apt-get: ragel valgrind |
During RubyKaigi, I discussed the issue of long completion times in CI when running with ruby_memcheck with @nateberkopec. He agreed that a good solution is to only run the ruby_memcheck pipeline only on the main branch, that way it doesn't block PRs while still running for every commit. |
Maybe a bit of an explanation of
Critically, it installs packages before Since this code will run only on Actions Ubuntu, it could be done with |
Which makes it a total PITA to run in a fork. One of the main remaining issues with GitHub Actions. I wonder if a few tests or scripts specific to ruby_memcheck should be used for CI. CI systems are limited, and some of the current tests (like the bundler tests for app reloading) may require patching to run with ruby_memcheck. Also, some tests are time sensitive/limited, and they may have issues running with ruby_memcheck. Maybe send a stream of tcp sockets, and another with a stream of ssl sockets. That would check normal operation, maybe more code should be used to check if any error handling causes memory leaks. I would like to get ruby_memcheck running as part of Puma's CI. I think it's probably a nontrivial task to properly implement. |
Above I mentioned timing. I've been running Puma CI quite a bit this weekend. Earlier, an Ubuntu system took 25 seconds to compile, most of the other Ubuntu jobs take 4 to 6 seconds. Just now, a macOS system took about 110 seconds to compile, normal times are around 11 seconds. The macOS system also failed the tests. With variances like the above, CI stability can be very difficult. Adding valgrind to it (as is) would probably lead to insanity... |
@MSP-Greg |
Thank you again for the PR, and thanks to @peterzhu2118 for participating. Been busy re Puma 6.0.0, I need to work on some other projects. I want to pick up work on using ruby_memcheck/valgrind in CI sometime soon. I suspect writing code specifically for it is probably best. Filtering similar to the ragel workflow would only run CI with it when needed. The extension code in Puma handles request parsing and SSL connections. Code that generates request streams is probably a good start, followed with code that throws some errors to check whether error handling has any leaks.
Whatever you prefer. Leaving it open is fine by me, not speaking for others... |
Thanks for your contribution @kos31de. I generally don't like leaving PRs open if we don't have a clear action to take at the moment. Please re-open whenever you think it is ready. |
Description
close #2945
Add a step to the workflow to detect memory leaks with ruby_memcheck.
Your checklist for this pull request
[ci skip]
to the title of the PR.#issue
" to the PR description or my commit messages.