Skip to content

Commit 4712a3d

Browse files
authored
Merge pull request rmosolgo#4317 from rmosolgo/forward-port-perf
Forward port perf
2 parents 4a4d5ac + 4f7bc72 commit 4712a3d

10 files changed

Lines changed: 108 additions & 40 deletions

File tree

Rakefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,12 @@ namespace :bench do
128128
prepare_benchmark
129129
GraphQLBenchmark.profile_stack_depth
130130
end
131+
132+
desc "Run a very big introspection query"
133+
task :profile_large_introspection do
134+
prepare_benchmark
135+
GraphQLBenchmark.profile_large_introspection
136+
end
131137
end
132138

133139
namespace :test do

benchmark/run.rb

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,43 @@ def self.profile
7272
StackProf::Report.new(result).print_text
7373
end
7474

75+
def self.profile_large_introspection
76+
schema = Class.new(GraphQL::Schema) do
77+
query_t = Class.new(GraphQL::Schema::Object) do
78+
graphql_name("Query")
79+
100.times do |n|
80+
obj_t = Class.new(GraphQL::Schema::Object) do
81+
graphql_name("Object#{n}")
82+
20.times do |n2|
83+
field :"field#{n2}", String do
84+
argument :arg, String
85+
end
86+
end
87+
end
88+
field :"rootfield#{n}", obj_t
89+
end
90+
end
91+
query(query_t)
92+
end
93+
94+
Benchmark.ips do |x|
95+
x.report("Run large introspection") {
96+
schema.to_json
97+
}
98+
end
99+
100+
result = StackProf.run(mode: :wall, interval: 10) do
101+
schema.to_json
102+
end
103+
StackProf::Report.new(result).print_text
104+
105+
report = MemoryProfiler.report do
106+
schema.to_json
107+
end
108+
puts "\n\n"
109+
report.pretty_print
110+
end
111+
75112
# Adapted from https://github.com/rmosolgo/graphql-ruby/issues/861
76113
def self.profile_large_result
77114
schema = ProfileLargeResult::Schema
@@ -128,10 +165,32 @@ class FooType < GraphQL::Schema::Object
128165
field :id, ID, null: false
129166
field :int1, Integer, null: false
130167
field :int2, Integer, null: false
131-
field :string1, String, null: false
132-
field :string2, String, null: false
133-
field :boolean1, Boolean, null: false
134-
field :boolean2, Boolean, null: false
168+
field :string1, String, null: false do
169+
argument :arg1, String, required: false
170+
argument :arg2, String, required: false
171+
argument :arg3, String, required: false
172+
argument :arg4, String, required: false
173+
end
174+
175+
field :string2, String, null: false do
176+
argument :arg1, String, required: false
177+
argument :arg2, String, required: false
178+
argument :arg3, String, required: false
179+
argument :arg4, String, required: false
180+
end
181+
182+
field :boolean1, Boolean, null: false do
183+
argument :arg1, String, required: false
184+
argument :arg2, String, required: false
185+
argument :arg3, String, required: false
186+
argument :arg4, String, required: false
187+
end
188+
field :boolean2, Boolean, null: false do
189+
argument :arg1, String, required: false
190+
argument :arg2, String, required: false
191+
argument :arg3, String, required: false
192+
argument :arg4, String, required: false
193+
end
135194
end
136195

137196
class QueryType < GraphQL::Schema::Object

lib/graphql/execution/interpreter/runtime.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, owner_obj
409409
raise "Invariant: no field for #{owner_type}.#{field_name}"
410410
end
411411
end
412+
412413
return_type = field_defn.type
413414

414415
next_path = path + [result_name]
@@ -431,17 +432,16 @@ def evaluate_selection(path, result_name, field_ast_nodes_or_ast_node, owner_obj
431432
total_args_count = field_defn.arguments(context).size
432433
if total_args_count == 0
433434
resolved_arguments = GraphQL::Execution::Interpreter::Arguments::EMPTY
434-
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
435+
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
435436
else
436437
# TODO remove all arguments(...) usages?
437438
@query.arguments_cache.dataload_for(ast_node, field_defn, object) do |resolved_arguments|
438-
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object)
439+
evaluate_selection_with_args(resolved_arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selections_result, parent_object, return_type)
439440
end
440441
end
441442
end
442443

443-
def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object) # rubocop:disable Metrics/ParameterLists
444-
return_type = field_defn.type
444+
def evaluate_selection_with_args(arguments, field_defn, next_path, ast_node, field_ast_nodes, owner_type, object, is_eager_field, result_name, selection_result, parent_object, return_type) # rubocop:disable Metrics/ParameterLists
445445
after_lazy(arguments, owner: owner_type, field: field_defn, path: next_path, ast_node: ast_node, owner_object: object, arguments: arguments, result_name: result_name, result: selection_result) do |resolved_arguments|
446446
if resolved_arguments.is_a?(GraphQL::ExecutionError) || resolved_arguments.is_a?(GraphQL::UnauthorizedError)
447447
continue_value(next_path, resolved_arguments, owner_type, field_defn, return_type.non_null?, ast_node, result_name, selection_result)

lib/graphql/introspection/directive_type.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ class DirectiveType < Introspection::BaseObject
1111
"to the executor."
1212
field :name, String, null: false, method: :graphql_name
1313
field :description, String
14-
field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false
15-
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
14+
field :locations, [GraphQL::Schema::LateBoundType.new("__DirectiveLocation")], null: false, scope: false
15+
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
1616
argument :include_deprecated, Boolean, required: false, default_value: false
1717
end
1818
field :on_operation, Boolean, null: false, deprecation_reason: "Use `locations`.", method: :on_operation?

