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

Lower the memory allocations #1188

Merged

Conversation

stokarenko
Copy link
Contributor

@stokarenko stokarenko commented Mar 10, 2019

It prevents the repeating hashes creation during the calculation of object and object_changes.

The real-life case, discovered with a help of memory_profiler gem:

  1. It saves ~35Mb per bulk of 100 typical objects like User;
  2. It saves ~875Mb per Sidekiq process full of bulk jobs like P1, under default concurrency 25.

As a part of RAM optimization we do:

  • memoization of repeatedly called PaperTrail::Events::Base methods;
  • cache the AR changed_attributes for AR < 5.1;
  • prefer to build the Version objects by pure Class.new instead of association.build.

The record's association cache will be invalidated on the way by association.reset, so no any explicit versions.reload calls are needed now.

  • Wrote good commit messages.
  • Feature branch is up-to-date with master (if not - rebase it).
  • Squashed related commits together.
  • Added tests.
  • Added an entry to the Changelog if the new
    code introduces user-observable changes.
  • The PR relates to only one subject with a clear title
    and description in grammatically correct, complete sentences.

@stokarenko stokarenko force-pushed the lower-the-memory-allocations branch 3 times, most recently from 5782dba to 2d09f08 Compare March 10, 2019 14:08
Copy link
Member

@jaredbeck jaredbeck left a comment

Choose a reason for hiding this comment

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

.

@jaredbeck
Copy link
Member

It saves ~35Mb per bulk of 100 typical objects like User;

Awesome! Thanks for working on this.

@jaredbeck
Copy link
Member

I'd expect a memory optimization to not change existing tests.

Said another way, I'd be a lot more comfortable reviewing this if existing tests can be kept exactly the same.

@stokarenko
Copy link
Contributor Author

Reverted the changes on tests, @jaredbeck please revisit.

Copy link
Member

@jaredbeck jaredbeck left a comment

Choose a reason for hiding this comment

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

Sergey, I've finished my first review. Generally speaking, I like the direction this is going.

In this first review, I've focused on getting more information about some things I don't understand, and trying to limit the scope. It's a big PR, so if you don't mind splitting it up a bit, as I suggest below, that would be very helpful.

In future reviews, I'll look more closely at some of the logic, and I'll be running your benchmarks locally.

lib/paper_trail/events/base.rb Show resolved Hide resolved
lib/paper_trail/events/base.rb Show resolved Hide resolved
lib/paper_trail/events/base.rb Outdated Show resolved Hide resolved
lib/paper_trail/record_trail.rb Show resolved Hide resolved
lib/paper_trail/record_trail.rb Show resolved Hide resolved
lib/paper_trail/record_trail.rb Outdated Show resolved Hide resolved
lib/paper_trail/record_trail.rb Show resolved Hide resolved
expect(&version_building).to allocate_less_than(35).kilobytes
end
end
end
Copy link
Member

Choose a reason for hiding this comment

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

It's very cool that you were able to write these benchmarks as tests. I've never worked on a project with such tests, but I'm willing to try it. My only concern would be if, in the future, memory usage inside rails increases (in a way we cannot control) causing these tests to fail. If it becomes painful in the future, we may need to separate these benchmarks from the test suite.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Any optimization efforts become to be mindless without such kind of tests :)
Any next PR can easily ruin all the winnings.

As for the third-party changes, which are really out of our control - at least we will know about the problems with them. We can mark such particular gems and versions as ineffective both in readme and tests for example.

In general you're right, the life will be harder with these tests :)

"expected that example will allocate less than #{expected}#{@scale},"\
" but allocated #{@allocated}#{@scale}"
end
end
Copy link
Member

Choose a reason for hiding this comment

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

I did not know the RSpec matcher API was so flexible. This is pretty great.

@stokarenko stokarenko force-pushed the lower-the-memory-allocations branch 2 times, most recently from 44474b2 to 6966f83 Compare March 13, 2019 09:17
@stokarenko
Copy link
Contributor Author

@jaredbeck please take a look at https://travis-ci.org/paper-trail-gem/paper_trail/builds/505655659

As you can see, the removal of #1189 is strongly affect to performance. I'm forced to make more pessimistic assertions for this PR.

@stokarenko
Copy link
Contributor Author

@jaredbeck it is ready for the next review )

Copy link
Member

@jaredbeck jaredbeck left a comment

Choose a reason for hiding this comment

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

Second review: Now that #1189 has been merged, please rebase and restore the memory numbers in the test.

There probably won't be a need for a third review, thank you for your work on this so far. Splitting it up into smaller pieces was very helpful, thanks.

lib/paper_trail/record_trail.rb Show resolved Hide resolved
It prevents the repeating hashes creation during the calculation of `object` and `object_changes`.

The real-life case, discovered with a help of `memory_profiler` gem:
1. It saves `~35Mb` per bulk of 100 typical objects like `User`;
2. It saves `~875Mb` per Sidekiq process full of bulk jobs like P1,
   under default concurrency 25.
@stokarenko
Copy link
Contributor Author

please rebase and restore the memory numbers in the test.

done, please revisit )

Thank you for assistance during this journey )

@jaredbeck jaredbeck merged commit cf17bc4 into paper-trail-gem:master Mar 14, 2019
@jaredbeck
Copy link
Member

I don't want to make any changes to our public API as part of an optimization PR.

I'm going to make build_version_on_create and build_version_on_update private, if you can live with that. I want it to be clear that they are not part of our public API (yet).

If you'd like to discuss some ideas for the public API, please email me (jared@jaredbeck.com) as we have temporarily disabled GH issues.

jaredbeck added a commit that referenced this pull request Mar 14, 2019
@jaredbeck
Copy link
Member

Released as 10.2.1

aried3r pushed a commit to aried3r/paper_trail that referenced this pull request Dec 14, 2020
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