mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-16 09:51:59 +03:00
1378730d43
I noticed a few extra calls to `.clone()` while working on an unrelated refactor. I want to remove them for brevity and simplicity; I don't expect a performance improvement. This turns on the Clippy warning `redundant_clone`, which detects unnecessary calls to `.clone()` (and `.to_string()`). It is an unstable warning and so might reports some false positives. If we find any, we can suppress the warning there. V3_GIT_ORIGIN_REV_ID: a713f29cf862d6f4cb40300105c6b9f96df00676
256 lines
8.0 KiB
Rust
256 lines
8.0 KiB
Rust
use core::time::Duration;
|
|
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, SamplingMode};
|
|
use execute::{execute_mutation_plan, execute_query_plan, generate_request_plan};
|
|
use execute::{execute_query_internal, generate_ir, HttpContext};
|
|
use hasura_authn_core::Identity;
|
|
use lang_graphql::http::RawRequest;
|
|
use open_dds::permissions::Role;
|
|
use schema::GDS;
|
|
use std::collections::HashMap;
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
use tokio::runtime::Runtime;
|
|
|
|
extern crate json_value_merge;
|
|
use json_value_merge::Merge;
|
|
use serde_json::Value;
|
|
|
|
use std::path::Path;
|
|
|
|
use lang_graphql as gql;
|
|
|
|
pub fn merge_with_common_metadata(
|
|
common_metadata_path: &Path,
|
|
metadata_path_string: &Path,
|
|
) -> Value {
|
|
let common_metadata = fs::read_to_string(common_metadata_path).unwrap();
|
|
let test_metadata = fs::read_to_string(metadata_path_string).unwrap();
|
|
|
|
let mut first_json_value: Value = serde_json::from_str(&common_metadata).unwrap();
|
|
let second_json_value: Value = serde_json::from_str(&test_metadata).unwrap();
|
|
first_json_value.merge(&second_json_value);
|
|
first_json_value
|
|
}
|
|
|
|
pub fn bench_execute(
|
|
c: &mut Criterion,
|
|
test_path_string: &str,
|
|
common_metadata_path_string: &str,
|
|
benchmark_group: &str,
|
|
) {
|
|
let root_test_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests");
|
|
let test_path = root_test_dir.join(test_path_string);
|
|
let request_path = test_path.join("request.gql");
|
|
|
|
let common_metadata_path = root_test_dir.join(common_metadata_path_string);
|
|
let metadata_path = test_path.join("metadata.json");
|
|
let metadata = merge_with_common_metadata(&metadata_path, &common_metadata_path);
|
|
|
|
let gds = GDS::new_with_default_flags(open_dds::traits::OpenDd::deserialize(metadata).unwrap())
|
|
.unwrap();
|
|
let schema = GDS::build_schema(&gds).unwrap();
|
|
let http_context = HttpContext {
|
|
client: reqwest::Client::new(),
|
|
ndc_response_size_limit: None,
|
|
};
|
|
let runtime = Runtime::new().unwrap();
|
|
|
|
let query = fs::read_to_string(request_path).unwrap();
|
|
let raw_request = RawRequest {
|
|
operation_name: None,
|
|
query,
|
|
variables: None,
|
|
};
|
|
|
|
let request_headers = reqwest::header::HeaderMap::new();
|
|
let session = Identity::admin(Role::new("admin"))
|
|
.get_role_authorization(None)
|
|
.unwrap()
|
|
.build_session(HashMap::new());
|
|
|
|
let mut group = c.benchmark_group(benchmark_group);
|
|
|
|
// these numbers are fairly low, optimising for runtime of benchmark suite
|
|
group.warm_up_time(Duration::from_millis(500));
|
|
group.sample_size(20);
|
|
group.sampling_mode(SamplingMode::Flat);
|
|
|
|
// Parse request
|
|
group.bench_with_input(
|
|
BenchmarkId::new("bench", "Resolution of raw request"),
|
|
&(&runtime, &raw_request),
|
|
|b, (runtime, request)| {
|
|
b.to_async(*runtime).iter(|| async {
|
|
gql::parser::Parser::new(&request.query)
|
|
.parse_executable_document()
|
|
.unwrap()
|
|
});
|
|
},
|
|
);
|
|
|
|
let query = gql::parser::Parser::new(&raw_request.query)
|
|
.parse_executable_document()
|
|
.unwrap();
|
|
|
|
// Normalize request
|
|
let request = gql::http::Request {
|
|
operation_name: None,
|
|
query,
|
|
variables: HashMap::default(),
|
|
};
|
|
|
|
group.bench_with_input(
|
|
BenchmarkId::new("bench_execute", "Normalize request"),
|
|
&(&runtime, &schema, &request),
|
|
|b, (runtime, schema, request)| {
|
|
b.to_async(*runtime).iter(|| async {
|
|
gql::validation::normalize_request(
|
|
&schema::GDSRoleNamespaceGetter {
|
|
scope: session.role.clone(),
|
|
},
|
|
schema,
|
|
request,
|
|
)
|
|
.unwrap();
|
|
});
|
|
},
|
|
);
|
|
|
|
let normalized_request = gql::validation::normalize_request(
|
|
&schema::GDSRoleNamespaceGetter {
|
|
scope: session.role.clone(),
|
|
},
|
|
&schema,
|
|
&request,
|
|
)
|
|
.unwrap();
|
|
|
|
// Generate IR
|
|
group.bench_with_input(
|
|
BenchmarkId::new("bench_execute", "Generate IR"),
|
|
&(&runtime, &schema),
|
|
|b, (runtime, schema)| {
|
|
b.to_async(*runtime).iter(|| async {
|
|
generate_ir(schema, &session, &request_headers, &normalized_request).unwrap()
|
|
});
|
|
},
|
|
);
|
|
|
|
let ir = generate_ir(&schema, &session, &request_headers, &normalized_request).unwrap();
|
|
|
|
// Generate Query Plan
|
|
group.bench_with_input(
|
|
BenchmarkId::new("bench_execute", "Generate Query Plan"),
|
|
&(&runtime),
|
|
|b, runtime| {
|
|
b.to_async(*runtime)
|
|
.iter(|| async { generate_request_plan(&ir).unwrap() });
|
|
},
|
|
);
|
|
|
|
// Execute Query plan
|
|
group.bench_with_input(
|
|
BenchmarkId::new("bench_execute", "Execute Query Plan"),
|
|
&(&runtime),
|
|
|b, runtime| {
|
|
b.to_async(*runtime).iter(|| async {
|
|
match generate_request_plan(&ir).unwrap() {
|
|
execute::RequestPlan::QueryPlan(query_plan) => {
|
|
execute_query_plan(&http_context, query_plan, None).await
|
|
}
|
|
execute::RequestPlan::MutationPlan(mutation_plan) => {
|
|
execute_mutation_plan(&http_context, mutation_plan, None).await
|
|
}
|
|
}
|
|
});
|
|
},
|
|
);
|
|
|
|
// Total execution time from start to finish
|
|
group.bench_with_input(
|
|
BenchmarkId::new("bench_execute", "Total Execution time"),
|
|
&(&runtime, &schema, raw_request),
|
|
|b, (runtime, schema, request)| {
|
|
b.to_async(*runtime).iter(|| async {
|
|
execute_query_internal(
|
|
&http_context,
|
|
schema,
|
|
&session,
|
|
&request_headers,
|
|
request.clone(),
|
|
None,
|
|
)
|
|
.await
|
|
.unwrap()
|
|
});
|
|
},
|
|
);
|
|
|
|
group.finish();
|
|
}
|
|
|
|
fn bench_execute_all(c: &mut Criterion) {
|
|
// Simple select
|
|
let test_path_string = "execute/models/select_one/simple_select";
|
|
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
|
bench_execute(
|
|
c,
|
|
test_path_string,
|
|
common_metadata_path_string,
|
|
"simple_select",
|
|
);
|
|
|
|
// Select Many
|
|
let test_path_string = "execute/models/select_many/simple_select";
|
|
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
|
bench_execute(
|
|
c,
|
|
test_path_string,
|
|
common_metadata_path_string,
|
|
"select_many",
|
|
);
|
|
|
|
// Select Many with where clause
|
|
let test_path_string = "execute/models/select_many/where/simple";
|
|
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
|
bench_execute(
|
|
c,
|
|
test_path_string,
|
|
common_metadata_path_string,
|
|
"select_many_where",
|
|
);
|
|
|
|
// Object Relationships
|
|
let test_path_string = "execute/relationships/object";
|
|
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
|
bench_execute(
|
|
c,
|
|
test_path_string,
|
|
common_metadata_path_string,
|
|
"object_relationship",
|
|
);
|
|
|
|
// Array Relationships
|
|
let test_path_string = "execute/relationships/array";
|
|
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
|
bench_execute(
|
|
c,
|
|
test_path_string,
|
|
common_metadata_path_string,
|
|
"array_relationship",
|
|
);
|
|
|
|
// Relay node field
|
|
let test_path_string = "execute/relay/relay";
|
|
let common_metadata_path_string = "execute/common_metadata/postgres_connector_schema.json";
|
|
bench_execute(
|
|
c,
|
|
test_path_string,
|
|
common_metadata_path_string,
|
|
"relay_node_field",
|
|
);
|
|
}
|
|
|
|
criterion_group!(benches, bench_execute_all);
|
|
criterion_main!(benches);
|