lib/graphql/introspection/field_type.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class FieldType < Introspection::BaseObject
77
"a name, potentially a list of arguments, and a return type."
88
field :name, String, null: false
99
field :description, String
10-
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false do
10+
field :args, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: false, scope: false do
1111
argument :include_deprecated, Boolean, required: false, default_value: false
1212
end
1313
field :type, GraphQL::Schema::LateBoundType.new("__Type"), null: false

lib/graphql/introspection/schema_type.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ class SchemaType < Introspection::BaseObject
88
"available types and directives on the server, as well as the entry points for "\
99
"query, mutation, and subscription operations."
1010

11-
field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false
11+
field :types, [GraphQL::Schema::LateBoundType.new("__Type")], "A list of all types supported by this server.", null: false, scope: false
1212
field :query_type, GraphQL::Schema::LateBoundType.new("__Type"), "The type that query operations will be rooted at.", null: false
1313
field :mutation_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server supports mutation, the type that mutation operations will be rooted at."
1414
field :subscription_type, GraphQL::Schema::LateBoundType.new("__Type"), "If this server support subscription, the type that subscription operations will be rooted at."
15-
field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false
15+
field :directives, [GraphQL::Schema::LateBoundType.new("__Directive")], "A list of all directives supported by this server.", null: false, scope: false
1616
field :description, String, resolver_method: :schema_description
1717

1818
def schema_description

lib/graphql/introspection/type_type.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@ class TypeType < Introspection::BaseObject
1414
field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
1515
field :name, String, method: :graphql_name
1616
field :description, String
17-
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")] do
17+
field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], scope: false do
1818
argument :include_deprecated, Boolean, required: false, default_value: false
1919
end
20-
field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")]
21-
field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")]
22-
field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")] do
20+
field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
21+
field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], scope: false
22+
field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], scope: false do
2323
argument :include_deprecated, Boolean, required: false, default_value: false
2424
end
25-
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")] do
25+
field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], scope: false do
2626
argument :include_deprecated, Boolean, required: false, default_value: false
2727
end
2828
field :of_type, GraphQL::Schema::LateBoundType.new("__Type")

lib/graphql/schema/field.rb

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -610,27 +610,29 @@ def authorized?(object, args, context)
610610
arg_values = args
611611
using_arg_values = false
612612
end
613-
# Faster than `.any?`
614-
arguments(context).each_value do |arg|
615-
arg_key = arg.keyword
616-
if arg_values.key?(arg_key)
617-
arg_value = arg_values[arg_key]
618-
if using_arg_values
619-
if arg_value.default_used?
620-
# pass -- no auth required for default used
621-
next
622-
else
623-
application_arg_value = arg_value.value
624-
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
625-
application_arg_value.keyword_arguments
613+
if args.size > 0
614+
args = context.warden.arguments(self)
615+
args.each do |arg|
616+
arg_key = arg.keyword
617+
if arg_values.key?(arg_key)
618+
arg_value = arg_values[arg_key]
619+
if using_arg_values
620+
if arg_value.default_used?
621+
# pass -- no auth required for default used
622+
next
623+
else
624+
application_arg_value = arg_value.value
625+
if application_arg_value.is_a?(GraphQL::Execution::Interpreter::Arguments)
626+
application_arg_value.keyword_arguments
627+
end
626628
end
629+
else
630+
application_arg_value = arg_value
627631
end
628-
else
629-
application_arg_value = arg_value
630-
end
631632

632-
if !arg.authorized?(object, application_arg_value, context)
633-
return false
633+
if !arg.authorized?(object, application_arg_value, context)
634+
return false
635+
end
634636
end
635637
end
636638
end

lib/graphql/schema/member/has_arguments.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ def argument_class(new_arg_class = nil)
209209
# @return [Interpreter::Arguments, Execution::Lazy<Interpeter::Arguments>]
210210
def coerce_arguments(parent_object, values, context, &block)
211211
# Cache this hash to avoid re-merging it
212-
arg_defns = self.arguments(context)
212+
arg_defns = context.warden.arguments(self)
213213
total_args_count = arg_defns.size
214214

215215
finished_args = nil
@@ -223,7 +223,7 @@ def coerce_arguments(parent_object, values, context, &block)
223223
argument_values = {}
224224
resolved_args_count = 0
225225
raised_error = false
226-
arg_defns.each do |arg_name, arg_defn|
226+
arg_defns.each do |arg_defn|
227227
context.dataloader.append_job do
228228
begin
229229
arg_defn.coerce_into_values(parent_object, values, context, argument_values)

lib/graphql/schema/warden.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def visible_type?(type, ctx); type.visible?(ctx); end
8181
def visible_enum_value?(ev, ctx); ev.visible?(ctx); end
8282
def visible_type_membership?(tm, ctx); tm.visible?(ctx); end
8383
def interface_type_memberships(obj_t, ctx); obj_t.interface_type_memberships; end
84+
def arguments(owner, ctx); owner.arguments(ctx); end
8485
end
8586
end
8687

@@ -175,8 +176,8 @@ def fields(type_defn)
175176

176177
# @param argument_owner [GraphQL::Field, GraphQL::InputObjectType]
177178
# @return [Array<GraphQL::Argument>] Visible arguments on `argument_owner`
178-
def arguments(argument_owner)
179-
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a) } }
179+
def arguments(argument_owner, ctx = nil)
180+
@visible_arguments ||= read_through { |o| o.arguments(@context).each_value.select { |a| visible_argument?(a, @context) } }
180181
@visible_arguments[argument_owner]
181182
end
182183

0 commit comments

Comments
 (0)