$30 off During Our Annual Pro Sale. View Details »

Learning from performance improvements on GraphQL Ruby

Learning from performance improvements on GraphQL Ruby

https://www.meetup.com/graphql-tokyo/events/295606838/

Meetup #21 Guest talk and lightning talks

Fumiaki MATSUSHIMA

September 13, 2023
Tweet

More Decks by Fumiaki MATSUSHIMA

Other Decks in Technology

Transcript

  1. @mtsmfm
    Learning from performance
    improvements on
    GraphQL Ruby

    View Slide

  2. Fumiaki
    Matsushima
    GitHub, Twitter
    @mtsmfm

    View Slide

  3. https://www.meetup.com/ja-JP/GraphQL-Tokyo/

    View Slide

  4. https://autify.com/

    View Slide

  5. https://autify.com/careers

    View Slide

  6. https://www.youtube.com/watch?v=dvip2PXi52Y&t=1875s

    View Slide

  7. View Slide

  8. View Slide

  9. Summary of my last talk
    - GraphQL Ruby 2.0.13 (the latest version at
    that time) is twice slower than 1.5.15

    View Slide

  10. Since 2.0.13, there have been 17
    releases!
    https://rubygems.org/gems/graphql/versions

    View Slide

  11. Benchmark target
    type Article {
    field0: String!
    field1: String!
    ...
    fieldN: String!
    }
    type Query {
    articles: [Article!]!
    }
    query {
    articles {
    field0, field1, ..., fieldN
    }
    }

    View Slide

  12. Benchmark target
    type Article {
    field0: String!
    field1: String!
    ...
    fieldN: String!
    }
    type Query {
    articles: [Article!]!
    }
    query {
    articles {
    field0, field1, ..., fieldN
    }
    }
    Num of
    articles
    = 1000
    Num of fields = 100

    View Slide

  13. Run benchmark on GitHub Actions
    https://github.com/mtsmfm/graphql-ruby-benchmark/pull/4

    View Slide

  14. Run benchmark on GitHub Actions
    https://github.com/mtsmfm/graphql-ruby-benchmark/pull/4

    View Slide

  15. Run benchmark on GitHub Actions
    https://github.com/mtsmfm/graphql-ruby-benchmark/pull/4

    View Slide

  16. Benchmark env
    - GitHub Actions (ubuntu-latest)
    - Ruby 3.2.2
    - https://github.com/mtsmfm/graphql-ruby-benchmark

    View Slide

  17. View Slide

  18. View Slide

  19. Many performance improvements
    https://github.com/rmosolgo/graphql-ruby/blob/904e8c595637450
    40b6d05c5ecb22a73a320c7b5/CHANGELOG.md

    View Slide

  20. View Slide

  21. View Slide

  22. PR #4399
    https://github.com/rmosolgo/graphql-ruby/pull/4399

    View Slide

  23. PR #4399
    https://github.com/rmosolgo/graphql-ruby/pull/4399

    View Slide

  24. PR #4399
    https://github.com/rmosolgo/graphql-ruby/pull/4399

    View Slide

  25. PR #4399
    https://github.com/rmosolgo/graphql-ruby/pull/4399

    View Slide

  26. PR #4399
    1. Introduces CurrentState class to store
    runtime state
    2. Removes unnecessary context lookup

    View Slide

  27. PR #4399
    1. Introduces CurrentState class to store
    runtime state
    2. Removes unnecessary context lookup

    View Slide

  28. Previous code

    View Slide

  29. Previous code

    View Slide

  30. PR #4399
    https://github.com/rmosolgo/graphql-ruby/pull/4399

    View Slide

  31. Referring context takes time?!

    View Slide

  32. Context#[]
    https://github.com/rmosolgo/graphql-ruby/blob/904e8c59563745040b6d05c5ec
    b22a73a320c7b5/lib/graphql/query/context.rb#L124-L141

    View Slide

  33. Context#[]
    https://github.com/rmosolgo/graphql-ruby/blob/904e8c59563745040b6d05c5ec
    b22a73a320c7b5/lib/graphql/query/context.rb#L124-L141
    Hash like
    Hash
    Set

    View Slide

  34. Looks fast
    enough
    🤔

    View Slide

  35. Benchmark target
    type Article {
    field0: String!
    field1: String!
    ...
    fieldN: String!
    }
    type Query {
    articles: [Article!]!
    }
    query {
    articles {
    field0, field1, ..., fieldN
    }
    }
    Num of
    articles
    = 1000
    Num of fields = 100

    View Slide

  36. Benchmark target
    type Article {
    field0: String!
    field1: String!
    ...
    fieldN: String!
    }
    type Query {
    articles: [Article!]!
    }
    query {
    articles {
    field0, field1, ..., fieldN
    }
    }
    Num of
    articles
    = 1000
    Num of fields = 100
    = 100,000 fields!

    View Slide

  37. Learning from PR #4399
    1. Field related code can be a hotspot
    a. Even context lookup

    View Slide

  38. Context#[]
    https://github.com/rmosolgo/graphql-ruby/blob/904e8c59563745040b6d05c5ec
    b22a73a320c7b5/lib/graphql/query/context.rb#L124-L141

    View Slide

  39. It changes [key] to public_send(key)
    https://github.com/rmosolgo/graphql-ruby/pull/4399/files#diff-2c8869b38ea62e6
    9d0aa4fc7e571e6dc3b8c9f05fba9c25bc79fc17cfee2a335

    View Slide

  40. require 'bundler/inline'
    gemfile do
    source 'https://rubygems.org'
    gem 'benchmark-ips', require: 'benchmark/ips'
    gem 'graphql'
    end
    state = GraphQL::Execution::Interpreter::Runtime::CurrentState.new
    Benchmark.ips do |x|
    x.report('send') do
    state.public_send(:current_arguments)
    end
    x.report('direct') do
    state.current_arguments
    end
    x.compare!
    end

    View Slide

  41. public_send is 2 times slower
    $ ruby foo.rb
    Warming up --------------------------------------
    send 889.676k i/100ms
    direct 2.157M i/100ms
    Calculating -------------------------------------
    send 8.757M (± 7.4%) i/s - 43.594M in 5.008124s
    direct 20.391M (± 7.0%) i/s - 103.546M in 5.105176s
    Comparison:
    direct: 20391490.9 i/s
    send: 8756908.0 i/s - 2.33x slower

    View Slide

  42. 2% improvements
    https://github.com/rmosolgo/graphql-ruby/pull/4631

    View Slide

  43. Conclusion
    1. GraphQL Ruby is twice faster than last year!
    2. Consider total number of fields
    a. Especially if you’re going to add some codes which
    affect all fields
    3. Enjoy Talk Driven Development

    View Slide