Browse Source

[xitca-web]add io_uring bench. update wasmtime cli. (#7652)

* update wasmtime to stable release.

* add io-uring bench.

* add tracing log.

* limit tracing to error level.

* do not ignore uri path.

* fortunes showcase mixture of io-uring and epoll.
fakeshadow 2 years ago
parent
commit
542904f589

File diff suppressed because it is too large
+ 329 - 168
frameworks/Rust/xitca-web/Cargo.lock


+ 35 - 19
frameworks/Rust/xitca-web/Cargo.toml

@@ -6,12 +6,17 @@ edition = "2021"
 [[bin]]
 name = "xitca-web"
 path = "./src/main.rs"
-required-features = ["raw", "simd"]
+required-features = ["raw", "sailfish", "simd"]
 
 [[bin]]
 name = "xitca-web-diesel"
 path = "./src/main_diesel.rs"
-required-features = ["orm", "serde", "web"]
+required-features = ["orm", "sailfish", "serde", "web"]
+
+[[bin]]
+name = "xitca-web-iou"
+path = "./src/main_iou.rs"
+required-features = ["io-uring"]
 
 [[bin]]
 name = "xitca-web-wasm"
@@ -29,14 +34,21 @@ simd = ["simd-json", "simd-json-derive"]
 serde = ["dep:serde"]
 # web optional
 web = ["xitca-web"]
+# templating optional
+sailfish = ["dep:sailfish"]
+# io-uring optional
+io-uring = ["tokio-uring", "xitca-server/io-uring"]
 
 [dependencies]
 xitca-http = { version = "0.1", features = ["util-service"] }
+xitca-io = "0.1"
 xitca-server = "0.1"
 xitca-service = "0.1"
 xitca-unsafe-collection = "0.1"
 
-atoi = "1.0.0"
+atoi = "2"
+tracing = "0.1.37"
+tracing-subscriber = { version = "0.3.1", features = ["env-filter"] }
 
 # web optional
 xitca-web = { version = "0.1", features = ["json"], optional = true }
@@ -45,25 +57,30 @@ xitca-web = { version = "0.1", features = ["json"], optional = true }
 xitca-postgres = { version = "0.1", default-features = false, features = ["single-thread"], optional = true }
 
 # diesel-pg orm optional
-diesel = { version = "2.0.0-rc.0", default-features = false, features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"], optional = true }
-diesel-async = { version = "0.1.0", default-features = false, features = ["postgres"], optional = true }
+diesel = { version = "2.0.0", default-features = false, features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes"], optional = true }
+diesel-async = { version = "0.1.1", default-features = false, features = ["postgres"], optional = true }
 tang-rs = { version = "0.2", optional = true }
 
 # simd-json optional
 simd-json = { version = "0.6", default-features = false, features = ["swar-number-parsing", "hints"], optional = true }
-simd-json-derive = { version = "0.4", default-features = false, optional = true }
+simd-json-derive = { version = "0.6.3", default-features = false, optional = true }
 
 # serde optional
 serde = { version = "1", features = ["derive"], optional = true }
 
+# io-uring optional
+tokio-uring = { version = "0.3", features = ["bytes"], optional = true }
+
+# templating optional
+sailfish = { version = "0.5.0", optional = true }
+
 # stuff can not be used or not needed in wasi target
 [target.'cfg(not(target_family = "wasm"))'.dependencies]
 mimalloc = { version = "0.1.29", default-features = false }
 core_affinity = "0.5.10"
 futures-util = { version = "0.3.18", default-features = false, features = ["alloc"] }
-rand = { version = "0.8.5", default-features = false, features = ["min_const_gen", "nightly", "small_rng"] }
-sailfish = "0.4"
-tokio = "1.21"
+rand = { version = "0.8.5", default-features = false, features = ["min_const_gen", "nightly", "simd_support", "small_rng"] }
+tokio = "1.21.2"
 
 [profile.release]
 lto = true
@@ -72,13 +89,12 @@ codegen-units = 1
 panic = "abort"
 
 [patch.crates-io]
-xitca-http = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-xitca-io = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-xitca-server = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-xitca-service = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-xitca-unsafe-collection = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-xitca-web = { git = "https://github.com/HFQR/xitca-web.git", rev = "2994d3c56fb2027cbe4c39baf2ddcc56fc863655" }
-
-diesel = { git = "https://github.com/diesel-rs/diesel.git", rev = "53a4157776d4320fffc11fe73779cc53702843d6" }
-diesel-async = { git = "https://github.com/weiznich/diesel_async.git", rev = "3c9e976c1c30d3aa3d0751b89f72b2ce43869c4f" }
+xitca-http = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+xitca-io = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+xitca-server = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+xitca-service = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+xitca-unsafe-collection = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+xitca-web = { git = "https://github.com/HFQR/xitca-web.git", rev = "7a2b6c37011f41fe851ad73480320b2e753c5e7c" }
+
+tokio-uring = { git = "https://github.com/tokio-rs/tokio-uring.git", rev = "8725b81b862cc480be93b1a11c80b9990d51d890" }

+ 1 - 1
frameworks/Rust/xitca-web/README.md

@@ -2,7 +2,7 @@
 
 ## Description
 
-An alternative http library and web framework inspired by actix and hyper. Implementation is rewritten with similar style and types.
+An alternative http library and web framework inspired by hyper. Implementation is rewritten with similar style and types.
 
 ## Database
 

+ 18 - 0
frameworks/Rust/xitca-web/benchmark_config.json

@@ -46,6 +46,24 @@
         "notes": "",
         "versus": ""
       },
+      "iou": {
+        "plaintext_url": "/plaintext",
+        "fortune_url": "/fortunes",
+        "port": 8080,
+        "approach": "Realistic",
+        "classification": "Micro",
+        "database": "Postgres",
+        "framework": "xitca-web",
+        "language": "Rust",
+        "orm": "Raw",
+        "platform": "None",
+        "webserver": "xitca-server",
+        "os": "Linux",
+        "database_os": "Linux",
+        "display_name": "xitca-web [io-uring]",
+        "notes": "",
+        "versus": ""
+      },
       "wasm": {
         "plaintext_url": "/plaintext",
         "port": 8080,

+ 14 - 1
frameworks/Rust/xitca-web/config.toml

@@ -35,6 +35,19 @@ platform = "None"
 webserver = "xitca-server"
 versus = ""
 
+[iou]
+urls.plaintext = "/plaintext"
+urls.fortune = "/fortunes"
+approach = "Realistic"
+classification = "Platform"
+database = "Postgres"
+database_os = "Linux"
+os = "Linux"
+orm = "Raw"
+platform = "None"
+webserver = "xitca-server"
+versus = ""
+
 [wasm]
 urls.plaintext = "/plaintext"
 approach = "Realistic"
@@ -42,4 +55,4 @@ classification = "Micro"
 os = "wasi"
 platform = "wasm"
 webserver = "xitca-server"
-versus = ""
+versus = ""

+ 17 - 20
frameworks/Rust/xitca-web/src/db_diesel.rs

@@ -153,9 +153,9 @@ impl DieselPool {
     pub async fn update(&self, num: u16) -> DbResult<Vec<World>> {
         use crate::schema::world::dsl::*;
 
-        let worlds = {
-            let mut conn = self.pool.get().await?;
+        let mut conn = self.pool.get().await?;
 
+        let mut worlds = {
             let mut rng = self.rng.borrow_mut();
             (0..num)
                 .map(|_| {
@@ -171,28 +171,25 @@ impl DieselPool {
                     }
                 })
                 .collect::<FuturesUnordered<_>>()
-        };
-
-        let mut worlds = worlds.try_collect::<Vec<_>>().await?;
+        }
+        .try_collect::<Vec<_>>()
+        .await?;
 
         worlds.sort_by_key(|w| w.id);
 
-        self.pool
-            .get()
-            .await?
-            .transaction(move |conn| {
-                Box::pin(async move {
-                    for w in &worlds {
-                        diesel::update(world)
-                            .filter(id.eq(w.id))
-                            .set(randomnumber.eq(w.randomnumber))
-                            .execute(conn)
-                            .await?;
-                    }
-                    Ok(worlds)
-                })
+        conn.transaction(move |conn| {
+            Box::pin(async move {
+                for w in &worlds {
+                    diesel::update(world)
+                        .filter(id.eq(w.id))
+                        .set(randomnumber.eq(w.randomnumber))
+                        .execute(conn)
+                        .await?;
+                }
+                Ok(worlds)
             })
-            .await
+        })
+        .await
     }
 
     pub async fn tell_fortune(&self) -> DbResult<Fortunes> {

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

@@ -30,7 +30,7 @@ use xitca_http::{
     },
     HttpServiceBuilder,
 };
-use xitca_service::{fn_service, BuildServiceExt, Service};
+use xitca_service::{fn_service, Service, ServiceExt};
 
 use self::db::Client;
 use self::ser::Message;

+ 202 - 0
frameworks/Rust/xitca-web/src/main_iou.rs

@@ -0,0 +1,202 @@
+// used as reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for
+// network io.
+
+#![allow(dead_code)]
+#![feature(type_alias_impl_trait)]
+
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
+mod db;
+mod ser;
+mod util;
+
+use std::{
+    convert::Infallible,
+    fmt,
+    future::{poll_fn, Future},
+    io,
+};
+
+use futures_util::stream::Stream;
+use tracing::{span, Level};
+use xitca_http::http::const_header_value::TEXT_HTML_UTF8;
+use xitca_http::{
+    body::{BodySize, Once},
+    date::DateTimeService,
+    h1::proto::context::Context,
+    http::{
+        const_header_value::TEXT,
+        header::{CONTENT_TYPE, SERVER},
+        IntoResponse, Response, StatusCode,
+    },
+    util::{
+        middleware::Logger,
+        service::context::{Context as Ctx, ContextBuilder},
+    },
+    Request,
+};
+use xitca_io::{
+    bytes::{Buf, Bytes, BytesMut},
+    net::TcpStream,
+};
+use xitca_service::{fn_service, ready::ReadyService, Service, ServiceExt};
+use xitca_unsafe_collection::pin;
+
+use self::{
+    db::Client,
+    util::{DB_URL, SERVER_HEADER_VALUE},
+};
+
+fn main() -> io::Result<()> {
+    tracing_subscriber::fmt()
+        .with_env_filter("[xitca-iou]=trace")
+        .init();
+    xitca_server::Builder::new()
+        .bind("xitca-iou", "0.0.0.0:8080", || {
+            Http1IOU::new(ContextBuilder::new(|| db::create(DB_URL)).service(fn_service(handler)))
+                .enclosed(Logger::with_span(span!(Level::ERROR, "xitca-iou")))
+        })?
+        .build()
+        .wait()
+}
+
+async fn handler<B>(ctx: Ctx<'_, Request<B>, Client>) -> Result<Response<Once<Bytes>>, Infallible> {
+    let (req, cli) = ctx.into_parts();
+    let mut res = match req.uri().path() {
+        "/plaintext" => {
+            let mut res = req.into_response(Bytes::from_static(b"Hello, World!"));
+            res.headers_mut().insert(CONTENT_TYPE, TEXT);
+            res
+        }
+        "/fortunes" => {
+            use sailfish::TemplateOnce;
+            let fortunes = cli.tell_fortune().await.unwrap().render_once().unwrap();
+            let mut res = req.into_response(Bytes::from(fortunes));
+            res.headers_mut().append(CONTENT_TYPE, TEXT_HTML_UTF8);
+            res
+        }
+        _ => {
+            let mut res = req.into_response(Once::default());
+            *res.status_mut() = StatusCode::NOT_FOUND;
+            res
+        }
+    };
+    res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
+    Ok(res)
+}
+
+struct Http1IOU<S> {
+    service: S,
+}
+
+impl<S> Http1IOU<S> {
+    fn new(service: S) -> Self {
+        Self { service }
+    }
+}
+
+// builder for http service.
+impl<S> Service for Http1IOU<S>
+where
+    S: Service,
+{
+    type Response = Http1IOUService<S::Response>;
+    type Error = S::Error;
+    type Future<'f> = impl Future<Output = Result<Self::Response, Self::Error>> + 'f where Self: 'f, (): 'f ;
+
+    fn call<'s>(&'s self, _: ()) -> Self::Future<'s>
+    where
+        (): 's,
+    {
+        async {
+            let service = self.service.call(()).await?;
+            Ok(Http1IOUService {
+                service,
+                date: DateTimeService::new(),
+            })
+        }
+    }
+}
+
+struct Http1IOUService<S> {
+    service: S,
+    date: DateTimeService,
+}
+
+// delegate to inner service's ready state
+impl<S> ReadyService for Http1IOUService<S>
+where
+    S: ReadyService,
+{
+    type Ready = S::Ready;
+    type ReadyFuture<'f> = S::ReadyFuture<'f> where Self: 'f ;
+
+    fn ready(&self) -> Self::ReadyFuture<'_> {
+        self.service.ready()
+    }
+}
+
+// runner for http service.
+impl<S> Service<TcpStream> for Http1IOUService<S>
+where
+    S: Service<Request<()>, Response = Response<Once<Bytes>>>,
+    S::Error: fmt::Debug,
+{
+    type Response = ();
+    type Error = io::Error;
+    type Future<'f> = impl Future<Output = Result<Self::Response, Self::Error>> + 'f where Self: 'f, TcpStream: 'f ;
+
+    fn call<'s>(&'s self, stream: TcpStream) -> Self::Future<'s>
+    where
+        TcpStream: 's,
+    {
+        async {
+            let std = stream.into_std()?;
+            let stream = tokio_uring::net::TcpStream::from_std(std);
+
+            let mut read_buf = BytesMut::with_capacity(4096);
+            let mut write_buf = BytesMut::with_capacity(4096);
+
+            let mut ctx = Context::<_, 8>::new(self.date.get());
+
+            loop {
+                let (res, buf) = stream.read(read_buf).await;
+                let n = res?;
+
+                if n == 0 {
+                    break;
+                }
+
+                read_buf = buf;
+
+                while let Some((req, _)) = ctx.decode_head::<65535>(&mut read_buf).unwrap() {
+                    let (parts, body) = self.service.call(req).await.unwrap().into_parts();
+                    let size = BodySize::from_stream(&body);
+                    let mut encoder = ctx.encode_head(parts, size, &mut write_buf).unwrap();
+                    pin!(body);
+                    while let Some(chunk) = poll_fn(|cx| body.as_mut().poll_next(cx)).await {
+                        let chunk = chunk.unwrap();
+                        encoder.encode(chunk, &mut write_buf);
+                    }
+                    encoder.encode_eof(&mut write_buf);
+                }
+
+                if !write_buf.is_empty() {
+                    let (res, mut w) = stream.write(write_buf).await;
+                    let n = res?;
+                    if n == 0 {
+                        break;
+                    }
+
+                    w.advance(n);
+                    write_buf = w;
+                }
+
+                read_buf.reserve(4096 - read_buf.capacity());
+            }
+
+            Ok(())
+        }
+    }
+}

+ 2 - 2
frameworks/Rust/xitca-web/xitca-web-diesel.dockerfile

@@ -3,9 +3,9 @@ FROM rust:latest
 ADD ./ /xitca-web
 WORKDIR /xitca-web
 
-RUN rustup default nightly-2022-09-04
+RUN rustup default nightly-2022-10-27
 RUN cargo clean
-RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin xitca-web-diesel --features orm,serde,web
+RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin xitca-web-diesel --features orm,sailfish,serde,web
 
 EXPOSE 8080
 

+ 12 - 0
frameworks/Rust/xitca-web/xitca-web-iou.dockerfile

@@ -0,0 +1,12 @@
+FROM rust:latest
+
+ADD ./ /xitca-web
+WORKDIR /xitca-web
+
+RUN rustup default nightly-2022-10-27
+RUN cargo clean
+RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin xitca-web-iou --features io-uring,raw,sailfish,simd
+
+EXPOSE 8080
+
+CMD ./target/release/xitca-web-iou

+ 3 - 3
frameworks/Rust/xitca-web/xitca-web-wasm.dockerfile

@@ -3,14 +3,14 @@ FROM rust:latest
 ADD ./ /xitca-web
 WORKDIR /xitca-web
 
-RUN rustup default nightly-2022-09-04
+RUN rustup default nightly-2022-10-27
 RUN rustup target add wasm32-wasi
 RUN cargo clean
 RUN RUSTFLAGS="--cfg tokio_unstable" cargo build --release --bin xitca-web-wasm --target wasm32-wasi --features web
 
-RUN curl --show-error --location --fail https://github.com/bytecodealliance/wasmtime/releases/download/v0.40.1/wasmtime-v0.40.1-x86_64-linux.tar.xz --output wasmtime.tar.xz 
+RUN curl --show-error --location --fail https://github.com/bytecodealliance/wasmtime/releases/download/v2.0.0/wasmtime-v2.0.0-x86_64-linux.tar.xz --output wasmtime.tar.xz
 RUN tar -xvf wasmtime.tar.xz
 
 EXPOSE 8080
 
-CMD ./wasmtime-v0.40.1-x86_64-linux/wasmtime ./target/wasm32-wasi/release/xitca-web-wasm.wasm --tcplisten 0.0.0.0:8080 --env FD_COUNT=3
+CMD ./wasmtime-v2.0.0-x86_64-linux/wasmtime ./target/wasm32-wasi/release/xitca-web-wasm.wasm --tcplisten 0.0.0.0:8080 --env FD_COUNT=3

+ 2 - 2
frameworks/Rust/xitca-web/xitca-web.dockerfile

@@ -3,9 +3,9 @@ FROM rust:latest
 ADD ./ /xitca-web
 WORKDIR /xitca-web
 
-RUN rustup default nightly-2022-09-04
+RUN rustup default nightly-2022-10-27
 RUN cargo clean
-RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin xitca-web --features raw,simd
+RUN RUSTFLAGS="-C target-cpu=native" cargo build --release --bin xitca-web --features raw,sailfish,simd
 
 EXPOSE 8080
 

Some files were not shown because too many files changed in this diff