Skip to content

Commit ea96185

Browse files
authored
[xitca-web] utilize simd-json for unrealistic benchmark (#9583)
* utilize simd-json for unrealistic benchmark * fix pg binding build * fix wasm build * explicit cast fd to tcp listener type * update to rust edition 2024 * feature flag fix
1 parent 756600e commit ea96185

18 files changed

+402
-203
lines changed

frameworks/Rust/xitca-web/Cargo.lock

Lines changed: 329 additions & 123 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frameworks/Rust/xitca-web/Cargo.toml

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "xitca-web"
33
version = "0.1.0"
4-
edition = "2021"
4+
edition = "2024"
55

66
[[bin]]
77
name = "xitca-web"
@@ -46,7 +46,7 @@ template = ["dep:sailfish"]
4646
# io-uring optional
4747
io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"]
4848
# unrealistic performance optimization
49-
perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot"]
49+
perf = ["dep:core_affinity", "dep:mimalloc", "tokio/parking_lot", "simd-json", "simd-json-derive"]
5050

5151
[dependencies]
5252
xitca-http = "0.7"
@@ -83,11 +83,13 @@ tokio-uring = { version = "0.5", optional = true }
8383
# perf optional
8484
core_affinity = { version = "0.8.1", optional = true }
8585
mimalloc = { version = "0.1", default-features = false, optional = true }
86+
simd-json = { version = "0.14", optional = true }
87+
simd-json-derive = { version = "0.15", default-features = false, optional = true }
8688

8789
# stuff can not be used or not needed in wasi target
8890
[target.'cfg(not(target_family = "wasm"))'.dependencies]
8991
futures-core = { version = "0.3", default-features = false }
90-
rand = { version = "0.8", features = ["small_rng"] }
92+
rand = { version = "0.9", features = ["os_rng", "small_rng"], default-features = false }
9193
tokio = "1.41"
9294

9395
[profile.release]
@@ -102,9 +104,9 @@ xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-di
102104
diesel-async = { git = "https://github.com/weiznich/diesel_async", rev = "5b8262b" }
103105
mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" }
104106

105-
xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "3b005af" }
106-
xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "3b005af" }
107-
xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "3b005af" }
108-
xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "3b005af" }
109-
xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "3b005af" }
110-
xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "3b005af" }
107+
xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "c2de532" }
108+
xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "c2de532" }
109+
xitca-postgres = { git = "http://github.com/HFQR/xitca-web", rev = "c2de532" }
110+
xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "c2de532" }
111+
xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "c2de532" }
112+
xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "c2de532" }

frameworks/Rust/xitca-web/src/db.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ mod db_util;
33

44
use core::cell::RefCell;
55

6-
use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement, Execute};
6+
use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement};
77

88
use super::{
99
ser::{Fortune, Fortunes, World},
10-
util::{HandleResult, DB_URL},
10+
util::{DB_URL, HandleResult},
1111
};
1212

13-
use db_util::{not_found, sort_update_params, update_query_from_num, Shared, FORTUNE_STMT, WORLD_STMT};
13+
use db_util::{FORTUNE_STMT, Shared, WORLD_STMT, not_found, sort_update_params, update_query_from_num};
1414

