Skip to content

Instantly share code, notes, and snippets.

@DmitryTsepelev
Last active February 19, 2021 09:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DmitryTsepelev/36e290cf64b4ec0b18294d0a57fb26ff to your computer and use it in GitHub Desktop.
Save DmitryTsepelev/36e290cf64b4ec0b18294d0a57fb26ff to your computer and use it in GitHub Desktop.

Setup

Results gathered from my MacBook Pro Mid 2014 (2,5 GHz Quad-Core Intel Core i7, 16 GB 1600 MHz DDR3)

GraphQL Parsing

                                   user     system      total        real
1 fields, 0 nested levels:     0.000153   0.000002   0.000155 (  0.000152)
1 fields, 2 nested levels:     0.000188   0.000001   0.000189 (  0.000187)
1 fields, 4 nested levels:     0.000252   0.000001   0.000253 (  0.000240)
2 fields, 0 nested levels:     0.000134   0.000013   0.000147 (  0.000132)
2 fields, 2 nested levels:     0.000420   0.000006   0.000426 (  0.000411)
2 fields, 4 nested levels:     0.001695   0.000001   0.001696 (  0.001694)
4 fields, 0 nested levels:     0.000154   0.000001   0.000155 (  0.000153)
4 fields, 2 nested levels:     0.001744   0.000001   0.001745 (  0.001744)
4 fields, 4 nested levels:     0.032188   0.000269   0.032457 (  0.032581)
8 fields, 0 nested levels:     0.000316   0.000034   0.000350 (  0.000352)
8 fields, 2 nested levels:     0.013464   0.000218   0.013682 (  0.013917)
8 fields, 4 nested levels:     0.910159   0.008081   0.918240 (  0.919507)

Execution

GraphQL

Execution

Without Interpreter, 1.11.5:

Rehearsal ------------------------------------
   1.163833   0.007014   1.170847 (  1.178342)
--------------------------- total: 1.170847sec

       user     system      total        real
   1.069720   0.003178   1.072898 (  1.076896)

With Interpreter, 1.11.5:

Rehearsal ------------------------------------
   1.078940   0.005128   1.084068 (  1.093612)
--------------------------- total: 1.084068sec

       user     system      total        real
   1.045195   0.002486   1.047681 (  1.050175)

1.12.4:

Rehearsal ------------------------------------
   1.015847   0.003550   1.019397 (  1.020423)
--------------------------- total: 1.019397sec

       user     system      total        real
   1.020112   0.001398   1.021510 (  1.022449)

Memory

Without Interpreter, 1.11.5:

Total allocated: 98.99 kB (943 objects)
Total retained:  5.38 kB (29 objects)

allocated memory by gem
-----------------------------------
  79.71 kB  graphql-1.11.5
   7.67 kB  other
   6.05 kB  ostruct
   2.70 kB  set
   2.49 kB  racc
  256.00 B  time
  120.00 B  forwardable

With Interpreter, 1.11.5:

Total allocated: 90.48 kB (909 objects)
Total retained:  0 B (0 objects)

allocated memory by gem
-----------------------------------
  74.40 kB  graphql-1.11.5
   7.62 kB  other
   5.81 kB  ostruct
   2.33 kB  racc
  256.00 B  time
   80.00 B  forwardable

1.12.4:

Total allocated: 55.20 kB (689 objects)
Total retained:  0 B (0 objects)

allocated memory by gem
-----------------------------------
  40.76 kB  graphql-1.12.4
   8.55 kB  other
   5.64 kB  ostruct
  256.00 B  time

JSON API

Execution

Rehearsal ------------------------------------
   0.169245   0.000979   0.170224 (  0.170495)
--------------------------- total: 0.170224sec

       user     system      total        real
   0.157097   0.000130   0.157227 (  0.157253)

Memory

Total allocated: 30.50 kB (285 objects)
Total retained:  464.00 B (2 objects)

allocated memory by gem
-----------------------------------
  15.26 kB  jsonapi-serializable-0.3.1
   5.77 kB  jsonapi-renderer-0.2.2
   3.57 kB  rack-2.0.7
   3.18 kB  other
   1.56 kB  uri
   1.17 kB  set
