Browse Source

Add FaF (rust) framework (#6491)

* add faf framework

* add faf framework

* clean up code and slight reorg

* add HTTP methods and cleanup

* converted to a library format, updated docker to point to a tag, generally simplified

* simplified README.md
James Bates 4 years ago
parent
commit
5e1032e15b

+ 4 - 0
frameworks/Rust/faf/.gitignore

@@ -0,0 +1,4 @@
+/target
+/docs
+/.vscode
+/prof

+ 18 - 0
frameworks/Rust/faf/Cargo.toml

@@ -0,0 +1,18 @@
+[package]
+name = "faf-ex"
+version = "0.1.0"
+authors = ["James Bates <[email protected]>"]
+edition = "2018"
+
+[profile.release]
+opt-level = 3
+panic = 'unwind'
+codegen-units = 1
+lto = "thin"
+debug = false
+overflow-checks = false
+
+[dependencies]
+mimalloc = { version = "*", default-features = false }
+faf = { git = "https://github.com/errantmind/faf" }
+#faf = { path = "/home/errant/dev/projects/faf-epoll" }

+ 4 - 0
frameworks/Rust/faf/README.md

@@ -0,0 +1,4 @@
+# faf
+FaF is a Linux webserver written in Rust. It has a single goal: to demonstrate the upper bound of possible single-node performance. It is meant as a living reference project and may have cutting edge dependencies. Being a reference project, documentation and simplicity are essential and will be maintained to the best of my ability.
+
+[FaF Repo](https://github.com/errantmind/faf)

+ 25 - 0
frameworks/Rust/faf/benchmark_config.json

@@ -0,0 +1,25 @@
+{
+   "framework": "faf",
+   "tests": [
+      {
+         "default": {
+            "plaintext_url": "/plaintext",
+            "port": 8089,
+            "approach": "Realistic",
+            "classification": "Platform",
+            "database": "None",
+            "framework": "faf",
+            "language": "Rust",
+            "flavor": "None",
+            "orm": "None",
+            "platform": "None",
+            "webserver": "None",
+            "os": "Linux",
+            "database_os": "None",
+            "display_name": "faf",
+            "notes": "",
+            "versus": "None"
+         }
+      }
+   ]
+}

+ 15 - 0
frameworks/Rust/faf/config.toml

@@ -0,0 +1,15 @@
+[framework]
+name = "faf"
+
+[main]
+urls.plaintext = "/plaintext"
+# urls.json = "/j"
+approach = "Realistic"
+classification = "Platform"
+database = "None"
+database_os = "None"
+os = "Linux"
+orm = "None"
+platform = "None"
+webserver = "None"
+versus = "None"

+ 14 - 0
frameworks/Rust/faf/faf.dockerfile

@@ -0,0 +1,14 @@
+FROM errantmind/debian-faf:v2
+
+COPY ./Cargo.toml ./Cargo.toml
+COPY ./src ./src
+COPY ./merged.profdata ./merged.profdata
+ENV CC=/usr/bin/clang-12
+ENV CXX=/usr/bin/clang++-12
+RUN /root/.cargo/bin/cargo update
+RUN RUSTFLAGS="-Ctarget-cpu=native -Clinker=/usr/bin/clang-12 -Clink-arg=-fuse-ld=lld-12 -Clink-arg=-flto=thin \
+   -Clto=thin -Cembed-bitcode=yes -Copt-level=3 -Ccodegen-units=1 -Cforce-frame-pointers=n -Cprofile-use=/faf/merged.profdata" \
+   /root/.cargo/bin/cargo build --verbose --release && strip --strip-all target/release/faf-ex
+
+EXPOSE 8089
+CMD ./target/release/faf-ex

BIN
frameworks/Rust/faf/merged.profdata


+ 97 - 0
frameworks/Rust/faf/src/main.rs

@@ -0,0 +1,97 @@
+#[global_allocator]
+static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
+
+use faf::const_concat_bytes;
+use faf::const_config::*;
+use faf::const_http::*;
+use faf::extern_http_date;
+use faf::util::{const_len, memcmp};
+
+const ROUTE_PLAINTEXT: &[u8] = b"/p";
+const ROUTE_PLAINTEXT_LEN: usize = const_len(ROUTE_PLAINTEXT);
+const ROUTE_JSON: &[u8] = b"/j";
+const ROUTE_JSON_LEN: usize = const_len(ROUTE_JSON);
+
+const TEXT_PLAIN_CONTENT_TYPE: &[u8] = b"Content-Type: text/plain";
+const CONTENT_LENGTH: &[u8] = b"Content-Length: ";
+const PLAINTEXT_BODY: &[u8] = b"Hello, World!";
+const PLAINTEXT_BODY_LEN: usize = const_len(PLAINTEXT_BODY);
+const PLAINTEXT_BODY_SIZE: &[u8] = b"13";
+
+const PLAINTEXT_BASE: &[u8] = const_concat_bytes!(
+   HTTP_200_OK,
+   CRLF,
+   SERVER,
+   CRLF,
+   TEXT_PLAIN_CONTENT_TYPE,
+   CRLF,
+   CONTENT_LENGTH,
+   PLAINTEXT_BODY_SIZE,
+   CRLF
+);
+
+const PLAINTEXT_BASE_LEN: usize = const_len(PLAINTEXT_BASE);
+
+#[inline]
+fn cb(
+   method: *const i8,
+   method_len: usize,
+   path: *const i8,
+   path_len: usize,
+   _headers: &[faf::phr_header; MAX_HEADERS_TO_PARSE],
+   _num_headers: usize,
+   response_buffer: &mut [u8; REQ_RES_BUFF_SIZE],
+) -> usize {
+   if method_len < GET_LEN || path_len < ROUTE_PLAINTEXT_LEN {
+      return 0;
+   }
+   unsafe {
+      if memcmp(GET.as_ptr() as *const i8, method, GET_LEN) == 0 {
+         // For performance purposes, this will successfully match '/p' to '/plaintext' and '/pickle'. Use with caution
+         if memcmp(ROUTE_PLAINTEXT.as_ptr() as *const i8, path, ROUTE_PLAINTEXT_LEN) == 0 {
+            let mut date_buff = crate::extern_http_date::get_buff_with_date();
+            extern_http_date::get_http_date(&mut date_buff);
+            std::ptr::copy_nonoverlapping(PLAINTEXT_BASE.as_ptr(), response_buffer.as_mut_ptr(), PLAINTEXT_BASE_LEN);
+            std::ptr::copy_nonoverlapping(
+               date_buff.as_ptr(),
+               response_buffer.as_mut_ptr().add(PLAINTEXT_BASE_LEN),
+               DATE_LEN,
+            );
+            std::ptr::copy_nonoverlapping(
+               CRLFCRLF.as_ptr(),
+               response_buffer.as_mut_ptr().add(PLAINTEXT_BASE_LEN + DATE_LEN),
+               CRLFCRLF_LEN,
+            );
+            std::ptr::copy_nonoverlapping(
+               PLAINTEXT_BODY.as_ptr(),
+               response_buffer.as_mut_ptr().add(PLAINTEXT_BASE_LEN + DATE_LEN + CRLFCRLF_LEN),
+               PLAINTEXT_BODY_LEN,
+            );
+
+            return PLAINTEXT_BASE_LEN + DATE_LEN + CRLFCRLF_LEN + PLAINTEXT_BODY_LEN;
+         } else if memcmp(ROUTE_JSON.as_ptr() as *const i8, path, ROUTE_JSON_LEN) == 0 {
+         } else {
+            std::ptr::copy_nonoverlapping(
+               HTTP_404_NOTFOUND.as_ptr(),
+               response_buffer.as_mut_ptr(),
+               HTTP_404_NOTFOUND_LEN,
+            );
+            return HTTP_404_NOTFOUND_LEN;
+         }
+      } else {
+         std::ptr::copy_nonoverlapping(
+            HTTP_405_NOTALLOWED.as_ptr(),
+            response_buffer.as_mut_ptr(),
+            HTTP_405_NOTALLOWED_LEN,
+         );
+         return HTTP_405_NOTALLOWED_LEN;
+      }
+   };
+
+   0
+}
+
+#[inline]
+fn main() {
+   faf::epoll::go(8089, cb);
+}