1515
pub struct Client {
1616
pool: Pool,

frameworks/Rust/xitca-web/src/db_diesel.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use diesel::{prelude::*, r2d2};
1010

1111
use crate::{
1212
ser::{Fortune, Fortunes, World},
13-
util::{HandleResult, Rand, DB_URL},
13+
util::{DB_URL, HandleResult, Rand},
1414
};
1515

1616
use db_util::{not_found, update_query_from_ids};

frameworks/Rust/xitca-web/src/db_diesel_async.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use std::{io, sync::Mutex};
55

66
use diesel::prelude::*;
77
use diesel_async::{
8-
pooled_connection::{bb8, AsyncDieselConnectionManager},
98
RunQueryDsl,
9+
pooled_connection::{AsyncDieselConnectionManager, bb8},
1010
};
1111
use futures_util::{
1212
future::join,
@@ -16,7 +16,7 @@ use xitca_postgres_diesel::AsyncPgConnection;
1616

1717
use crate::{
1818
ser::{Fortune, Fortunes, World},
19-
util::{HandleResult, Rand, DB_URL},
19+
util::{DB_URL, HandleResult, Rand},
2020
};
2121

2222
use db_util::{not_found, update_query_from_ids};

frameworks/Rust/xitca-web/src/db_unrealistic.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ mod db_util;
66

77
use std::cell::RefCell;
88

9-
use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement, Execute};
9+
use xitca_postgres::{Execute, iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement};
1010

1111
use super::{
1212
ser::{Fortune, Fortunes, World},
13-
util::{HandleResult, DB_URL},
13+
util::{DB_URL, HandleResult},
1414
};
1515

16-
use db_util::{not_found, sort_update_params, update_query_from_num, Shared, FORTUNE_STMT, WORLD_STMT};
16+
use db_util::{FORTUNE_STMT, Shared, WORLD_STMT, not_found, sort_update_params, update_query_from_num};
1717

1818
pub struct Client {
1919
cli: xitca_postgres::Client,
@@ -36,7 +36,7 @@ pub async fn create() -> HandleResult<Client> {
3636

3737
let mut updates = vec![Statement::default()];
3838

39-
for update in (1..=500).map(update_query_from_num).into_iter() {
39+
for update in (1..=500).map(update_query_from_num) {
4040
let stmt = Statement::named(&update, &[]).execute(&cli).await?.leak();
4141
updates.push(stmt);
4242
}
@@ -61,20 +61,18 @@ impl Client {
6161
pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
6262
let len = num as usize;
6363

64-
let mut res = Vec::with_capacity(len);
65-
66-
{
67-
let (ref mut rng, ..) = *self.shared.borrow_mut();
68-
for _ in 0..len {
69-
let stream = self.world.bind([rng.gen_id()]).query(&self.cli).await?;
70-
res.push(stream);
71-
}
64+
let mut res = {
65+
let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
66+
// unrealistic as all queries are sent with only one sync point.
67+
let mut pipe = Pipeline::unsync_with_capacity_from_buf(len, buf);
68+
(0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query(&mut pipe))?;
69+
pipe.query(&self.cli)?
7270
};
7371

7472
let mut worlds = Vec::with_capacity(len);
7573

76-
for mut stream in res {
77-
let row = stream.try_next().await?.ok_or_else(not_found)?;
74+
while let Some(mut item) = res.try_next().await? {
75+
let row = item.try_next().await?.ok_or_else(not_found)?;
7876
worlds.push(World::new(row.get(0), row.get(1)));
7977
}
8078

frameworks/Rust/xitca-web/src/main.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@ mod ser;
33
mod util;
44

55
use xitca_http::{
6+
HttpServiceBuilder,
67
h1::RequestBody,
7-
http::{header::SERVER, StatusCode},
8+
http::{StatusCode, header::SERVER},
89
util::{
910
middleware::context::{Context, ContextBuilder},
1011
service::{
1112
route::get,
1213
router::{Router, RouterError},
1314
},
1415
},
15-
HttpServiceBuilder,
1616
};
17-
use xitca_service::{fn_service, Service, ServiceExt};
17+
use xitca_service::{Service, ServiceExt, fn_service};
1818

1919
use db::Client;
20-
use ser::{error_response, IntoResponse, Message, Request, Response};
21-
use util::{HandleResult, QueryParse, State, SERVER_HEADER_VALUE};
20+
use ser::{IntoResponse, Message, Request, Response, error_response};
21+
use util::{HandleResult, QueryParse, SERVER_HEADER_VALUE, State};
2222

2323
type Ctx<'a> = Context<'a, Request<RequestBody>, State<Client>>;
2424

@@ -30,33 +30,27 @@ fn main() -> std::io::Result<()> {
3030
.insert("/fortunes", get(fn_service(fortunes)))
3131
.insert("/queries", get(fn_service(queries)))
3232
.insert("/updates", get(fn_service(updates)))
33-
.enclosed_fn(middleware)
3433
.enclosed(ContextBuilder::new(|| async { db::create().await.map(State::new) }))
34+
.enclosed_fn(async |service, req| {
35+
let mut res = service.call(req).await.unwrap_or_else(error_handler);
36+
res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
37+
Ok::<_, core::convert::Infallible>(res)
38+
})
3539
.enclosed(HttpServiceBuilder::h1().io_uring());
3640
xitca_server::Builder::new()
3741
.bind("xitca-web", "0.0.0.0:8080", service)?
3842
.build()
3943
.wait()
4044
}
4145

42-
async fn middleware<S>(service: &S, req: Ctx<'_>) -> Result<Response, core::convert::Infallible>
43-
where
44-
S: for<'c> Service<Ctx<'c>, Response = Response, Error = RouterError<util::Error>>,
45-
{
46-
let mut res = service.call(req).await.unwrap_or_else(error_handler);
47-
res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
48-
Ok(res)
49-
}
50-
5146
#[cold]
5247
#[inline(never)]
5348
fn error_handler(e: RouterError<util::Error>) -> Response {
54-
let status = match e {
49+
error_response(match e {
5550
RouterError::Match(_) => StatusCode::NOT_FOUND,
5651
RouterError::NotAllowed(_) => StatusCode::METHOD_NOT_ALLOWED,
5752
RouterError::Service(_) => StatusCode::INTERNAL_SERVER_ERROR,
58-
};
59-
error_response(status)
53+
})
6054
}
6155

6256
async fn plain_text(ctx: Ctx<'_>) -> HandleResult<Response> {

frameworks/Rust/xitca-web/src/main_orm.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,16 @@ mod schema;
33
mod ser;
44
mod util;
55

6-
use serde::Serialize;
76
use xitca_web::{
7+
App,
88
codegen::route,
99
handler::{html::Html, json::Json, query::Query, state::StateRef, text::Text},
10-
http::{header::SERVER, WebResponse},
10+
http::{WebResponse, header::SERVER},
1111
route::get,
12-
App,
1312
};
1413

1514
use db_diesel_async::Pool;
16-
use ser::Num;
15+
use ser::{Num, World};
1716
use util::{HandleResult, SERVER_HEADER_VALUE};
1817

1918
fn main() -> std::io::Result<()> {
@@ -39,7 +38,7 @@ fn header(mut res: WebResponse) -> WebResponse {
3938
}
4039

4140
#[route("/db", method = get)]
42-
async fn db(StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Json<impl Serialize>> {
41+
async fn db(StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Json<World>> {
4342
pool.get_world().await.map(Json)
4443
}
4544

@@ -51,17 +50,11 @@ async fn fortunes(StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Html<Strin
5150
}
5251

5352
#[route("/queries", method = get)]
54-
async fn queries(
55-
Query(Num(num)): Query<Num>,
56-
StateRef(pool): StateRef<'_, Pool>,
57-
) -> HandleResult<Json<impl Serialize>> {
53+
async fn queries(Query(Num(num)): Query<Num>, StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Json<Vec<World>>> {
5854
pool.get_worlds(num).await.map(Json)
5955
}
6056

6157
#[route("/updates", method = get)]
62-
async fn updates(
63-
Query(Num(num)): Query<Num>,
64-
StateRef(pool): StateRef<'_, Pool>,
65-
) -> HandleResult<Json<impl Serialize>> {
58+
async fn updates(Query(Num(num)): Query<Num>, StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Json<Vec<World>>> {
6659
pool.update(num).await.map(Json)
6760
}

frameworks/Rust/xitca-web/src/main_sync.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ mod util;
55

66
use serde::Serialize;
77
use xitca_web::{
8+
App,
89
codegen::route,
910
handler::{html::Html, json::Json, query::Query, state::StateOwn, text::Text},
10-
http::{header::SERVER, WebResponse},
11+
http::{WebResponse, header::SERVER},
1112
route::get,
12-
App,
1313
};
1414

1515
use db_diesel::Pool;

frameworks/Rust/xitca-web/src/main_unrealistic.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ use xitca_http::{
1818
http::StatusCode,
1919
};
2020
use xitca_service::Service;
21+
// simd-json crate is realistic approach to json serializer.
22+
// That said xitca-web by default utilize serde-json as serializer making it an unrealistic representation of framework performance
23+
use simd_json_derive::Serialize;
2124

2225
use self::{
2326
ser::Message,
@@ -106,7 +109,7 @@ async fn handler<'h>(req: Request<'h, State<db::Client>>, res: Response<'h>) ->
106109
.header("server", "X")
107110
// unrealistic content length header.
108111
.header("content-length", "27")
109-
.body_writer(|buf| serde_json::to_writer(BufMutWriter(buf), &Message::new()).unwrap()),
112+
.body_writer(|buf| Message::new().json_write(&mut BufMutWriter(buf)).unwrap()),
110113

111114
// all database related categories are unrealistic. please reference db_unrealistic module for detail.
112115
"/fortunes" => {
@@ -139,10 +142,10 @@ async fn handler<'h>(req: Request<'h, State<db::Client>>, res: Response<'h>) ->
139142

140143
fn json_response<'r, DB, T>(res: Response<'r>, state: &State<DB>, val: &T) -> Response<'r, 3>
141144
where
142-
T: serde::Serialize,
145+
T: Serialize,
143146
{
144147
let buf = &mut *state.write_buf.borrow_mut();
145-
serde_json::to_writer(BufMutWriter(buf), val).unwrap();
148+
val.json_write(&mut BufMutWriter(buf)).unwrap();
146149
let res = res
147150
.status(StatusCode::OK)
148151
.header("content-type", "application/json")

0 commit comments

Comments
 (0)