Browse Source

Axum perf improvements (#9379)

* perf: switch plaintext and json to one runtime per thread, improving performance.

* perf: remove need for additional vec

* perf: reduce length of query parameter

* perf: increase strength of inlining hint

* perf: reduce query length

* perf: shorten path and use references

* bug: increased length of route in line with requirements
Andrew James 9 months ago
parent
commit
992475cec3

+ 9 - 9
frameworks/Rust/axum/benchmark_config.json

@@ -28,7 +28,7 @@
         "docker_cmd": "/app/axum-sqlx",
         "docker_cmd": "/app/axum-sqlx",
         "db_url": "/db",
         "db_url": "/db",
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
-        "cached_query_url": "/cached-queries?queries=",
+        "cached_query_url": "/cached-queries?q=",
         "port": 8000,
         "port": 8000,
         "approach": "Realistic",
         "approach": "Realistic",
         "classification": "Fullstack",
         "classification": "Fullstack",
@@ -50,8 +50,8 @@
         "docker_cmd": "/app/axum-pg",
         "docker_cmd": "/app/axum-pg",
         "db_url": "/db",
         "db_url": "/db",
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
-        "query_url": "/queries?queries=",
-        "update_url": "/updates?queries=",
+        "query_url": "/queries?q=",
+        "update_url": "/updates?q=",
         "port": 8000,
         "port": 8000,
         "approach": "Realistic",
         "approach": "Realistic",
         "classification": "Fullstack",
         "classification": "Fullstack",
@@ -72,8 +72,8 @@
         "dockerfile": "axum.dockerfile",
         "dockerfile": "axum.dockerfile",
         "docker_cmd": "/app/axum-pg-pool",
         "docker_cmd": "/app/axum-pg-pool",
         "db_url": "/db",
         "db_url": "/db",
-        "query_url": "/queries?queries=",
-        "update_url": "/updates?queries=",
+        "query_url": "/queries?q=",
+        "update_url": "/updates?q=",
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
         "port": 8000,
         "port": 8000,
         "approach": "Realistic",
         "approach": "Realistic",
@@ -95,9 +95,9 @@
         "dockerfile": "axum.dockerfile",
         "dockerfile": "axum.dockerfile",
         "docker_cmd": "/app/axum-mongo",
         "docker_cmd": "/app/axum-mongo",
         "db_url": "/db",
         "db_url": "/db",
-        "query_url": "/queries?queries=",
+        "query_url": "/queries?q=",
         "fortune_url": "/fortunes",
         "fortune_url": "/fortunes",
-        "update_url": "/updates?queries=",
+        "update_url": "/updates?q=",
         "port": 8000,
         "port": 8000,
         "approach": "Realistic",
         "approach": "Realistic",
         "classification": "Fullstack",
         "classification": "Fullstack",
@@ -118,8 +118,8 @@
         "dockerfile": "axum.dockerfile",
         "dockerfile": "axum.dockerfile",
         "docker_cmd": "/app/axum-mongo-raw",
         "docker_cmd": "/app/axum-mongo-raw",
         "db_url": "/db",
         "db_url": "/db",
-        "query_url": "/queries?queries=",
-        "update_url": "/updates?queries=",
+        "query_url": "/queries?q=",
+        "update_url": "/updates?q=",
         "port": 8000,
         "port": 8000,
         "approach": "Realistic",
         "approach": "Realistic",
         "classification": "Fullstack",
         "classification": "Fullstack",

+ 2 - 2
frameworks/Rust/axum/src/common/mod.rs

@@ -36,14 +36,14 @@ where
 
 
 /// Generate a single integer in the range 1 to 10,000 (inclusive)
 /// Generate a single integer in the range 1 to 10,000 (inclusive)
 #[allow(dead_code)]
 #[allow(dead_code)]
-#[inline]
+#[inline(always)]
 pub fn random_id(rng: &mut SmallRng) -> i32 {
 pub fn random_id(rng: &mut SmallRng) -> i32 {
     rng.gen_range(1..10_001)
     rng.gen_range(1..10_001)
 }
 }
 
 
 /// Generate vector of integers in the range 1 to 10,000 (inclusive)
 /// Generate vector of integers in the range 1 to 10,000 (inclusive)
 #[allow(dead_code)]
 #[allow(dead_code)]
-#[inline]
+#[inline(always)]
 pub fn random_ids(rng: &mut SmallRng, count: usize) -> Vec<i32> {
 pub fn random_ids(rng: &mut SmallRng, count: usize) -> Vec<i32> {
     rng.sample_iter(Uniform::new(1, 10_001))
     rng.sample_iter(Uniform::new(1, 10_001))
         .take(count)
         .take(count)

+ 3 - 2
frameworks/Rust/axum/src/common/utils.rs

@@ -7,13 +7,14 @@ use serde::Deserialize;
 
 
 #[derive(Debug, Deserialize)]
 #[derive(Debug, Deserialize)]
 pub struct Params {
 pub struct Params {
-    queries: Option<String>,
+    q: Option<String>,
 }
 }
 
 
 #[allow(dead_code)]
 #[allow(dead_code)]
+#[inline(always)]
 pub fn parse_params(params: Params) -> usize {
 pub fn parse_params(params: Params) -> usize {
     params
     params
-        .queries
+        .q
         .and_then(|q| q.parse().ok())
         .and_then(|q| q.parse().ok())
         .unwrap_or(1)
         .unwrap_or(1)
         .clamp(1, 500)
         .clamp(1, 500)

+ 6 - 3
frameworks/Rust/axum/src/main.rs

@@ -26,13 +26,16 @@ pub async fn json() -> impl IntoResponse {
     (StatusCode::OK, Json(message))
     (StatusCode::OK, Json(message))
 }
 }
 
 
-#[tokio::main]
-async fn main() {
+fn main() {
     dotenv().ok();
     dotenv().ok();
+    server::start_tokio(serve_app)
+}
+
+async fn serve_app() {
 
 
     let app = Router::new()
     let app = Router::new()
         .route("/plaintext", get(plaintext))
         .route("/plaintext", get(plaintext))
         .route("/json", get(json));
         .route("/json", get(json));
 
 
     server::serve_hyper(app, Some(8000)).await
     server::serve_hyper(app, Some(8000)).await
-}
+}

+ 6 - 4
frameworks/Rust/axum/src/main_sqlx.rs

@@ -1,6 +1,8 @@
 mod common;
 mod common;
 mod sqlx;
 mod sqlx;
 
 
+use std::sync::Arc;
+
 use ::sqlx::PgPool;
 use ::sqlx::PgPool;
 use axum::{
 use axum::{
     extract::{Query, State},
     extract::{Query, State},
@@ -56,7 +58,7 @@ async fn queries(
     let ids = random_ids(&mut rng, count);
     let ids = random_ids(&mut rng, count);
     let mut worlds: Vec<World> = Vec::with_capacity(count);
     let mut worlds: Vec<World> = Vec::with_capacity(count);
 
 
-    for id in ids {
+    for id in &ids {
         let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID)
         let world: World = ::sqlx::query_as(common::SELECT_WORLD_BY_ID)
             .bind(id)
             .bind(id)
             .fetch_one(&mut *db.acquire().await.unwrap())
             .fetch_one(&mut *db.acquire().await.unwrap())
@@ -96,7 +98,7 @@ async fn cache(
 ) -> impl IntoResponse {
 ) -> impl IntoResponse {
     let count = parse_params(params);
     let count = parse_params(params);
     let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
     let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
-    let mut worlds: Vec<Option<World>> = Vec::with_capacity(count);
+    let mut worlds: Vec<Option<Arc<World>>> = Vec::with_capacity(count);
 
 
     for id in random_ids(&mut rng, count) {
     for id in random_ids(&mut rng, count) {
         worlds.push(cache.get(&id).await);
         worlds.push(cache.get(&id).await);
@@ -113,7 +115,7 @@ async fn preload_cache(AppState { db, cache }: &AppState) {
         .expect("error loading worlds");
         .expect("error loading worlds");
 
 
     for world in worlds {
     for world in worlds {
-        cache.insert(world.id, world).await;
+        cache.insert(world.id, Arc::new(world)).await;
     }
     }
 }
 }
 
 
@@ -121,7 +123,7 @@ async fn preload_cache(AppState { db, cache }: &AppState) {
 #[derive(Clone)]
 #[derive(Clone)]
 struct AppState {
 struct AppState {
     db: PgPool,
     db: PgPool,
-    cache: Cache<i32, World>,
+    cache: Cache<i32, Arc<World>>,
 }
 }
 
 
 #[tokio::main]
 #[tokio::main]

+ 7 - 10
frameworks/Rust/axum/src/pg/database.rs

@@ -90,21 +90,18 @@ impl PgConnection {
     }
     }
 
 
     pub async fn update_worlds(&self, num: usize) -> Result<Vec<World>, PgError> {
     pub async fn update_worlds(&self, num: usize) -> Result<Vec<World>, PgError> {
-        let worlds = self.fetch_random_worlds(num).await?;
+        let mut worlds = self.fetch_random_worlds(num).await?;
 
 
         // Update the worlds with new random numbers
         // Update the worlds with new random numbers
         let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
         let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
         let mut ids = Vec::with_capacity(num);
         let mut ids = Vec::with_capacity(num);
         let mut nids = Vec::with_capacity(num);
         let mut nids = Vec::with_capacity(num);
-        let worlds: Vec<World> = worlds
-            .into_iter()
-            .map(|mut w| {
-                w.randomnumber = random_id(&mut rng);
-                ids.push(w.id);
-                nids.push(w.randomnumber);
-                w
-            })
-            .collect();
+
+        for w in &mut worlds {
+            w.randomnumber = random_id(&mut rng);
+            ids.push(w.id);
+            nids.push(w.randomnumber);
+        }
 
 
         // Update the random worlds in the database.
         // Update the random worlds in the database.
         self.client
         self.client