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

Optimize memory alloc and retained #2441

Merged
merged 9 commits into from
May 20, 2024

Conversation

ericproulx
Copy link
Contributor

@ericproulx ericproulx commented May 18, 2024

This PR should improve memory allocation and retained.

Base code

class API < Grape::API
  prefix :api
  version :v1, using: :path

  namespace :test do
    2000.times do |index|
      get "/test#{index}/" do
        'hello'
      end
    end
  end
end

MemoryProfiler.report(allow_files: 'grape') do
  API.compile!
end.pretty_print

This code

branch allocated retained
master ~85.2 MB (502079 objects) ~15.74 MB (80035 objects)
this branch ~75.34MB (408047 objects) ~13.08 MB (54028 objects)
Difference ~9.96 MB (94032 objects) ~2.66 MB (26007) objects)

Real world app

branch allocated retained
master ~64.16 MB (353932 objects) ~9.02 MB (26379 objects)
this branch ~61.44 MB (329231 objects) ~5.86 MB (15271 objects)
Difference ~2.72 MB (24701 objects) ~3.17 MB (11108) objects )

Improve caching

lib/grape/namespace.rb and lib/grape/path.rb were already caching but it could be improved by adding Grape::Router.normalize_path call directly in the cache instead.

Stringify inheritable settings

prefix,namespace and other inheritable settings may be naturally declared with a symbol instead of a string and along compilation, they will be stringified and join create more complex strings. Saving them as string saves some memory allocation.

delete_if instead of -

delete_if will remove elements in the array and returns it. Substracting two arrays will create a new one. Most cases were calling keys and substracting values from its.

Replace AttributesTranslator by ActiveSupport::OrderedOptions

AttributesTranslator is basically a hash with dynamic accessor methods and it is used in lib/grape/router/route.rb and lib/grape/router/greedy_route.rb. These 2 also have an options which is the same data included in the AttributesTranslator. It didn't make sense to keep these two. So, I found that ActiveSupport::OrderedOptions is literally a hash with dynamic accessor methods and it could replace entirely AttributesTranslator. In conjunction with delegate_missing_to, I've successfully drop AttributesTranslator and just add an alias attributes to options.

Introducing base_route.rb

lib/grape/router/greedy_route.rb and lib/grape/router/route.rb are vey close in terms of code so I've created a base_route that both would inherit. It also encapsulated the regexification. I've also added some cache for the regex captures.

Some small refactors

I've refactored some small functions.

Fix #2440

@dblock
Copy link
Member

dblock commented May 20, 2024

This looks good. I opened #2442, too, might take it up if I have some time.

@ericproulx ericproulx marked this pull request as ready for review May 20, 2024 15:52
@dblock dblock merged commit 7c3ff27 into ruby-grape:master May 20, 2024
44 checks passed
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.

Investigation memory allocations
2 participants