Skip to content

Improve performance of collate & reduce memorty consumption#960

Merged
PragTob merged 6 commits into
mainfrom
collate-improve-performance
Jan 3, 2021
Merged

Improve performance of collate & reduce memorty consumption#960
PragTob merged 6 commits into
mainfrom
collate-improve-performance

Conversation

@PragTob

@PragTob PragTob commented Dec 28, 2020

Copy link
Copy Markdown
Collaborator

Draft to get early feedback! (cc: @deivid-rodriguez ? :D ) So Todos and fixmes are intended and will either get resolved or turned into tickets.

I'm worried about breaking things, as the work to move my quick performance hack to main line code was more involved than I had hoped.

I haven't measured this again but memory consumption and speed gains were massive with the initial spike. Perf was ~2x for my smaller sample set and it allowed the big sample set to do its thing at all (I killed it at 12GB memory consumption).


We used to read all files into memory - which gets too much if
someone runs a massively parallel CI because 400 * 10MB is still
~4GB and that's just pure file size and we do a lot more with it.

Breaks the interface of ResultMerger.merge_and_store but it's not
intended as a public interface. Will leave a note in the Changelog
anyhow.

What is attempted to do top leve is perhaps easier to see when
looking at the spike code: https://github.com/simplecov-ruby/simplecov/compare/collate-plus-plus?expand=1

Changes go further than just not reading all files in at once,
during the merge process we also operate on the raw file structure
as opposed to creating SimpleCov::Result. Creating SimpleCov::Result
comes with a lot of overhead, notably reading in all source files. So,
that's even worse doing ~400 times in a large code base.

There's more optimization potential for cases like these which
I'll open a ticket about but notably:

  • Potentially don't create SimpleCov::Result at all until we really
    produce results (just dump the raw coverage more or less)
  • allow running without a formatter as only the last one really
    needs the formatter

Comment thread lib/simplecov.rb Outdated

# Use the ResultMerger to produce a single, merged result, ready to use.
@result = ResultMerger.merge_and_store(*results)
# TODO: Did/does collate ignore old results? It probably shouldn't, right?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pretty sure it didn't/doesn't in the past but does right now which means we'll likely have to introduce a boolean flag to merge_and_store.

Comment thread lib/simplecov/result.rb
# to have "old" resultsets lying around (but not too old so that they're still
# considered we can adapt them).
# See https://github.com/simplecov-ruby/simplecov/pull/824#issuecomment-576049747
def adapt_result(result)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code had to be moved since we don't create Result objects for merging any more

Comment thread lib/simplecov/result.rb Outdated
end
end

# This is dropping data of files that can not be found... why though?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seriously... why? Can't we just let it in there and it'll be dropped on result generation anyhow as we can't display it? Probaby have to do some git digging on this to find the reason.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has existed basically forever: 4f37de8

Comment thread lib/simplecov/result_merger.rb Outdated
# SimpleCov::Result with merged coverage data and the command_name
# for the result consisting of a join on all source result's names
#
# TODO: Maybe put synchronization just around the reading?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah so right now it synchronizes including the whole merge time which might be a slow down - probably means extracting onr or 2 smaller methods and just puttign them together but should be worth it


# Clear out the previously cached .resultset
def clear_resultset
@resultset = nil

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resultset was only ever called in library code right after clearing it, so the whole clear and cache mechanism wasn't much good (unless I missed something)

@@ -0,0 +1,3 @@
# some comment
puts "wargh"
puts "wargh 1"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these files were just missing but referenced in tests and sicne we have code that removes missing files from saved results it caused problems so added them :)

@PragTob
PragTob marked this pull request as draft December 28, 2020 20:25
@deivid-rodriguez

Copy link
Copy Markdown
Collaborator

@PragTob I'm sorry I can't find time right now to review this 😞

@PragTob

PragTob commented Jan 3, 2021

Copy link
Copy Markdown
Collaborator Author

@deivid-rodriguez no worries at all! 💚 Just thought it'd be great. I'll merge it this afternoon, if at some point later you find the time I'd be happy but no pressure or worries at all. Happy new year and I hope that all is well! 🚀

WhatsApp Image 2020-12-10 at 09 49 49

@PragTob
PragTob removed the request for review from deivid-rodriguez January 3, 2021 13:20
PragTob and others added 5 commits January 3, 2021 14:39
We used to read all files into memory - which gets too much if
someone runs a massively parallel CI because 400 * 10MB is still
~4GB and that's just pure file size and we do a lot more with it.

Breaks the interface of ResultMerger.merge_and_store but it's not
intended as a public interface. Will leave a note in the Changelog
anyhow.

What is attempted to do top leve is perhaps easier to see when
looking at the spike code: https://github.com/simplecov-ruby/simplecov/compare/collate-plus-plus?expand=1

Changes go further than just not reading all files in at once,
during the merge process we also operate on the raw file structure
as opposed to creating SimpleCov::Result. Creating SimpleCov::Result
comes with a lot of overhead, notably reading in all source files. So,
that's even worse doing ~400 times in a large code base.

There's more optimization potential for cases like these which
I'll open a ticket about but notably:
* Potentially don't create SimpleCov::Result at all until we really
  produce results (just dump the raw coverage more or less)
* allow running without a formatter as only the last one really
  needs the formatter
* lets instead of instance variables
* less nesting but hopefully more meaningful
@PragTob
PragTob force-pushed the collate-improve-performance branch from df37201 to a3247f7 Compare January 3, 2021 13:39
@PragTob
PragTob marked this pull request as ready for review January 3, 2021 13:39
@PragTob
PragTob merged commit 168f244 into main Jan 3, 2021
@PragTob
PragTob deleted the collate-improve-performance branch January 3, 2021 14:50
@PragTob PragTob mentioned this pull request Jan 4, 2021
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants