Slide 1

Slide 1 text

@mtsmfm Learning from performance improvements on GraphQL Ruby

Slide 2

Slide 2 text

Fumiaki Matsushima GitHub, Twitter @mtsmfm

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

https://autify.com/

Slide 5

Slide 5 text

https://autify.com/careers

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Previous code

Slide 29

Slide 29 text

Previous code

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

Referring context takes time?!

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Looks fast enough 🤔

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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!

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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