Added new benchmark

This commit is contained in:
Ivan Plesskih 2020-06-02 17:57:07 +05:00
parent c41dba50bc
commit 547c653d28
9 changed files with 334 additions and 41 deletions

View File

@ -63,6 +63,8 @@ cargo bench
Now HTML report is available at `benchmark/target/criterion/report`
Read more here: https://bheisler.github.io/criterion.rs/book/criterion_rs.html
## Features
* Fully support async/await

View File

@ -4,10 +4,22 @@ version = "1.14.11"
authors = ["sunli <scott_s829@163.com>"]
edition = "2018"
[dependencies]
async-std = { version = "1.5.0", features = ["attributes"] }
futures = "0.3.4"
serde_json = "*"
async-graphql-parser = { path = "../async-graphql-parser" }
async-graphql = { path = ".." }
[dev-dependencies]
criterion = "0.3"
simple = { path = "simple" }
chat = { path = "chat" }
[[bench]]
name = "simple"
harness = false
[[bench]]
name = "chat"
harness = false

13
benchmark/benches/chat.rs Normal file
View File

@ -0,0 +1,13 @@
use chat::{Q, S};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use graphql_benchmark::{parse, run, serialize, GQLResponse};
pub fn bench(c: &mut Criterion) {
c.bench_function("chat run", |b| b.iter(|| run(&S, black_box(Q))));
c.bench_function("chat parse", |b| b.iter(|| parse(black_box(Q))));
let res = GQLResponse(Ok(run(&S, Q)));
c.bench_function("chat serialize", |b| b.iter(|| serialize(black_box(&res))));
}
criterion_group!(chat, bench);
criterion_main!(chat);

View File

@ -1,12 +1,15 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use simple::{parse, run, serialize, GQLResponse, Q};
use graphql_benchmark::{parse, run, serialize, GQLResponse};
use simple::{Q, S};
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("run", |b| b.iter(|| run(black_box(Q))));
c.bench_function("parse", |b| b.iter(|| parse(black_box(Q))));
let res = GQLResponse(run(Q));
c.bench_function("serialize", |b| b.iter(|| serialize(black_box(&res))));
pub fn bench(c: &mut Criterion) {
c.bench_function("simple run", |b| b.iter(|| run(&S, black_box(Q))));
c.bench_function("simple parse", |b| b.iter(|| parse(black_box(Q))));
let res = GQLResponse(Ok(run(&S, Q)));
c.bench_function("simple serialize", |b| {
b.iter(|| serialize(black_box(&res)))
});
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
criterion_group!(simple, bench);
criterion_main!(simple);

View File

@ -0,0 +1,9 @@
[package]
name = "chat"
version = "0.1.0"
authors = ["Ivan Plesskih <terma95@gmail.com>"]
edition = "2018"
[dependencies]
async-graphql = { path = "../.." }
lazy_static = "*"

249
benchmark/chat/src/lib.rs Normal file
View File

@ -0,0 +1,249 @@
use async_graphql::*;
pub struct ChatData {
pub id: String,
pub created_at: String,
pub title: String,
pub caption: String,
pub creator_user_id: String,
pub state: String,
}
pub struct UserData {
pub id: String,
pub is_operator: bool,
pub phone: u64,
pub join_date: String,
pub state: String,
}
pub struct ProfileData {
pub first_name: String,
pub last_name: String,
pub city: Option<String>,
pub job_title: Option<String>,
pub email: String,
}
pub struct MessageData {
pub id: String,
pub user_id: String,
pub timestamp: String,
pub edited: bool,
pub order: i32,
pub message: String,
}
lazy_static::lazy_static! {
pub static ref CHAT: ChatData = ChatData {
id: "1".to_string(),
created_at: "today".to_string(),
title: "chat".to_string(),
caption: "asdasd".to_string(),
creator_user_id: "123".to_string(),
state: "ACTIVE".to_string(),
};
pub static ref USER: UserData = UserData {
id: "123".to_string(),
is_operator: false,
phone: 79123273936,
join_date: "today".to_string(),
state: "ACTIVE".to_string(),
};
pub static ref PROFILE: ProfileData = ProfileData {
first_name: "Ivan".to_string(),
last_name: "Plesskih".to_string(),
city: Some("Che".to_string()),
job_title: Some("progr".to_string()),
email: "asd@qwe.ru".to_string(),
};
pub static ref MESSAGE: MessageData = MessageData {
id: "456".to_string(),
user_id: "123".to_string(),
timestamp: "today".to_string(),
edited: false,
order: 123,
message: "Hello, world!".to_string(),
};
}
pub struct Chat;
#[Object]
impl Chat {
pub async fn id(&self) -> ID {
ID::from(&CHAT.id)
}
pub async fn messages(&self) -> Vec<Message> {
let mut res = vec![];
for _ in 0..30 {
res.push(Message);
}
res
}
pub async fn users(&self) -> Vec<User> {
let mut res = vec![];
for _ in 0..5 {
res.push(User);
}
res
}
pub async fn creator(&self) -> User {
User
}
#[field(name = "created_at")]
pub async fn created_at(&self) -> &String {
&CHAT.created_at
}
pub async fn title(&self) -> &String {
&CHAT.title
}
pub async fn caption(&self) -> &String {
&CHAT.caption
}
pub async fn state(&self) -> &String {
&CHAT.state
}
}
pub struct Message;
#[Object]
impl Message {
pub async fn id(&self) -> ID {
ID::from(&MESSAGE.id)
}
pub async fn user(&self) -> User {
User
}
pub async fn timestamp(&self) -> &String {
&MESSAGE.timestamp
}
pub async fn message(&self) -> &String {
&MESSAGE.message
}
pub async fn order(&self) -> i32 {
MESSAGE.order
}
pub async fn edited(&self) -> bool {
MESSAGE.edited
}
}
pub struct User;
#[Object]
impl User {
pub async fn id(&self) -> ID {
ID::from(&USER.id)
}
pub async fn profile(&self) -> Option<UserProfile> {
Some(UserProfile)
}
#[field(name = "is_operator")]
pub async fn is_operator(&self) -> bool {
USER.is_operator
}
pub async fn phone(&self) -> String {
USER.phone.to_string()
}
#[field(name = "join_date")]
pub async fn join_date(&self) -> &String {
&USER.join_date
}
pub async fn state(&self) -> &String {
&USER.state
}
}
pub struct UserProfile;
#[Object]
impl UserProfile {
pub async fn email(&self) -> &String {
&PROFILE.email
}
#[field(name = "first_name")]
pub async fn first_name(&self) -> &String {
&PROFILE.first_name
}
#[field(name = "last_name")]
pub async fn last_name(&self) -> &String {
&PROFILE.last_name
}
#[field(name = "job_title")]
pub async fn job_title(&self) -> &Option<String> {
&PROFILE.job_title
}
pub async fn city(&self) -> &Option<String> {
&PROFILE.city
}
}
pub struct Query;
#[Object]
impl Query {
async fn chats(&self) -> Vec<Chat> {
let mut res = vec![];
for _ in 0..30 {
res.push(Chat);
}
res
}
}
lazy_static::lazy_static! {
pub static ref S: Schema<Query, EmptyMutation, EmptySubscription> = Schema::new(Query, EmptyMutation, EmptySubscription);
}
pub const Q: &str = r#"
fragment User on User {
id
is_operator
phone
join_date
state
profile {
email
first_name
last_name
job_title
city
}
}
{
chats {
id
created_at
title
caption
state
creator {
...User
}
messages {
id
timestamp
edited
message
order
}
users {
...User
}
}
}
"#;

View File

@ -6,8 +6,4 @@ edition = "2018"
[dependencies]
async-graphql = { path = "../.." }
async-std = { version = "1.5.0", features = ["attributes"] }
futures = "0.3.4"
serde_json = "*"
lazy_static = "*"
async-graphql-parser = { path = "../../async-graphql-parser" }
lazy_static = "*"

View File

@ -1,7 +1,4 @@
use async_graphql::*;
use async_graphql_parser::{parse_query, query::Document};
use async_std::task;
pub use http::GQLResponse;
pub struct QueryRoot;
@ -38,6 +35,11 @@ impl MyObj {
}
}
lazy_static::lazy_static! {
pub static ref S: Schema<QueryRoot, EmptyMutation, EmptySubscription> = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
// static ref D: Document = parse_query(Q).unwrap();
}
pub const Q: &str = r#"{
valueI32 obj {
valueI32 valueList obj {
@ -71,28 +73,3 @@ pub const Q: &str = r#"{
}
}
}"#;
lazy_static::lazy_static! {
static ref S: Schema<QueryRoot, EmptyMutation, EmptySubscription> = Schema::new(QueryRoot, EmptyMutation, EmptySubscription);
// static ref D: Document = parse_query(Q).unwrap();
}
pub fn run(q: &str) -> Result<QueryResponse> {
task::block_on(async { S.execute(q).await })
}
pub fn parse(q: &str) -> Document {
parse_query(q).unwrap()
}
// pub fn validate() {
// check_rules(&S.env.registry, &D, S.validation_mode).unwrap();
// }
//
// pub fn resolve() {
// do_resolve(...).unwrap();
// }
pub fn serialize(r: &GQLResponse) -> String {
serde_json::to_string(&r).unwrap()
}

32
benchmark/src/lib.rs Normal file
View File

@ -0,0 +1,32 @@
pub use async_graphql::http::GQLResponse;
use async_graphql::{ObjectType, QueryResponse, Schema, SubscriptionType};
use async_graphql_parser::{parse_query, query::Document};
use async_std::task;
pub fn run<Query, Mutation, Subscription>(
s: &Schema<Query, Mutation, Subscription>,
q: &str,
) -> QueryResponse
where
Query: ObjectType + Send + Sync + 'static,
Mutation: ObjectType + Send + Sync + 'static,
Subscription: SubscriptionType + Send + Sync + 'static,
{
task::block_on(async { s.execute(q).await.unwrap() })
}
pub fn parse(q: &str) -> Document {
parse_query(q).unwrap()
}
// pub fn validate() {
// check_rules(&S.env.registry, &D, S.validation_mode).unwrap();
// }
//
// pub fn resolve() {
// do_resolve(...).unwrap();
// }
pub fn serialize(r: &GQLResponse) -> String {
serde_json::to_string(&r).unwrap()
}