Fewer allocations in gem installation#6975
Conversation
lib/rubygems/package.rb
Outdated
|
|
||
| if entry.file? | ||
| File.open(destination, "wb") {|out| out.write entry.read } | ||
| File.open(destination, "wb") {|out| IO.copy_stream entry, out } |
There was a problem hiding this comment.
Yep, truffleruby failing in your tests too. I haven't been able to extract a distilled case yet, but @eregon could maybe take a look anyway? I think the issue is that copy_stream is not reading and writing byte for byte identically.
There's layers and layers here, the src entry is a TarReader wrapping a zlib reader, wrapping a TarReader. This change alone causes the bug, if I'm not mistaken.
You may have to revert this part until it's fixed in truffleruby, or found not to be broken?
There was a problem hiding this comment.
It seems likely to be truffleruby/truffleruby#3280 which is now fixed in dev builds
There was a problem hiding this comment.
@martinemde thoughts on introducing a utility method that is IO.copy_stream on all rubies except truffleruby before 23.1.2? Could go into #6958
There was a problem hiding this comment.
That's a great idea. Even fixed it's still broken on older trufflerubies, even if people don't usually update rubygems separately.
There was a problem hiding this comment.
I can add it to #6958. (Or please do if you'd like to get it done and I haven't gotten to it)
lib/rubygems/package.rb
Outdated
| gzio.read 16_384 until gzio.eof? # gzip checksum verification | ||
| buf = String.new(capacity: 16_384, encoding: Encoding::BINARY) | ||
| begin | ||
| gzio.readpartial(16_384, buf) until gzio.eof? # gzip checksum verification |
There was a problem hiding this comment.
gzio read partial returns arbitrarily different length strings on some gzips. Check the pathological gem that I mentioned in the zlib bug. It extracts validly when using read but not readpartial. I don't know how common this problem is.
EDIT: The real bug here is that gzio.readpartial until eof fails right now with Zlib.
lib/rubygems/package/tar_header.rb
Outdated
| eval <<-RUBY, binding, __FILE__, __LINE__ + 1 | ||
| # frozen_string_literal: true | ||
|
|
||
| def copy_vals(vals) | ||
| #{FIELDS.map {|name| "@#{name} = vals[:#{name}]" }.join("; ")} | ||
| end | ||
| RUBY |
There was a problem hiding this comment.
This definitely needs a comment about why. This is not your grandma's self documenting code. 👵🏻
There was a problem hiding this comment.
Or, alternatively, why convert to instance variables at all? Why not store vals directly and iterate FIELDS one time to create attr readers that just lookup the key in the vals hash. vals is mutable and is already allocated.
There was a problem hiding this comment.
After coming back to this 3 months later, I think I'd prefer we just write out all the assignments just like in ==. The eval feels really complex compared to simple repetition.
f50168d to
1488197
Compare
|
Blocked until code is updated to not use |
04b7958 to
8e7c2ca
Compare
|
My git scripts messed up, will clean up tomorrow |
dca336c to
4bba03a
Compare
|
Sorry for the churn, @martinemde this should be ready for another look |
4bba03a to
5a12814
Compare
5a12814 to
17dbff2
Compare
For now, on a small rails app I have hanging around: ``` ==> memprof.after.txt <== Total allocated: 872.51 MB (465330 objects) Total retained: 40.48 kB (326 objects) ==> memprof.before.txt <== Total allocated: 890.79 MB (1494026 objects) Total retained: 40.40 kB (328 objects) ``` Not a huge difference in memory usage, but it's a drastic improvement in total number of allocations. Additionally, this will pay huge dividends once ruby/zlib#61 is merged, as it will allow us to completely avoid allocations in the repeated calls to readpartial, which currently accounts for most of the memory usage shown above.
17dbff2 to
f78d45d
Compare
For now, on a small rails app I have hanging around:
Not a huge difference in memory usage, but it's a drastic improvement
in total number of allocations.
Additionally, this will pay huge dividends once
ruby/zlib#61 is merged, as it will allow us to
completely avoid allocations in the repeated calls to readpartial,
which currently accounts for most of the memory usage shown above.
What was the end-user or developer problem that led to this PR?
What is your fix for the problem, implemented in this PR?
Make sure the following tasks are checked