require "bundler/inline"
require "benchmark"
gemfile do
source "https://rubygems.org"
gem "graphql"
gem "memory_profiler"
end
def generate_fields(field_count, nesting_level, indent = 6)
fields = field_count.times.map do |i|
field = " " * indent + "field#{i+1}"
if nesting_level > 0
field += <<-gql
\s{
#{generate_fields(field_count, nesting_level - 1, indent + 2)}
#{" " * indent}}
gql
end
field
end
fields.join("\n")
end
def generate_query(field_count, nesting_level)
<<-gql
query {
#{generate_fields(field_count, nesting_level)}
}
gql
end
Benchmark.bm(28) do |x|
[1, 2, 4, 8].each do |field_count|
[0, 2, 4].each do |nesting_level|
x.report("#{field_count} fields, #{nesting_level} nested levels: ") do
GraphQL.parse(generate_query(field_count, nesting_level))
end
end
end
end
require "bundler/inline"
require "date"
gemfile do
source "https://rubygems.org"
gem "graphql"
gem "memory_profiler"
end
class OrderType < GraphQL::Schema::Object
field :id, ID, null: false
field :placed_at, GraphQL::Types::ISO8601DateTime, null: false
end
class UserType < GraphQL::Schema::Object
field :id, ID, null: false
field :name, String, null: false
field :orders, [OrderType], null: false
end
class QueryType < GraphQL::Schema::Object
field :user, UserType, null: true do
argument :id, ID, required: true
end
def user(id:)
OpenStruct.new(
id: id,
name: "John Doe",
orders: [
OpenStruct.new(id: 1, placed_at: DateTime.now),
OpenStruct.new(id: 2, placed_at: DateTime.now)
],
)
end
end
class GraphqlSchema < GraphQL::Schema
query QueryType
end
GraphqlSchema.graphql_definition
query = <<-gql
query GetUser($id: ID!) {
user(id: $id) {
id
name
orders {
id
placedAt
}
}
}
gql
# Memory:
report = MemoryProfiler.report { GraphqlSchema.execute(query, variables: { id: "1" }) }
report.pretty_print(scale_bytes: true)
# Execution
require "benchmark"
n = 1_000
Benchmark.bmbm do |x|
x.report do
n.times { GraphqlSchema.execute(query, variables: { id: "1" }) }
end
end
require "bundler/inline"
require 'date'
gemfile do
source "https://rubygems.org"
gem "graphql"
gem "memory_profiler"
end
class OrderType < GraphQL::Schema::Object
field :id, ID, null: false
field :placed_at, GraphQL::Types::ISO8601DateTime, null: false
end
class UserType < GraphQL::Schema::Object
field :id, ID, null: false
field :name, String, null: false
field :orders, [OrderType], null: false
end
class QueryType < GraphQL::Schema::Object
field :user, UserType, null: true do
argument :id, ID, required: true
end
def user(id:)
OpenStruct.new(
id: id,
name: "John Doe",
orders: [
OpenStruct.new(id: 1, placed_at: DateTime.now),
OpenStruct.new(id: 2, placed_at: DateTime.now)
],
)
end
end
class GraphqlSchema < GraphQL::Schema
query QueryType
use GraphQL::Execution::Interpreter
use GraphQL::Analysis::AST
end
query = <<-gql
query GetUser($id: ID!) {
user(id: $id) {
id
name
orders {
id
placedAt
}
}
}
gql
GraphqlSchema.execute(query, variables: { id: "1" })
# Memory:
report = MemoryProfiler.report { GraphqlSchema.execute(query, variables: { id: "1" }) }
report.pretty_print(scale_bytes: true)
# Execution
require "benchmark"
n = 1_000
Benchmark.bmbm do |x|
x.report do
n.times { GraphqlSchema.execute(query, variables: { id: "1" }) }
end
end
require "ostruct"
require "date"
require "bundler/inline"
require "rack/utils"
gemfile do
source "https://rubygems.org"
gem "jsonapi-serializable"
gem "memory_profiler"
end
class User
attr_reader :id, :name, :orders
def initialize(id, name, orders)
@id, @name, @orders = id, name, orders
end
class << self
def find(id)
new(
id,
"John Doe",
[Order.new(1, DateTime.now), Order.new(2, DateTime.now)],
)
end
end
end
class Order
attr_reader :id, :placed_at
def initialize(id, placed_at)
@id, @placed_at = id, placed_at
end
end
class SerializableOrder < JSONAPI::Serializable::Resource
type 'orders'
attributes :id
attribute :placed_at do
@object.placed_at.iso8601
end
link :self do
"orders/#{@object.id}"
end
end
class SerializableUser < JSONAPI::Serializable::Resource
type 'users'
attributes :id, :name
has_many :orders do
data do
@object.orders
end
end
link :self do
"users/#{@object.id}"
end
end
class UserController
def show(uri)
parsed_uri = URI.parse(uri)
user_id = parsed_uri.path.delete("/users/")
user = User.find(user_id)
render_params = Rack::Utils.parse_nested_query(parsed_uri.query).yield_self do |parsed|
parsed.merge(
"fields" => parsed["fields"].map { |k, v| [k.to_sym, v.split(",")] }.to_h
).transform_keys(&:to_sym)
end
JSONAPI::Serializable::Renderer.new.render(
user,
render_params.merge(class: { User: SerializableUser, Order: SerializableOrder })
)
end
end
uri = "http://example.com/users/1?include=orders&fields[users]=id,name&fields[orders]=id,placed_at"
# Memory
report = MemoryProfiler.report { UserController.new.show(uri) }
report.pretty_print(scale_bytes: true)
# Execution
require "benchmark"
n = 1_000
Benchmark.bmbm do |x|
x.report do
n.times { UserController.new.show(uri) }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment