Compare commits

...

24 Commits

Author SHA1 Message Date
emil 01acb468de feat: added logging instrumentation for tenant preprocessing param
1 year ago
Emil Abbasov 693e633164 Removed all the PNMs from the testbenchs
1 year ago
Emil Abbasov 0f758a7602 fix: Update multi-tenancy-tests for GOCR to accept PNGs
1 year ago
Emil Abbasov 7a534581c5 fix: Update gocr tests to send PNGs instead of PNMs
1 year ago
Emil Abbasov 8f1ea67df9 feat: GOCR now suports PNG input (no conversion, no pnm at all)
1 year ago
Emil 6b0ba99e86
feature: added SJF scheduler and Regression based prediction (#385)
1 year ago
Emil 4ae8b02413
Enhanced Bash scripts (#384)
1 year ago
Emil de22264f4d
Merge pull request #383 from gwsystems/mt-dbf
2 years ago
Emil Abbasov bfc842924e feat: added new test for cnn_face_detection app
2 years ago
Emil Abbasov 9f465e01fe Merge branch 'mt-dbf' of https://github.com/gwsystems/sledge-serverless-framework into mt-dbf
2 years ago
Emil Abbasov 22860ba0d1 Merge pull request #380 from gwsystems/mt-dbf
2 years ago
Emil 4e1f67929e
Merge pull request #381 from mzpqnxow/portable-uname-arch
2 years ago
AG 23639915c4
Update install_deb.sh
2 years ago
Emil b85e13fb5f
Merge pull request #380 from gwsystems/mt-dbf
2 years ago
Emil Abbasov ba8818e4f8 added multi-tenancy testbed
2 years ago
Emil Abbasov 90f9987c82 Fix: temporary fix (by Xiaosu) that introduces locks that prevent scalability
2 years ago
emil 8d1ba3d9b0 cleanup
2 years ago
Emil 5e2558048a
Fix: Change the TLS-model for the libsledge to init-exec (#370)
3 years ago
emil 562e5d8623 Fix: Change the TLS-model for the libsledge to init-exec
3 years ago
emil bc2c52165a update cmu-sod tests
3 years ago
Emil dac95d08f4
Remove wasm_apps submodule from Sledge repo (#368)
3 years ago
emil be911e206c updated README to reflect latest changes
3 years ago
lyuxiaosu 6d7d815ee7
remove sending duplicate http response header (#367)
3 years ago
Emil a2188b8bae
Retrieve more accurate CPU frequency for runtime (#366)
3 years ago

@ -1,4 +1,3 @@
---
BasedOnStyle: Mozilla
IndentWidth: 8
Language: Cpp
@ -10,10 +9,10 @@ AlignConsecutiveMacros: true
AlignEscapedNewlines: Left
AlignTrailingComments: true
AllowShortBlocksOnASingleLine: true
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: AllDefinitions
@ -38,7 +37,7 @@ BreakBeforeBinaryOperators: NonAssignment
ColumnLimit: 120
Cpp11BracedListStyle: false
Cpp11BracedListStyle: true
IndentCaseLabels: false
IndentWrappedFunctionNames: false
@ -47,10 +46,9 @@ KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 2
DerivePointerAlignment: false
PointerAlignment: Right
SortIncludes: false
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true

@ -4,7 +4,7 @@ on: [push, pull_request]
env:
LLVM_VERSION: 13
WASI_SDK_URL: https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
WASI_SDK_VERSION: 12
WASI_SDK_PATH: /opt/wasi-sdk
LANG: C.UTF-8
LANGUAGE: C.UTF-8
@ -13,18 +13,18 @@ env:
# job control
jobs:
format:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- name: Apt Update
run: sudo apt-get update
- uses: actions/checkout@v2
- name: Install LLVM
- name: Install Clang Format
run: |
sudo ./install_llvm.sh $LLVM_VERSION
- name: Clang Format
- name: Run Clang Format
run: ./format.sh -d
test:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- name: Apt Update
run: sudo apt-get update
@ -62,6 +62,7 @@ jobs:
echo "/root/.cargo/bin:$PATH" >> $GITHUB_PATH
- name: Get wasi-sdk
run: |
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_SDK_VERSION/wasi-sdk-$WASI_SDK_VERSION.0-linux.tar.gz
wget $WASI_SDK_URL -O wasi-sdk.tar.gz
mkdir -p $WASI_SDK_PATH
tar xvfz wasi-sdk.tar.gz --strip-components=1 -C $WASI_SDK_PATH
@ -94,6 +95,9 @@ jobs:
- name: Compile SLEdge
run: |
make runtime
- name: Install wasm_apps link
run: |
make wasm_apps
# TODO:Cache assets before being copied to ./runtime/bin
- name: Cache gocr
uses: actions/cache@v2

1
.gitignore vendored

@ -52,6 +52,7 @@ dkms.conf
runtime/tags
runtime/bin
applications/wasm_apps
applications/tmp/
applications/**/*.csv
applications/**/*.txt

4
.gitmodules vendored

@ -12,7 +12,3 @@
[submodule "jsmn"]
path = runtime/thirdparty/jsmn
url = https://github.com/gwsystems/jsmn.git
[submodule "wasm_apps"]
path = applications/wasm_apps
url = https://github.com/gwsystems/wasm_apps.git
branch = master

@ -1,24 +1,23 @@
{
"configurations": [
{
"name": "Linux",
"intelliSenseMode": "clang-x64",
"includePath": [
"/usr/include/",
"${workspaceFolder}/runtime/include/",
"${workspaceFolder}/runtime/thirdparty/ck/include/",
"${workspaceFolder}/runtime/thirdparty/http-parser/",
"${workspaceFolder}/runtime/thirdparty/jsmn/",
"${workspaceFolder}/awsm/runtime/libc/wasi/include/",
"${workspaceFolder}/libsledge/include"
],
"defines": [
"x86_64",
"_GNU_SOURCE"
],
"cStandard": "c17",
"compilerPath": "/usr/bin/clang"
}
],
"version": 4
}
"configurations": [
{
"name": "Linux",
"intelliSenseMode": "clang-x64",
"includePath": [
"/usr/include/",
"${workspaceFolder}/runtime/include/",
"${workspaceFolder}/runtime/thirdparty/ck/include/",
"${workspaceFolder}/runtime/thirdparty/http-parser/",
"${workspaceFolder}/runtime/thirdparty/jsmn/",
"${workspaceFolder}/awsm/runtime/libc/wasi/include/",
"${workspaceFolder}/libsledge/include"
],
"defines": [
"x86_64",
"_GNU_SOURCE"
],
"cStandard": "c17"
}
],
"version": 4
}

@ -116,7 +116,7 @@
"tenant.h": "c",
"route_config.h": "c",
"http_router.h": "c",
"admissions_info.h": "c",
"execution_histogram.h": "c",
"tcp_server.h": "c",
"stdint.h": "c",
"scheduler_options.h": "c",
@ -126,8 +126,38 @@
"local_cleanup_queue.h": "c",
"sandbox_state_transition.h": "c",
"http_session_perf_log.h": "c",
"traffic_control.h": "c",
"memory_resource": "c",
"memory": "c",
"istream": "c",
"ostream": "c",
"sstream": "c",
"streambuf": "c",
"sandbox_perf_log.h": "c",
"global_request_scheduler_deque.h": "c",
"message.h": "c",
"dbf.h": "c",
"dbf_generic.h": "c",
"tenant_functions.h": "c",
"thread": "c",
"limits": "c",
"algorithm": "c",
"stdio.h": "c",
"get_time.h": "c",
"unistd.h": "c",
"wasi.h": "c",
"stat.h": "c",
"functional": "c",
"sandbox_state.h": "c",
"ratio": "c",
"tuple": "c",
"type_traits": "c",
"perf_window.h": "c",
"global_request_scheduler_deque.h": "c"
"http_route_total.h": "c",
"sledge_abi_symbols.h": "c",
"mutex": "c",
"lock.h": "c",
"route_latency.h": "c"
},
"files.exclude": {
"**/.git": true,
@ -189,5 +219,6 @@
"TKILL",
"WASI"
],
"C_Cpp.errorSquiggles": "Enabled"
"C_Cpp.errorSquiggles": "Enabled",
"C_Cpp.default.compilerPath": "/usr/bin/clang"
}

@ -1,9 +1,12 @@
# using ubuntu 20 docker image
FROM ubuntu:focal
ENV LLVM_VERSION=13
ENV WASI_SDK_VERSION=12
ARG DEBIAN_FRONTEND=noninteractive
ARG HEY_URL=https://hey-release.s3.us-east-2.amazonaws.com/hey_linux_amd64
ARG WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb
ARG WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_SDK_VERSION/wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb
ARG SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.2.4/shfmt_v3.2.4_linux_amd64
ARG SHELLCHECK_URL=https://github.com/koalaman/shellcheck/releases/download/stable/shellcheck-stable.linux.x86_64.tar.xz
@ -74,12 +77,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
vim \
wabt
ENV LLVM_VERSION=12
ADD install_llvm.sh /sledge/install_llvm.sh
RUN ./sledge/install_llvm.sh $LLVM_VERSION
# WASI-SDK
RUN curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb
RUN curl -sS -L -O $WASI_SDK_URL && dpkg -i wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb && rm -f wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb
ENV WASI_SDK_PATH=/opt/wasi-sdk
# Create non-root user and add to sudoers

@ -11,7 +11,7 @@ submodules:
git submodule update --init --recursive
.PHONY: install
install: submodules all
install: submodules wasm_apps all
# aWsm: the WebAssembly to LLVM bitcode compiler
.PHONY: awsm
@ -50,6 +50,10 @@ applications:
applications.clean:
make -C applications clean
# Instead of having two copies of wasm_apps, just link to the awsm repo's copy
wasm_apps:
ln -sr awsm/applications/wasm_apps/ applications/
# Tests
.PHONY: test
test:

@ -80,24 +80,34 @@ And then simply delete this repository.
An SLEdge serverless function consists of a shared library (\*.so) and a JSON configuration file that determines how the runtime should execute the serverless function. As an example, here is the configuration file for our sample fibonacci function:
```json
{
"name": "fibonacci",
"path": "fibonacci.wasm.so",
"port": 10000,
"expected-execution-us": 600,
"relative-deadline-us": 2000,
"http-resp-content-type": "text/plain"
}
[
{
"name": "GWU",
"port": 10010,
"routes": [
{
"route": "/fib",
"path": "fibonacci.wasm.so",
"expected-execution-us": 6000,
"relative-deadline-us": 20000,
"http-resp-content-type": "text/plain"
}
]
}
]
```
The `port` and `name` fields are used to determine the path where our serverless function will be served served.
The `port` and `route` fields are used to determine the path where our serverless function will be served served.
In our case, we are running the SLEdge runtime on localhost, so our function is available at `http://localhost:10000/fibonacci`
In our case, we are running the SLEdge runtime on localhost, so our function is available at `localhost:10010/fib`.
Our fibonacci function will parse a single argument from the HTTP POST body that we send. The expected Content-Type is "text/plain" and the buffer is sized to 1024 bytes for both the request and response. This is sufficient for our simple Fibonacci function, but this must be changed and sized for other functions, such as image processing.
Our fibonacci function will parse a single argument from the HTTP POST body that we send. The expected Content-Type is "text/plain".
Now that we understand roughly how the SLEdge runtime interacts with serverless function, let's run Fibonacci!
The fastest way to check it out is just to click on the following URL on your Web browser: [http://localhost:10010/fib?10](http://localhost:10010/fib?10)
From the root project directory of the host environment (not the Docker container!), navigate to the binary directory
```bash
@ -107,25 +117,33 @@ cd runtime/bin/
Now run the sledgert binary, passing the JSON file of the serverless function we want to serve. Because serverless functions are loaded by SLEdge as shared libraries, we want to add the `applications/` directory to LD_LIBRARY_PATH.
```bash
LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../tests/test_fibonacci.json
LD_LIBRARY_PATH="$(pwd):$LD_LIBRARY_PATH" ./sledgert ../../tests/fibonacci/bimodal/spec.json
```
While you don't see any output to the console, the runtime is running in the foreground.
Let's now invoke our serverless function to compute the 10th fibonacci number. I'll use [HTTPie](https://httpie.org/) to send a POST request with a body containing the parameter I want to pass to my serverless function. Feel free to use cURL or whatever network client you prefer!
Let's now invoke our serverless function to compute the 10th fibonacci number. We'll use `cURL` and [HTTPie](https://httpie.org/) to send a HTTP GET and POST requests with the parameter we want to pass to my serverless function. Feel free to use whatever other network client you prefer!
Open a new terminal session and execute the following
Open a **new** terminal session and execute the following
```bash
echo "10" | http :10000
# HTTP GET method:
http localhost:10010/fib?10
curl localhost:10010/fib?10
# HTTP POST method:
echo "10" | http POST localhost:10010/fib
curl -i -d 10 localhost:10010/fib
```
You should receive the following in response. The serverless function says that the 10th fibonacci number is 55, which seems to be correct!
```bash
HTTP/1.1 200 OK
Content-length: 3
Content-type: text/plain
Server: SLEdge
Connection: close
Content-Type: text/plain
Content-Length: 3
55
```

@ -26,15 +26,12 @@ all: \
gps_ekf.install \
license_plate_detection.install \
resize_image.install \
scratch_storage_get.install \
scratch_storage_set.install \
scratch_storage_delete.install \
scratch_storage_upsert.install \
cnn_face_detection.install \
get_jpeg_resolution.install \
.PHONY: clean
clean:
@make -C wasm_apps clean
@make -C scratch_storage clean
@rm -rf dist
@rm -rf ../runtime/bin/*.so
@ -68,7 +65,7 @@ dist/%.bc: ./wasm_apps/dist/%.wasm dist
${AWSMCC} ${AWSMFLAGS} $< -o $@
dist/%.ll: dist/%.bc
llvm-dis-12 $< -o $@
llvm-dis $< -o $@
dist/%.wasm.so: dist/%.bc
${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@
@ -105,6 +102,12 @@ gps_ekf.install: ../runtime/bin/gps_ekf.wasm.so
.PHONY: license_plate_detection.install
license_plate_detection.install: ../runtime/bin/license_plate_detection.wasm.so
.PHONY: cnn_face_detection.install
cnn_face_detection.install: ../runtime/bin/cnn_face_detection.wasm.so
.PHONY: get_jpeg_resolution.install
get_jpeg_resolution.install: ../runtime/bin/get_jpeg_resolution.wasm.so
.PHONY: trap_divzero.install
trap_divzero.install: ../runtime/bin/trap_divzero.wasm.so

@ -1 +0,0 @@
Subproject commit 3f5bc009f71c9561bfb4f3b08b47aa53983ef0f9

@ -1 +1 @@
Subproject commit 69c8b6116664d65a851cc459601bef6af3caeaea
Subproject commit 272fcf42b6559ccb5c5213eb78edfc0f703520ab

@ -1,7 +1,9 @@
#!/bin/bash
LLVM_VERSION=13
validate() {
utility="clang-format-13"
utility="clang-format"
utility_version="$("$utility" --version 2> /dev/null)" || {
echo "$utility not found in path!"
exit 1
@ -11,7 +13,7 @@ validate() {
declare -i major=0
declare -i minor=0
declare -i patch=0
declare -i required_major=13
declare -i required_major=$LLVM_VERSION
declare -i required_minor=0
declare -i required_patch=0
@ -43,14 +45,14 @@ help() {
dry_run() {
find runtime \
\( -path "runtime/thirdparty" -o -path "applications/gocr" -o -path "applications/TinyEKF" -o -path "applications/CMSIS_5_NN" -o -path "applications/sod" -o -path "applications/**/thirdparty" \) -prune -false -o \
-type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print \
| xargs clang-format -Werror -n -ferror-limit=0
\( -path "runtime/thirdparty" \) -prune -false -o \
-type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print0 \
| xargs --null clang-format -Werror -n -ferror-limit=1
}
format() {
find runtime \
\( -path "runtime/thirdparty" -o -path "applications/gocr" -o -path "applications/TinyEKF" -o -path "applications/CMSIS_5_NN" -o -path "applications/sod" -o -path "applications/**/thirdparty" \) -prune -false -o \
\( -path "runtime/thirdparty" \) -prune -false -o \
-type f \( -iname \*.h -o -iname \*.c -o -iname \*.s \) -print0 \
| xargs --null clang-format -i
}

@ -1,12 +1,14 @@
#!/bin/bash
LLVM_VERSION=12
# Note, wasi-sdk versions do NOT match llvm versions, e.g. wasi-sdk-12 actually uses llvm-11
LLVM_VERSION=13
WASI_SDK_VERSION=12
ARCH=$(uname -p)
ARCH=$(uname -m)
if [[ $ARCH = "x86_64" ]]; then
SHFMT_URL=https://github.com/mvdan/sh/releases/download/v3.4.3/shfmt_v3.4.3_linux_amd64
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk_12.0_amd64.deb
WASI_SDK_URL=https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-$WASI_SDK_VERSION/wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb
elif [[ $ARCH = "aarch64" ]]; then
SHFMT_URL=https://github.com/patrickvane/shfmt/releases/download/master/shfmt_linux_arm
echo "ARM64 support is still a work in progress!"
@ -64,7 +66,7 @@ wget $SHFMT_URL -O shfmt && chmod +x shfmt && sudo mv shfmt /usr/local/bin/shfmt
sudo ./install_llvm.sh $LLVM_VERSION
curl -sS -L -O $WASI_SDK_URL && sudo dpkg -i wasi-sdk_12.0_amd64.deb && rm -f wasi-sdk_12.0_amd64.deb
curl -sS -L -O $WASI_SDK_URL && sudo dpkg -i wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb && rm -f wasi-sdk_$WASI_SDK_VERSION.0_amd64.deb
if [ -z "${WASI_SDK_PATH}" ]; then
export WASI_SDK_PATH=/opt/wasi-sdk

@ -8,28 +8,28 @@ echo "Installing LLVM $LLVM_VERSION"
# Script Installs clang, lldb, lld, and clangd
curl --proto '=https' --tlsv1.2 -sSf https://apt.llvm.org/llvm.sh | bash -s -- "$LLVM_VERSION"
# Installing "libc++-xx-dev" automagically installs "libc++1-xx", "libunwind-xx" and "libunwind-xx-dev"
apt-get install -y --no-install-recommends \
"libc++-$LLVM_VERSION-dev" \
"libc++abi-$LLVM_VERSION-dev" \
"libc++1-$LLVM_VERSION" \
"libunwind-$LLVM_VERSION" \
"libunwind-$LLVM_VERSION-dev" \
"clang-tools-$LLVM_VERSION" \
"clang-tidy-$LLVM_VERSION" \
"clang-format-$LLVM_VERSION"
sudo update-alternatives --remove-all clang-format
sudo update-alternatives --remove-all clang
sudo update-alternatives --remove-all clang++
sudo update-alternatives --remove-all llvm-config
sudo update-alternatives --remove-all llvm-objdump
sudo update-alternatives --remove-all llvm-objdump
sudo update-alternatives --remove-all clang-tidy
update-alternatives --remove-all wasm-ld
update-alternatives --remove-all llvm-config
update-alternatives --remove-all llvm-objdump
update-alternatives --remove-all llvm-dis
update-alternatives --remove-all clang-format
update-alternatives --remove-all clang
update-alternatives --remove-all clang++
update-alternatives --remove-all clang-tidy
update-alternatives --install /usr/bin/wasm-ld wasm-ld "/usr/bin/wasm-ld-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/llvm-config llvm-config "/usr/bin/llvm-config-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/llvm-objdump llvm-objdump "/usr/bin/llvm-objdump-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/llvm-dis llvm-dis /usr/bin/llvm-dis-$LLVM_VERSION 100
update-alternatives --install /usr/bin/clang-format clang-format "/usr/bin/clang-format-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/clang clang "/usr/bin/clang-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/clang++ clang++ "/usr/bin/clang++-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/llvm-config llvm-config "/usr/bin/llvm-config-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/llvm-objdump llvm-objdump "/usr/bin/llvm-objdump-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/clang-tidy clang-tidy "/usr/bin/clang-tidy-$LLVM_VERSION" 100
update-alternatives --install /usr/bin/wasm-ld wasm-ld "/usr/bin/wasm-ld-$LLVM_VERSION" 100

@ -1,7 +1,8 @@
CFILES := src/*.c
INCLUDES := -Iinclude/
CFLAGS := -fPIC -O3 -flto
# fPIC = Position Independent Code, necessary for linking to relative addresses.
CFLAGS := -fPIC -O3 -flto -ftls-model=initial-exec
# Strips out calls to assert() and disables debuglog
CFLAGS+=-DNDEBUG

@ -15,7 +15,7 @@ libsledge defines a ABI between the sledgert runtime and a \*.so shared library
A SLEdge \*.so serverless module is generated by the latter portion of the aWsm/SLEdge toolchain.
The first portion of the toolchain is responsible for compiling a source program into a WebAssembly module. This is handled by standard compilers capable of emitting WebAssembly.
The second portion of the toolchain is the aWsm compiler, which generates a \*.bc file with a well defined ABI
The second portion of the toolchain is the aWsm compiler, which generates a \*.bc file with a well defined ABI.
The third portion of the toolchain is the LLVM compiler, which ingests a \*.bc file emitted by aWsm and the libsledge static library, and emits a SLEdge \*.so serverless module.
## Architecture
@ -24,16 +24,12 @@ In order to reduce the overhead of calling sledgert functions, libsledge operate
The `sledge_abi__wasm_module_instance` structure includes the WebAssembly function table and the WebAssembly linear memory. This subset was selected because the author believes that use of function pointers and linear memory is frequent enough that LTO when compiling the \*.so file is beneficial.
All WebAssembly state
## WebAssembly Instruction Implementation
Here is a list of WebAssembly instructions that depend on symbols from libsledge, libc, or sledgert (via the SLEdge ABI).
### [Control Instructions](https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions)
The ABI includes the
| Instruction | aWsm ABI | libc Dependencies | SLEdge ABI |
| ------------- | ------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| call_indirect | `get_function_from_table` | `stderr`, `fprintf` | `sledge_abi__current_wasm_module_instance.table`, `sledge_abi__wasm_trap_raise`, `WASM_TRAP_INVALID_INDEX`, `WASM_TRAP_MISMATCHED_TYPE` |
@ -115,13 +111,6 @@ The ABI includes the
| memory.size | `instruction_memory_size` | | `sledge_abi__current_wasm_module_instance.memory` |
| None | `initialize_region` | | `sledge_abi__current_wasm_module_instance.memory`, `sledge_abi__wasm_memory_initialize_region` |
Discussion:
- Should `instruction_memory_grow` be moved into sledgert? This would simplify the handling of the "cache" and generating a memory profile?
- Rename `sledge_abi__wasm_globals_*` to `sledge_abi__wasm_global_*`
- Implement Unsupported Numeric Instructions
- Should the wasm global table be accessed directly instead of via a runtime function?
- Should the Function Table be handled by the \*.so file or sledgert? Are function pointers really called that frequently?
# SLEdge \*.so Module Loading / Initialization
@ -136,27 +125,32 @@ The `sledgert` runtime is invoked with an argument containing the path to a JSON
The path to the JSON file is passed to `module_alloc_from_json`, which uses the Jasmine library to parse the JSON, performs validation, and passes the resulting specification to `module_alloc` for each module definition found. `module_alloc` allocated heap memory for a `struct module` and then calls `module_init`. `module_init` calls `sledge_abi_symbols_init`, which calls `dlopen` on the _.so file at the path specified in the JSON and then calls `dlsym` to resolve symbols within the _.so module.
`module.abi.initialize_globals` -> `SLEDGE_ABI__INITIALIZE_GLOBALS` -> `populate_globals`
`module.abi.initialize_memory`-> `SLEDGE_ABI__INITIALIZE_MEMORY` -> `populate_memory`
`module.abi.initialize_table` -> `SLEDGE_ABI__INITIALIZE_TABLE` -> `populate_table`
`module.abi.entrypoint` -> `SLEDGE_ABI__ENTRYPOINT` -> `wasmf__start`
`module.abi.starting_pages` -> `SLEDGE_ABI__STARTING_PAGES` -> `starting_pages`
`module.abi.max_pages` -> `SLEDGE_ABI__MAX_PAGES` -> `max_pages`
`module.abi.globals_len` -> `SLEDGE_ABI__GLOBALS_LEN` -> `globals_len`
- `module.abi.initialize_globals` -> `SLEDGE_ABI__INITIALIZE_GLOBALS` -> `populate_globals`
- `module.abi.initialize_memory`-> `SLEDGE_ABI__INITIALIZE_MEMORY` -> `populate_memory`
- `module.abi.initialize_table` -> `SLEDGE_ABI__INITIALIZE_TABLE` -> `populate_table`
- `module.abi.entrypoint` -> `SLEDGE_ABI__ENTRYPOINT` -> `wasmf__start`
- `module.abi.starting_pages` -> `SLEDGE_ABI__STARTING_PAGES` -> `starting_pages`
- `module.abi.max_pages` -> `SLEDGE_ABI__MAX_PAGES` -> `max_pages`
- `module.abi.globals_len` -> `SLEDGE_ABI__GLOBALS_LEN` -> `globals_len`
`module init` then calls `module.abi.initialize_table`, which populates the indirect function table with the actual functions. This is performed once during module initialization because this table does not actually vary between instances of a module.
`module_init` then calls `module.abi.initialize_table`, which populates the indirect function table with the actual functions. This is performed once during module initialization because this table does not actually vary between instances of a module.
# SLEdge \*.so Module Instantiation
When `sledgert` receives a request at the registered port specified in the JSON, it performs assorted allocation and initialization steps. The scheduler sets the expected ABI symbols and yields to `current_sandbox_start`, which immediately calls `current_sandbox_init`. This function initializes the associated runtime state and
When `sledgert` receives a request at the registered port specified in the JSON, it performs allocation and initialization steps. The scheduler sets the expected ABI symbols and yields to `current_sandbox_start`, which immediately calls `current_sandbox_init`. This function initializes the associated runtime state and
1. calls `module.abi.initialize_globals` for the current sandbox if not NULL. This is optional because the module might not have been built with the `--runtime-globals`, in which case runtime globals are not used at all. If not NULL, the globals are set in the table.
2. calls `module.abi.initialize_memory`, which copies regions into the linear memory
2. calls `module.abi.initialize_memory`, which copies segments into the linear memory
`current_sandbox_init` calls `wasi_context_init` to initialize the WASI context within the runtime.
`current_sandbox_init` returns to `current_sandbox_start`, which sets up wasm traps using `setjmp` and then calls `module.abi.entrypoint`
# Questions:
# Discussion (follow-up with Github issues):
- Should `sledge_abi__current_wasm_module_instance` be turned into a macro defined int the ABI header?
- Should `sledge_abi__current_wasm_module_instance` be turned into a macro defined int the ABI header? That way it'll be easier to change the ABI symbols (change once, applied everywhere).
- Should `instruction_memory_grow` be moved into sledgert? This would simplify the handling of the "cache" and generating a memory profile?
- Rename `sledge_abi__wasm_globals_*` to `sledge_abi__wasm_global_*`
- Implement Unsupported Numeric Instructions
- Should the wasm global table be accessed directly instead of via a runtime function? If we expose the wasm global table to libsledge, then we have worse ABI stability, but better performance.
- Should the Function Table be handled by the \*.so file or sledgert? Are function pointers really called that frequently?

@ -1,8 +1,6 @@
#include <stdint.h>
#include "sledge_abi.h"
// TODO: Validate uint32_t as return value;
uint32_t
wasi_snapshot_preview1_args_get(__wasi_size_t argv_retoffset, __wasi_size_t argv_buf_retoffset)
{

@ -38,6 +38,10 @@ BINARY_NAME=sledgert
# Feature Toggles
CFLAGS += -DEXECUTION_HISTOGRAM
# CFLAGS += -DEXECUTION_REGRESSION
# It is recommended (not mandatory) to enable this flag along with the EXECUTION_HISTOGRAM flag:
# CFLAGS += -DADMISSIONS_CONTROL
# Debugging Flags
@ -56,6 +60,7 @@ BINARY_NAME=sledgert
# CFLAGS += -DLOG_TO_FILE
# Various Informational Logs for Debugging
# CFLAGS += -DLOG_EXECUTION_HISTOGRAM
# CFLAGS += -DLOG_ADMISSIONS_CONTROL
# CFLAGS += -DLOG_CONTEXT_SWITCHES
# CFLAGS += -DLOG_HTTP_PARSER

@ -1,18 +1,19 @@
#pragma once
#ifdef ADMISSIONS_CONTROL
#include <stdbool.h>
#include <stdint.h>
#ifdef ADMISSIONS_CONTROL
#define ADMISSIONS_CONTROL_GRANULARITY 1000000
extern _Atomic uint64_t admissions_control_admitted;
extern uint64_t admissions_control_capacity;
#endif
void admissions_control_initialize(void);
void admissions_control_add(uint64_t admissions_estimate);
void admissions_control_subtract(uint64_t admissions_estimate);
uint64_t admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline);
uint64_t admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us);
void admissions_control_log_decision(uint64_t admissions_estimate, bool admitted);
uint64_t admissions_control_decide(uint64_t admissions_estimate);
#endif

@ -1,15 +0,0 @@
#pragma once
#include "perf_window_t.h"
struct admissions_info {
struct perf_window perf_window;
uint8_t percentile; /* 50 - 99 */
int control_index; /* Precomputed Lookup index when perf_window is full */
uint64_t estimate; /* cycles */
uint64_t relative_deadline; /* Relative deadline in cycles. This is duplicated state */
};
void admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile,
uint64_t expected_execution, uint64_t relative_deadline);
void admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration);

@ -3,9 +3,9 @@
#include <setjmp.h>
#include <ucontext.h>
#include "arch/arch_context_variant_t.h"
#include "arch/reg_t.h"
#include "arch/ureg_t.h"
#include "arch/arch_context_variant_t.h"
struct arch_context {
arch_context_variant_t variant;

@ -1,5 +1,6 @@
#pragma once
#include "likely.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

@ -3,6 +3,7 @@
#include <threads.h>
#include "current_wasm_module_instance.h"
#include "listener_thread.h"
#include "sandbox_types.h"
/* current sandbox that is active.. */
@ -30,24 +31,25 @@ current_sandbox_set(struct sandbox *sandbox)
/* Unpack hierarchy to avoid pointer chasing */
if (sandbox == NULL) {
sledge_abi__current_wasm_module_instance = (struct wasm_module_instance){
/* Public */
.abi =
(struct sledge_abi__wasm_module_instance){
.memory =
(struct sledge_abi__wasm_memory){
.size = 0,
.capacity = 0,
.max = 0,
.buffer = NULL,
},
.table = NULL,
.wasmg_0 = 0,
},
/* Private */
.wasi_context = NULL,
/* Public */
.abi =
(struct sledge_abi__wasm_module_instance){
.memory =
(struct sledge_abi__wasm_memory){
.size = 0,
.capacity = 0,
.max = 0,
.buffer = NULL,
},
.table = NULL,
.wasmg_0 = 0,
},
/* Private */
.wasi_context = NULL,
};
worker_thread_current_sandbox = NULL;
runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX;
worker_thread_current_sandbox = NULL;
/* This is because the event core does not maintain core-assigned deadline */
if (!listener_thread_is_running()) runtime_worker_threads_deadline[worker_thread_idx] = UINT64_MAX;
} else {
sledge_abi__current_wasm_module_instance.wasi_context = sandbox->wasi_context;
memcpy(&sledge_abi__current_wasm_module_instance.abi.memory, &sandbox->memory->abi,
@ -55,8 +57,9 @@ current_sandbox_set(struct sandbox *sandbox)
sledge_abi__current_wasm_module_instance.abi.table = sandbox->module->indirect_table;
wasm_globals_update_if_used(&sandbox->globals, 0,
&sledge_abi__current_wasm_module_instance.abi.wasmg_0);
worker_thread_current_sandbox = sandbox;
runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline;
worker_thread_current_sandbox = sandbox;
if (!listener_thread_is_running())
runtime_worker_threads_deadline[worker_thread_idx] = sandbox->absolute_deadline;
}
}

@ -0,0 +1,14 @@
#pragma once
#include "perf_window_t.h"
struct execution_histogram {
struct perf_window perf_window;
uint8_t percentile; /* 50 - 99 */
int control_index; /* Precomputed Lookup index when perf_window is full */
uint64_t estimated_execution; /* cycles */
};
void execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile,
uint64_t expected_execution);
void execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration);

@ -0,0 +1,26 @@
#pragma once
#ifdef EXECUTION_REGRESSION
#include "http_session.h"
#include <stdint.h>
static inline uint64_t
get_regression_prediction(struct http_session *session)
{
/* Default Pre-processing - Extract payload size */
const int payload_size = session->http_request.body_length;
const double regression_params[2] = {payload_size, session->regression_param};
/* Perform Linear Regression using the factors provided by the regressor performed AoT on Matlab using training
* tenant-given dataset */
const struct regression_model model = session->route->regr_model;
const uint64_t prediction = (regression_params[0] / model.scale * model.beta1
+ regression_params[1] / model.scale * model.beta2)
+ model.bias;
return prediction;
}
#endif

@ -1,14 +1,12 @@
#pragma once
#include <stdlib.h>
#include <string.h>
#include "http.h"
#include "module.h"
#include "route_latency.h"
#include "route.h"
#include "route_config.h"
#include "route_latency.h"
#include "vec.h"
#include <stdlib.h>
typedef struct route route_t;
VEC(route_t)
@ -22,7 +20,8 @@ http_router_init(http_router_t *router, size_t capacity)
}
static inline int
http_router_add_route(http_router_t *router, struct route_config *config, struct module *module)
http_router_add_route(http_router_t *router, struct route_config *config, struct module *module,
struct module *module_proprocess)
{
assert(router != NULL);
assert(config != NULL);
@ -30,20 +29,35 @@ http_router_add_route(http_router_t *router, struct route_config *config, struct
assert(config->route != NULL);
assert(config->http_resp_content_type != NULL);
struct route route = { .route = config->route,
.module = module,
.relative_deadline_us = config->relative_deadline_us,
.relative_deadline = (uint64_t)config->relative_deadline_us
* runtime_processor_speed_MHz,
.response_content_type = config->http_resp_content_type };
struct route route = {.route = config->route,
.module = module,
.relative_deadline_us = config->relative_deadline_us,
.relative_deadline = (uint64_t)config->relative_deadline_us * runtime_processor_speed_MHz,
.response_content_type = config->http_resp_content_type};
route_latency_init(&route.latency);
http_route_total_init(&route.metrics);
/* Admissions Control */
uint64_t expected_execution = (uint64_t)config->expected_execution_us * runtime_processor_speed_MHz;
admissions_info_initialize(&route.admissions_info, config->admissions_percentile, expected_execution,
route.relative_deadline);
#ifdef EXECUTION_REGRESSION
/* Execution Regression setup */
route.module_proprocess = module_proprocess;
route.regr_model.bias = config->model_bias / 1000.0;
route.regr_model.scale = config->model_scale / 1000.0;
route.regr_model.num_of_param = config->model_num_of_param;
route.regr_model.beta1 = config->model_beta1 / 1000.0;
route.regr_model.beta2 = config->model_beta2 / 1000.0;
#endif
const uint64_t expected_execution = route.relative_deadline / 2;
#ifdef ADMISSIONS_CONTROL
/* Addmissions Control setup */
route.execution_histogram.estimated_execution = expected_execution;
#endif
#ifdef EXECUTION_HISTOGRAM
/* Execution Histogram setup */
execution_histogram_initialize(&route.execution_histogram, config->admissions_percentile, expected_execution);
#endif
int rc = vec_route_t_push(router, route);
if (unlikely(rc == -1)) { return -1; }

@ -57,6 +57,9 @@ struct http_session {
uint64_t request_downloaded_timestamp;
uint64_t response_takeoff_timestamp;
uint64_t response_sent_timestamp;
bool did_preprocessing;
uint64_t preprocessing_duration;
double regression_param; /* Calculated in tenant preprocessing logic if provided */
};
extern void http_session_perf_log_print_entry(struct http_session *http_session);
@ -197,8 +200,6 @@ http_session_set_response_header(struct http_session *session, int status_code)
rc = fprintf(session->response_header.handle, HTTP_RESPONSE_CONTENT_LENGTH,
session->response_body.size);
assert(rc > 0);
rc = fputs(HTTP_RESPONSE_200_OK, session->response_header.handle);
assert(rc != EOF);
}
rc = fputs(HTTP_RESPONSE_TERMINATOR, session->response_header.handle);

@ -1,8 +1,8 @@
#pragma once
#include "http_session.h"
#include "pretty_print.h"
#include "runtime.h"
#include "http_session.h"
extern FILE *http_session_perf_log;
typedef struct http_session http_session;
@ -15,8 +15,8 @@ static inline void
http_session_perf_log_print_header()
{
if (http_session_perf_log == NULL) { perror("http_session perf log"); }
fprintf(http_session_perf_log,
"tenant,route,state,header_len,resp_body_len,receive_duration,sent_duration,total_lifetime,proc_MHz\n");
fprintf(http_session_perf_log, "tenant,route,state,header_len,resp_body_len,receive_duration,sent_duration,"
"total_lifetime,preprocessing,proc_MHz\n");
}
static inline void

@ -2,12 +2,12 @@
#include <errno.h>
#include <inttypes.h>
#include <jsmn.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jsmn.h>
static inline char *
jsmn_type(jsmntype_t type)

@ -98,12 +98,12 @@ map_set(struct map *map, uint8_t *key, uint32_t key_len, uint8_t *value, uint32_
}
struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node));
*(new_node) = (struct map_node){ .hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value = xmalloc(value_len),
.value_len = value_len,
.next = bucket->head };
*(new_node) = (struct map_node){.hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value = xmalloc(value_len),
.value_len = value_len,
.next = bucket->head};
// Copy Key and Value
memcpy(new_node->key, key, key_len);
@ -174,12 +174,12 @@ map_upsert(struct map *map, uint8_t *key, uint32_t key_len, uint8_t *value, uint
struct map_node *new_node = (struct map_node *)xmalloc(sizeof(struct map_node));
*(new_node) = (struct map_node){ .hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value = xmalloc(value_len),
.value_len = value_len,
.next = bucket->head };
*(new_node) = (struct map_node){.hash = hash,
.key = xmalloc(key_len),
.key_len = key_len,
.value = xmalloc(value_len),
.value_len = value_len,
.next = bucket->head};
assert(new_node->key);
assert(new_node->value);

@ -1,22 +1,11 @@
#pragma once
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include "admissions_control.h"
#include "admissions_info.h"
#include "current_wasm_module_instance.h"
#include "panic.h"
#include "pool.h"
#include "sledge_abi_symbols.h"
#include "tcp_server.h"
#include "types.h"
#include "sledge_abi_symbols.h"
#include "wasm_stack.h"
#include "wasm_memory.h"
#include "wasm_table.h"
#include "wasm_stack.h"
extern thread_local int worker_thread_idx;
@ -28,9 +17,15 @@ struct module_pool {
struct wasm_stack_pool stack;
} CACHE_PAD_ALIGNED;
enum module_type
{
APP_MODULE,
PREPROCESS_MODULE
};
struct module {
char *path;
uint32_t stack_size; /* a specification? */
char *path;
uint32_t stack_size; /* a specification? */
enum module_type type;
/* Handle and ABI Symbols for *.so file */
struct sledge_abi_symbols abi;
@ -41,12 +36,13 @@ struct module {
struct module_pool *pools;
} CACHE_PAD_ALIGNED;
/********************************
* Public Methods from module.c *
*******************************/
void module_free(struct module *module);
struct module *module_alloc(char *path);
struct module *module_alloc(char *path, enum module_type type);
/*************************
* Public Static Inlines *
@ -115,7 +111,9 @@ module_alloc_table(struct module *module)
static inline void
module_initialize_pools(struct module *module)
{
for (int i = 0; i < runtime_worker_threads_count; i++) {
/* Create only a single pool for the preprocessing module, since it is executed only by the event core. */
const int n = module->type == APP_MODULE ? runtime_worker_threads_count : 1;
for (int i = 0; i < n; i++) {
wasm_memory_pool_init(&module->pools[i].memory, false);
wasm_stack_pool_init(&module->pools[i].stack, false);
}
@ -124,7 +122,8 @@ module_initialize_pools(struct module *module)
static inline void
module_deinitialize_pools(struct module *module)
{
for (int i = 0; i < runtime_worker_threads_count; i++) {
const int n = module->type == APP_MODULE ? runtime_worker_threads_count : 1;
for (int i = 0; i < n; i++) {
wasm_memory_pool_deinit(&module->pools[i].memory);
wasm_stack_pool_deinit(&module->pools[i].stack);
}

@ -72,8 +72,8 @@ perf_window_fill(struct perf_window *perf_window, uint64_t newest_execution_time
{
for (uint16_t i = 0; i < PERF_WINDOW_CAPACITY; i++) {
perf_window->by_termination[i] = i;
perf_window->by_duration[i] = (struct execution_node){ .execution_time = newest_execution_time,
.by_termination_idx = i };
perf_window->by_duration[i] = (struct execution_node){.execution_time = newest_execution_time,
.by_termination_idx = i};
}
perf_window->count = PERF_WINDOW_CAPACITY;
}

@ -1,7 +1,7 @@
#pragma once
#include <stdio.h>
#include <stdarg.h>
#include <stdio.h>
#define PRETTY_PRINT_COLOR_CODE_RED "\033[1;31m"
#define PRETTY_COLOR_CODE_GREEN "\033[0;32m"

@ -3,8 +3,8 @@
#include <errno.h>
#include "lock.h"
#include "listener_thread.h"
#include "lock.h"
#include "panic.h"
#include "runtime.h"
#include "worker_thread.h"

@ -2,8 +2,8 @@
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "runtime.h" /* For runtime_pid */

@ -1,22 +1,32 @@
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdint.h>
#include "admissions_info.h"
#include "module.h"
#include "execution_histogram.h"
#include "http_route_total.h"
#include "module.h"
#include "perf_window.h"
struct regression_model {
double bias;
double scale;
uint32_t num_of_param;
double beta1;
double beta2;
};
/* Assumption: entrypoint is always _start. This should be enhanced later */
struct route {
char *route;
struct http_route_total metrics;
struct module *module;
/* HTTP State */
uint32_t relative_deadline_us;
uint64_t relative_deadline; /* cycles */
char *response_content_type;
struct admissions_info admissions_info;
struct perf_window latency;
uint32_t relative_deadline_us;
uint64_t relative_deadline; /* cycles */
char *response_content_type;
struct execution_histogram execution_histogram;
struct perf_window latency;
struct module *module_proprocess;
struct regression_model regr_model;
};

@ -13,8 +13,13 @@ enum route_config_member
route_config_member_route,
route_config_member_path,
route_config_member_admissions_percentile,
route_config_member_expected_execution_us,
route_config_member_relative_deadline_us,
route_config_member_path_preprocess,
route_config_member_model_bias,
route_config_member_model_scale,
route_config_member_model_num_of_param,
route_config_member_model_beta1,
route_config_member_model_beta2,
route_config_member_http_resp_content_type,
route_config_member_len
};
@ -23,8 +28,13 @@ struct route_config {
char *route;
char *path;
uint8_t admissions_percentile;
uint32_t expected_execution_us;
uint32_t relative_deadline_us;
char *path_preprocess;
uint32_t model_bias;
uint32_t model_scale;
uint32_t model_num_of_param;
uint32_t model_beta1;
uint32_t model_beta2;
char *http_resp_content_type;
};
@ -45,9 +55,15 @@ route_config_print(struct route_config *config)
printf("[Route] Route: %s\n", config->route);
printf("[Route] Path: %s\n", config->path);
printf("[Route] Admissions Percentile: %hhu\n", config->admissions_percentile);
printf("[Route] Expected Execution (us): %u\n", config->expected_execution_us);
printf("[Route] Relative Deadline (us): %u\n", config->relative_deadline_us);
printf("[Route] HTTP Response Content Type: %s\n", config->http_resp_content_type);
#ifdef EXECUTION_HISTOGRAM
printf("[Route] Path of Preprocessing Module: %s\n", config->path_preprocess);
printf("[Route] Model Bias: %u\n", config->model_bias);
printf("[Route] Model Scale: %u\n", config->model_scale);
printf("[Route] Model Num of Parameters: %u\n", config->model_num_of_param);
printf("[Route] Model Betas: [%u, %u]\n", config->model_beta1, config->model_beta2);
#endif
}
/**
@ -59,7 +75,7 @@ static inline int
route_config_validate(struct route_config *config, bool *did_set)
{
if (did_set[route_config_member_route] == false) {
fprintf(stderr, "path field is required\n");
fprintf(stderr, "route field is required\n");
return -1;
}
@ -73,9 +89,9 @@ route_config_validate(struct route_config *config, bool *did_set)
config->http_resp_content_type = "text/plain";
}
if (scheduler != SCHEDULER_FIFO) {
if (scheduler != SCHEDULER_FIFO && scheduler != SCHEDULER_SJF) {
if (did_set[route_config_member_relative_deadline_us] == false) {
fprintf(stderr, "relative_deadline_us is required\n");
fprintf(stderr, "relative_deadline_us is required for the selected scheduler\n");
return -1;
}
@ -84,36 +100,80 @@ route_config_validate(struct route_config *config, bool *did_set)
(uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX, config->relative_deadline_us);
return -1;
}
}
#ifdef ADMISSIONS_CONTROL
if (did_set[route_config_member_expected_execution_us] == false) {
fprintf(stderr, "expected-execution-us is required\n");
return -1;
}
#ifdef EXECUTION_HISTOGRAM
if (config->admissions_percentile > 99 || config->admissions_percentile < 50) {
fprintf(stderr, "admissions-percentile must be > 50 and <= 99 but was %u, defaulting to 70\n",
config->admissions_percentile);
config->admissions_percentile = 70;
}
#endif
#ifdef EXECUTION_REGRESSION
if (did_set[route_config_member_path_preprocess] == false) {
fprintf(stderr, "model path_preprocess field is required. Put zero if just default preprocessing\n");
return -1;
} else if (strcmp(config->path_preprocess, "0") == 0) {
config->path_preprocess = NULL;
}
if (did_set[route_config_member_model_bias] == false) {
fprintf(stderr, "model bias field is required\n");
return -1;
}
if (did_set[route_config_member_model_scale] == false) {
fprintf(stderr, "model scale field is required\n");
return -1;
}
if (config->model_scale == 0) {
fprintf(stderr, "model scale cannot be zero (to avoid divide by zero)\n");
return -1;
}
if (did_set[route_config_member_admissions_percentile] == false) {
fprintf(stderr, "admissions_percentile is required\n");
if (did_set[route_config_member_model_num_of_param] == false) {
fprintf(stderr, "model num_of_param field is required\n");
return -1;
}
if (did_set[route_config_member_model_beta1] == false) {
fprintf(stderr, "model beta1 field is required\n");
return -1;
}
if (config->model_beta1 == 0) {
fprintf(stderr, "model beta1 cannot be zero (to avoid divide by zero)\n");
return -1;
}
if (did_set[route_config_member_model_beta2] == false) {
fprintf(stderr, "model beta2 field is required. Put zero for just default preprocessing\n");
return -1;
}
if (config->model_num_of_param < 1) {
fprintf(stderr, "model num_of_param must be at least 1 (just default preprocessing)\n");
return -1;
} else if (config->model_num_of_param == 1) {
if (config->path_preprocess) {
fprintf(stderr, "model_num_of_param cannot be 1 when using tenant preprocessing\n");
return -1;
}
if (config->admissions_percentile > 99 || config->admissions_percentile < 50) {
fprintf(stderr, "admissions-percentile must be > 50 and <= 99 but was %u\n",
config->admissions_percentile);
config->model_beta2 = 1; /* This is to avoid divide-by-zero */
} else {
/* For now we just support up to two params */
assert(config->model_num_of_param == 2);
if (config->path_preprocess == NULL) {
fprintf(stderr, "model_num_of_param cannot be more than 1 when just default preprocessing\n");
return -1;
}
/* If the ratio is too big, admissions control is too coarse */
uint32_t ratio = config->relative_deadline_us / config->expected_execution_us;
if (ratio > ADMISSIONS_CONTROL_GRANULARITY) {
fprintf(stderr,
"Ratio of Deadline to Execution time cannot exceed admissions control "
"granularity of "
"%d\n",
ADMISSIONS_CONTROL_GRANULARITY);
if (config->model_beta2 == 0) {
fprintf(stderr, "model beta2 cannot be zero (to avoid divide by zero)\n");
return -1;
}
#endif
}
#endif
return 0;
}

@ -6,12 +6,10 @@
#include "json.h"
#include "route_config.h"
static const char *route_config_json_keys[route_config_member_len] = { "route",
"path",
"admissions-percentile",
"expected-execution-us",
"relative-deadline-us",
"http-resp-content-type" };
static const char *route_config_json_keys[route_config_member_len] =
{"route", "path", "admissions-percentile", "relative-deadline-us",
"path_preprocess", "model-bias", "model-scale", "model-num-of-param",
"model-beta1", "model-beta2", "http-resp-content-type"};
static inline int
route_config_set_key_once(bool *did_set, enum route_config_member member)
@ -30,8 +28,8 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
int tokens_size)
{
int i = tokens_base;
char key[32] = { 0 };
bool did_set[route_config_member_len] = { false };
char key[32] = {0};
bool did_set[route_config_member_len] = {false};
if (!has_valid_type(tokens[i], "Anonymous Route Config Object", JSMN_OBJECT, json_buf)) return -1;
if (!is_nonempty_object(tokens[i], "Anonymous Route Config Object")) return -1;
@ -61,6 +59,11 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
if (route_config_set_key_once(did_set, route_config_member_path) == -1) return -1;
config->path = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start);
} else if (strcmp(key, route_config_json_keys[route_config_member_path_preprocess]) == 0) {
if (!is_nonempty_string(tokens[i], key)) return -1;
if (route_config_set_key_once(did_set, route_config_member_path_preprocess) == -1) return -1;
config->path_preprocess = strndup(json_buf + tokens[i].start, tokens[i].end - tokens[i].start);
} else if (strcmp(key, route_config_json_keys[route_config_member_admissions_percentile]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_admissions_percentile) == -1)
@ -70,15 +73,6 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
route_config_json_keys[route_config_member_admissions_percentile],
&config->admissions_percentile);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_expected_execution_us]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_expected_execution_us) == -1)
return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_expected_execution_us],
&config->expected_execution_us);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_relative_deadline_us]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_relative_deadline_us) == -1)
@ -88,6 +82,49 @@ route_config_parse(struct route_config *config, const char *json_buf, jsmntok_t
route_config_json_keys[route_config_member_relative_deadline_us],
&config->relative_deadline_us);
if (rc < 0) return -1;
} else if (strcmp(key, "expected-execution-us") == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
printf("The \"expected-execution-us\" field has been deprecated, so no need.\n");
} else if (strcmp(key, route_config_json_keys[route_config_member_model_bias]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_model_bias) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_bias],
&config->model_bias);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_scale]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_model_scale) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_scale],
&config->model_scale);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_num_of_param]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_model_num_of_param) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_num_of_param],
&config->model_num_of_param);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_beta1]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_model_beta1) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_beta1],
&config->model_beta1);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_model_beta2]) == 0) {
if (!has_valid_type(tokens[i], key, JSMN_PRIMITIVE, json_buf)) return -1;
if (route_config_set_key_once(did_set, route_config_member_model_beta2) == -1) return -1;
int rc = parse_uint32_t(tokens[i], json_buf,
route_config_json_keys[route_config_member_model_beta2],
&config->model_beta2);
if (rc < 0) return -1;
} else if (strcmp(key, route_config_json_keys[route_config_member_http_resp_content_type]) == 0) {
if (!is_nonempty_string(tokens[i], key)) return -1;
if (route_config_set_key_once(did_set, route_config_member_http_resp_content_type) == -1)

@ -1,10 +1,10 @@
#pragma once
#include <pthread.h>
#include <sys/epoll.h> /* for epoll_create1(), epoll_ctl(), struct epoll_event */
#include <sys/types.h> /* for pid_t */
#include <stdatomic.h>
#include <stdbool.h>
#include <sys/epoll.h> /* for epoll_create1(), epoll_ctl(), struct epoll_event */
#include <sys/types.h> /* for pid_t */
#include "likely.h"
#include "types.h"
@ -37,6 +37,7 @@ enum RUNTIME_SIGALRM_HANDLER
extern pid_t runtime_pid;
extern bool runtime_preemption_enabled;
extern bool runtime_worker_spinloop_pause_enabled;
extern uint32_t runtime_processor_speed_MHz;
extern uint32_t runtime_quantum_us;
extern enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler;

@ -1,12 +1,12 @@
#pragma once
#include <sys/mman.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>
#include "panic.h"
#include "tenant.h"
#include "sandbox_types.h"
#include "tenant.h"
/***************************
* Public API *

@ -13,9 +13,10 @@ static inline void
sandbox_perf_log_print_header()
{
if (sandbox_perf_log == NULL) { perror("sandbox perf log"); }
fprintf(sandbox_perf_log, "id,tenant,route,state,deadline,actual,queued,uninitialized,allocated,initialized,"
"runnable,interrupted,preempted,"
"running_sys,running_user,asleep,returned,complete,error,proc_MHz,memory\n");
fprintf(sandbox_perf_log,
"id,tenant,route,state,deadline,actual,queued,uninitialized,allocated,initialized,"
"runnable,interrupted,preempted,"
"running_sys,running_user,asleep,returned,complete,error,proc_MHz,payload_size,regression_param\n");
}
/**
@ -36,7 +37,8 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox)
* becomes more intelligent, then peak linear memory size needs to be tracked
* seperately from current linear memory size.
*/
fprintf(sandbox_perf_log, "%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u\n",
fprintf(sandbox_perf_log,
"%lu,%s,%s,%s,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%u,%u,%d,%d,%lf\n",
sandbox->id, sandbox->tenant->name, sandbox->route->route, sandbox_state_stringify(sandbox->state),
sandbox->route->relative_deadline, sandbox->total_time, queued_duration,
sandbox->duration_of_state[SANDBOX_UNINITIALIZED], sandbox->duration_of_state[SANDBOX_ALLOCATED],
@ -45,7 +47,8 @@ sandbox_perf_log_print_entry(struct sandbox *sandbox)
sandbox->duration_of_state[SANDBOX_RUNNING_SYS], sandbox->duration_of_state[SANDBOX_RUNNING_USER],
sandbox->duration_of_state[SANDBOX_ASLEEP], sandbox->duration_of_state[SANDBOX_RETURNED],
sandbox->duration_of_state[SANDBOX_COMPLETE], sandbox->duration_of_state[SANDBOX_ERROR],
runtime_processor_speed_MHz);
runtime_processor_speed_MHz, sandbox->response_code, 0, sandbox->payload_size,
sandbox->regression_param);
}
static inline void

@ -5,10 +5,10 @@
#include "arch/getcycles.h"
#include "local_runqueue.h"
#include "sandbox_types.h"
#include "sandbox_state.h"
#include "sandbox_state_history.h"
#include "sandbox_state_transition.h"
#include "sandbox_types.h"
/**
* Transitions a sandbox to the SANDBOX_ASLEEP state.

@ -3,7 +3,9 @@
#include <assert.h>
#include <stdint.h>
#include "admissions_control.h"
#include "arch/getcycles.h"
#include "execution_histogram.h"
#include "panic.h"
#include "sandbox_functions.h"
#include "sandbox_perf_log.h"
@ -46,15 +48,24 @@ sandbox_set_as_complete(struct sandbox *sandbox, sandbox_state_t last_state)
sandbox_state_totals_increment(SANDBOX_COMPLETE);
sandbox_state_totals_decrement(last_state);
struct route *route = sandbox->route;
#ifdef EXECUTION_HISTOGRAM
/* Execution Histogram Post Processing */
const uint64_t execution_duration = sandbox->duration_of_state[SANDBOX_RUNNING_USER]
+ sandbox->duration_of_state[SANDBOX_RUNNING_SYS];
execution_histogram_update(&route->execution_histogram, execution_duration);
#endif
#ifdef ADMISSIONS_CONTROL
/* Admissions Control Post Processing */
admissions_info_update(&sandbox->route->admissions_info, sandbox->duration_of_state[SANDBOX_RUNNING_USER]
+ sandbox->duration_of_state[SANDBOX_RUNNING_SYS]);
admissions_control_subtract(sandbox->admissions_estimate);
#endif
/* Terminal State Logging for Sandbox */
sandbox_perf_log_print_entry(sandbox);
sandbox_summarize_page_allocations(sandbox);
route_latency_add(&sandbox->route->latency, sandbox->total_time);
route_latency_add(&route->latency, sandbox->total_time);
/* State Change Hooks */
sandbox_state_transition_from_hook(sandbox, last_state);

@ -3,16 +3,17 @@
#include <assert.h>
#include <stdint.h>
#include "admissions_control.h"
#include "arch/getcycles.h"
#include "listener_thread.h"
#include "local_runqueue.h"
#include "sandbox_state.h"
#include "panic.h"
#include "sandbox_functions.h"
#include "sandbox_perf_log.h"
#include "sandbox_state.h"
#include "sandbox_state_history.h"
#include "sandbox_state_transition.h"
#include "sandbox_summarize_page_allocations.h"
#include "panic.h"
/**
* Transitions a sandbox to the SANDBOX_ERROR state.
@ -48,14 +49,21 @@ sandbox_set_as_error(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
if (last_state == SANDBOX_RUNNING_SYS) {
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
}
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_ERROR);
sandbox_state_totals_increment(SANDBOX_ERROR);
sandbox_state_totals_decrement(last_state);
#ifdef ADMISSIONS_CONTROL
/* Admissions Control Post Processing */
admissions_control_subtract(sandbox->admissions_estimate);
#endif
/* Return HTTP session to listener core to be written back to client */
http_session_set_response_header(sandbox->http, 500);

@ -25,6 +25,10 @@ sandbox_set_as_interrupted(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
assert(last_state == SANDBOX_RUNNING_USER);
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
/* We do not append SANDBOX_INTERRUPTED to the sandbox_state_history because it would quickly fill the buffer */

@ -3,8 +3,8 @@
#include <assert.h>
#include <stdint.h>
#include "auto_buf.h"
#include "arch/getcycles.h"
#include "auto_buf.h"
#include "listener_thread.h"
#include "local_runqueue.h"
#include "panic.h"
@ -45,6 +45,9 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_RETURNED);
@ -60,5 +63,7 @@ sandbox_set_as_returned(struct sandbox *sandbox, sandbox_state_t last_state)
sandbox_state_transition_from_hook(sandbox, last_state);
sandbox_state_transition_to_hook(sandbox, SANDBOX_RETURNED);
assert(sandbox->response_code == 0);
sandbox->response_code = 200;
sandbox_process_scheduler_updates(sandbox);
}

@ -41,6 +41,11 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
if (last_state == SANDBOX_RUNNING_USER) {
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
}
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_SYS);
@ -55,6 +60,8 @@ sandbox_set_as_running_sys(struct sandbox *sandbox, sandbox_state_t last_state)
static inline void
sandbox_syscall(struct sandbox *sandbox)
{
if (sandbox->module->type == PREPROCESS_MODULE) return;
assert(sandbox->state == SANDBOX_RUNNING_USER);
sandbox_set_as_running_sys(sandbox, SANDBOX_RUNNING_USER);

@ -6,10 +6,10 @@
#include "arch/getcycles.h"
#include "current_sandbox.h"
#include "panic.h"
#include "sandbox_functions.h"
#include "sandbox_state_history.h"
#include "sandbox_state_transition.h"
#include "sandbox_types.h"
#include "sandbox_functions.h"
static inline void
sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state)
@ -37,6 +37,11 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state)
/* State Change Bookkeeping */
assert(now > sandbox->timestamp_of.last_state_change);
sandbox->last_state_duration = now - sandbox->timestamp_of.last_state_change;
if (last_state == SANDBOX_RUNNING_SYS) {
sandbox->remaining_exec = (sandbox->remaining_exec > sandbox->last_state_duration)
? sandbox->remaining_exec - sandbox->last_state_duration
: 0;
}
sandbox->duration_of_state[last_state] += sandbox->last_state_duration;
sandbox->timestamp_of.last_state_change = now;
sandbox_state_history_append(&sandbox->state_history, SANDBOX_RUNNING_USER);
@ -61,6 +66,8 @@ sandbox_set_as_running_user(struct sandbox *sandbox, sandbox_state_t last_state)
static inline void
sandbox_return(struct sandbox *sandbox)
{
if (sandbox->module->type == PREPROCESS_MODULE) return;
assert(sandbox->state == SANDBOX_RUNNING_SYS);
sandbox_set_as_running_user(sandbox, SANDBOX_RUNNING_SYS);
}

@ -9,11 +9,11 @@
#include "sandbox_state.h"
#include "sandbox_state_history.h"
#include "tenant.h"
#include "wasi.h"
#include "wasm_globals.h"
#include "wasm_memory.h"
#include "wasm_types.h"
#include "wasm_stack.h"
#include "wasm_globals.h"
#include "wasi.h"
#include "wasm_types.h"
/*********************
* Structs and Types *
@ -38,6 +38,7 @@ struct sandbox {
uint64_t id;
sandbox_state_t state;
struct sandbox_state_history state_history;
uint16_t response_code;
/* Accounting Info */
@ -61,10 +62,13 @@ struct sandbox {
uint64_t duration_of_state[SANDBOX_STATE_COUNT];
uint64_t last_state_duration;
uint64_t remaining_exec;
uint64_t absolute_deadline;
uint64_t admissions_estimate; /* estimated execution time (cycles) * runtime_admissions_granularity / relative
deadline (cycles) */
uint64_t total_time; /* Total time from Request to Response */
int payload_size;
double regression_param; /* Calculated in tenant preprocessing logic if provided */
/* System Interface State */
int32_t return_value;

@ -9,19 +9,19 @@
#include "global_request_scheduler_deque.h"
#include "global_request_scheduler_minheap.h"
#include "global_request_scheduler_mtds.h"
#include "local_cleanup_queue.h"
#include "local_runqueue.h"
#include "local_runqueue_minheap.h"
#include "local_runqueue_list.h"
#include "local_cleanup_queue.h"
#include "local_runqueue_minheap.h"
#include "local_runqueue_mtds.h"
#include "panic.h"
#include "sandbox_functions.h"
#include "sandbox_types.h"
#include "sandbox_set_as_interrupted.h"
#include "sandbox_set_as_preempted.h"
#include "sandbox_set_as_runnable.h"
#include "sandbox_set_as_running_sys.h"
#include "sandbox_set_as_interrupted.h"
#include "sandbox_set_as_running_user.h"
#include "sandbox_types.h"
#include "scheduler_options.h"
@ -106,6 +106,31 @@ done:
return local_runqueue_get_next();
}
static inline struct sandbox *
scheduler_sjf_get_next()
{
struct sandbox *local = local_runqueue_get_next();
uint64_t local_rem_exec = local == NULL ? UINT64_MAX : local->remaining_exec;
struct sandbox *global = NULL;
uint64_t global_remaining_exec = global_request_scheduler_peek();
/* Try to pull and allocate from the global queue if earlier
* This will be placed at the head of the local runqueue */
if (global_remaining_exec < local_rem_exec) {
if (global_request_scheduler_remove_if_earlier(&global, local_rem_exec) == 0) {
assert(global != NULL);
assert(global->remaining_exec < local_rem_exec);
sandbox_prepare_execution_environment(global);
assert(global->state == SANDBOX_INITIALIZED);
sandbox_set_as_runnable(global, SANDBOX_INITIALIZED);
}
}
/* Return what is at the head of the local runqueue or NULL if empty */
return local_runqueue_get_next();
}
static inline struct sandbox *
scheduler_edf_get_next()
{
@ -163,6 +188,8 @@ scheduler_get_next()
return scheduler_mtdbf_get_next();
case SCHEDULER_MTDS:
return scheduler_mtds_get_next();
case SCHEDULER_SJF:
return scheduler_sjf_get_next();
case SCHEDULER_EDF:
return scheduler_edf_get_next();
case SCHEDULER_FIFO:
@ -177,12 +204,13 @@ scheduler_initialize()
{
switch (scheduler) {
case SCHEDULER_MTDBF:
// global_request_scheduler_mtdbf_initialize();
/* TODO: loading */
break;
case SCHEDULER_MTDS:
global_request_scheduler_mtds_initialize();
break;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
global_request_scheduler_minheap_initialize();
break;
case SCHEDULER_FIFO:
@ -204,6 +232,7 @@ scheduler_runqueue_initialize()
local_runqueue_mtds_initialize();
break;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
local_runqueue_minheap_initialize();
break;
case SCHEDULER_FIFO:
@ -222,6 +251,8 @@ scheduler_print(enum SCHEDULER variant)
return "FIFO";
case SCHEDULER_EDF:
return "EDF";
case SCHEDULER_SJF:
return "SJF";
case SCHEDULER_MTDS:
return "MTDS";
case SCHEDULER_MTDBF:
@ -287,6 +318,7 @@ scheduler_process_policy_specific_updates_on_interrupts(struct sandbox *interrup
case SCHEDULER_FIFO:
return;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
return;
case SCHEDULER_MTDS:
local_timeout_queue_process_promotions();
@ -407,6 +439,9 @@ scheduler_idle_loop()
/* Clear the cleanup queue */
local_cleanup_queue_free();
/* Improve the performance of spin-wait loops (works only if preemptions enabled) */
if (runtime_worker_spinloop_pause_enabled) pause();
}
}

@ -2,10 +2,11 @@
enum SCHEDULER
{
SCHEDULER_FIFO = 0,
SCHEDULER_EDF = 1,
SCHEDULER_MTDS = 2,
SCHEDULER_MTDBF = 3
SCHEDULER_FIFO,
SCHEDULER_EDF,
SCHEDULER_SJF,
SCHEDULER_MTDS,
SCHEDULER_MTDBF
};
extern enum SCHEDULER scheduler;

@ -5,8 +5,8 @@
#include <stdint.h>
#include "debuglog.h"
#include "wasm_types.h"
#include "sledge_abi.h"
#include "wasm_types.h"
struct sledge_abi_symbols {
void *handle;

@ -1,7 +1,7 @@
#pragma once
#include <stdatomic.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdlib.h>
#include "worker_thread.h"

@ -3,10 +3,10 @@
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdint.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include "debuglog.h"

@ -1,7 +1,7 @@
#pragma once
#include <assert.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
@ -9,8 +9,8 @@
#include <unistd.h>
#include "debuglog.h"
#include "panic.h"
#include "likely.h"
#include "panic.h"
static inline void
tcp_session_close(int client_socket, struct sockaddr *client_address)
@ -21,7 +21,7 @@ tcp_session_close(int client_socket, struct sockaddr *client_address)
assert(client_socket != STDERR_FILENO);
if (unlikely(close(client_socket) < 0)) {
char client_address_text[INET6_ADDRSTRLEN] = { '\0' };
char client_address_text[INET6_ADDRSTRLEN] = {'\0'};
if (unlikely(inet_ntop(AF_INET, &client_address, client_address_text, INET6_ADDRSTRLEN) == NULL)) {
debuglog("Failed to log client_address: %s", strerror(errno));
}

@ -45,8 +45,10 @@ tenant_config_print(struct tenant_config *config)
{
printf("[Tenant] Name: %s\n", config->name);
printf("[Tenant] Path: %d\n", config->port);
printf("[Tenant] Replenishment Period (us): %u\n", config->replenishment_period_us);
printf("[Tenant] Max Budget (us): %u\n", config->max_budget_us);
if (scheduler == SCHEDULER_MTDS) {
printf("[Tenant] Replenishment Period (us): %u\n", config->replenishment_period_us);
printf("[Tenant] Max Budget (us): %u\n", config->max_budget_us);
}
printf("[Tenant] Routes Size: %zu\n", config->routes_len);
for (int i = 0; i < config->routes_len; i++) { route_config_print(&config->routes[i]); }
}
@ -71,19 +73,19 @@ tenant_config_validate(struct tenant_config *config, bool *did_set)
if (scheduler == SCHEDULER_MTDS) {
if (did_set[tenant_config_member_replenishment_period_us] == false) {
fprintf(stderr, "replenishment-period-us field is required\n");
return -1;
fprintf(stderr, "replenishment-period-us field is missing, so defaulting to 0\n");
config->replenishment_period_us = 0;
}
if (config->replenishment_period_us > (uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX) {
fprintf(stderr, "Relative-deadline-us must be between 0 and %u, was %u\n",
fprintf(stderr, "relative-deadline-us must be between 0 and %u, was %u\n",
(uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX, config->replenishment_period_us);
return -1;
}
if (did_set[tenant_config_member_max_budget_us] == false) {
fprintf(stderr, "max-budget-us field is required\n");
return -1;
fprintf(stderr, "max-budget-us field is missing, so defaulting to 0\n");
config->max_budget_us = 0;
}
if (config->max_budget_us > (uint32_t)RUNTIME_RELATIVE_DEADLINE_US_MAX) {

@ -9,8 +9,8 @@
#include "route_config_parse.h"
#include "tenant_config.h"
static const char *tenant_config_json_keys[tenant_config_member_len] = { "name", "port", "replenishment-period-us",
"max-budget-us", "routes" };
static const char *tenant_config_json_keys[tenant_config_member_len] = {"name", "port", "replenishment-period-us",
"max-budget-us", "routes"};
static inline int
tenant_config_set_key_once(bool *did_set, enum tenant_config_member member)
@ -29,8 +29,8 @@ tenant_config_parse(struct tenant_config *config, const char *json_buf, jsmntok_
int tokens_size)
{
int i = tokens_base;
char key[32] = { 0 };
bool did_set[tenant_config_member_len] = { false };
char key[32] = {0};
bool did_set[tenant_config_member_len] = {false};
if (!has_valid_type(tokens[i], "Anonymous Tenant Config Object", JSMN_OBJECT, json_buf)) return -1;
if (!is_nonempty_object(tokens[i], "Anonymous Tenant Config Object")) return -1;

@ -3,16 +3,15 @@
#include <stdint.h>
#include <string.h>
#include "admissions_info.h"
#include "http.h"
#include "listener_thread.h"
#include "module_database.h"
#include "panic.h"
#include "priority_queue.h"
#include "sandbox_functions.h"
#include "scheduler_options.h"
#include "tenant.h"
#include "tenant_config.h"
#include "priority_queue.h"
#include "sandbox_functions.h"
int tenant_database_add(struct tenant *tenant);
struct tenant *tenant_database_find_by_name(char *name);
@ -30,6 +29,7 @@ tenant_policy_specific_init(struct tenant *tenant, struct tenant_config *config)
case SCHEDULER_FIFO:
break;
case SCHEDULER_EDF:
case SCHEDULER_SJF:
break;
case SCHEDULER_MTDS:
/* Deferable Server Initialization */
@ -103,7 +103,7 @@ tenant_alloc(struct tenant_config *config)
struct module *module = module_database_find_by_path(&tenant->module_db, config->routes[i].path);
if (module == NULL) {
/* Ownership of path moves here */
module = module_alloc(config->routes[i].path);
module = module_alloc(config->routes[i].path, APP_MODULE);
if (module != NULL) {
module_database_add(&tenant->module_db, module);
config->routes[i].path = NULL;
@ -115,8 +115,30 @@ tenant_alloc(struct tenant_config *config)
assert(module != NULL);
struct module *module_proprocess = NULL;
#ifdef EXECUTION_REGRESSION
if (config->routes[i].path_preprocess) {
module_proprocess = module_database_find_by_path(&tenant->module_db,
config->routes[i].path_preprocess);
if (module_proprocess == NULL) {
/* Ownership of path moves here */
module_proprocess = module_alloc(config->routes[i].path_preprocess, PREPROCESS_MODULE);
if (module_proprocess != NULL) {
module_database_add(&tenant->module_db, module_proprocess);
config->routes[i].path_preprocess = NULL;
}
} else {
free(config->routes[i].path_preprocess);
config->routes[i].path_preprocess = NULL;
}
assert(module_proprocess != NULL);
}
#endif
/* Ownership of config's route and http_resp_content_type move here */
int rc = http_router_add_route(&tenant->router, &config->routes[i], module);
int rc = http_router_add_route(&tenant->router, &config->routes[i], module, module_proprocess);
if (unlikely(rc != 0)) {
panic("Tenant %s defined %lu routes, but router failed to grow beyond %lu\n", tenant->name,
config->routes_len, tenant->router.capacity);
@ -160,5 +182,6 @@ get_next_timeout_of_tenant(uint64_t replenishment_period)
* @param tenant
* @returns 0 on success, -1 on error
*/
int tenant_listen(struct tenant *tenant);
int listener_thread_register_tenant(struct tenant *tenant);
int tenant_listen(struct tenant *tenant);
int listener_thread_register_tenant(struct tenant *tenant);
void tenant_preprocess(struct http_session *session);

@ -85,9 +85,9 @@ wasm_globals_set_i32(struct vec_wasm_global_t *globals, uint32_t idx, int32_t va
wasm_global_t *current = vec_wasm_global_t_get(globals, idx);
if (unlikely(current->type != WASM_GLOBAL_TYPE_UNUSED && current->mut == false)) return -2;
int rc = vec_wasm_global_t_insert(globals, idx,
(wasm_global_t){
.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I32, .value = value });
int rc =
vec_wasm_global_t_insert(globals, idx,
(wasm_global_t){.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I32, .value = value});
return rc;
}
@ -99,8 +99,8 @@ wasm_globals_set_i64(struct vec_wasm_global_t *globals, uint32_t idx, int64_t va
if (unlikely(current->type != WASM_GLOBAL_TYPE_UNUSED && current->mut == false)) return -2;
// Returns -1 if idx > capacity
int rc = vec_wasm_global_t_insert(globals, idx,
(wasm_global_t){
.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I64, .value = value });
int rc =
vec_wasm_global_t_insert(globals, idx,
(wasm_global_t){.mut = is_mutable, .type = WASM_GLOBAL_TYPE_I64, .value = value});
return rc;
}

@ -8,8 +8,8 @@
#include <sys/mman.h>
#include "ps_list.h"
#include "types.h" /* PAGE_SIZE */
#include "sledge_abi.h"
#include "types.h" /* PAGE_SIZE */
#include "wasm_types.h"
#define WASM_MEMORY_MAX (uint64_t) UINT32_MAX + 1

@ -1,7 +1,7 @@
#pragma once
#include "sledge_abi.h"
#include "wasm_memory.h"
#include "wasm_table.h"
#include "sledge_abi.h"
/* This structure is the runtime representation of the unique state of a module instance
* Currently this is not spec-compliant, as it only supports a single table and a single memory and it excludes many

@ -2,9 +2,9 @@
#include <stdint.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <strings.h>
#include <sys/mman.h>
#include "ps_list.h"
#include "types.h"

@ -109,5 +109,5 @@ wasm_table_set(struct sledge_abi__wasm_table *wasm_table, uint32_t idx, uint32_t
/* TODO: atomic for multiple concurrent invocations? Issue #97 */
if (wasm_table->buffer[idx].type_id == type_id && wasm_table->buffer[idx].func_pointer == pointer) return;
wasm_table->buffer[idx] = (struct sledge_abi__wasm_table_entry){ .type_id = type_id, .func_pointer = pointer };
wasm_table->buffer[idx] = (struct sledge_abi__wasm_table_entry){.type_id = type_id, .func_pointer = pointer};
}

@ -8,6 +8,8 @@
#include "panic.h"
#include "runtime.h"
#ifdef ADMISSIONS_CONTROL
/*
* Unitless estimate of the instantaneous fraction of system capacity required to complete all previously
* admitted work. This is used to calculate free capacity as part of admissions control
@ -19,40 +21,32 @@
* success or failure)
*/
#ifdef ADMISSIONS_CONTROL
_Atomic uint64_t admissions_control_admitted;
uint64_t admissions_control_capacity;
const double admissions_control_overhead = 0.2;
#endif
void
admissions_control_initialize()
{
#ifdef ADMISSIONS_CONTROL
atomic_init(&admissions_control_admitted, 0);
admissions_control_capacity = runtime_worker_threads_count * ADMISSIONS_CONTROL_GRANULARITY
* ((double)1.0 - admissions_control_overhead);
#endif
}
void
admissions_control_add(uint64_t admissions_estimate)
{
#ifdef ADMISSIONS_CONTROL
assert(admissions_estimate > 0);
atomic_fetch_add(&admissions_control_admitted, admissions_estimate);
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Runtime Admitted: %lu / %lu\n", admissions_control_admitted, admissions_control_capacity);
#endif
#endif /* ADMISSIONS_CONTROL */
}
void
admissions_control_subtract(uint64_t admissions_estimate)
{
#ifdef ADMISSIONS_CONTROL
/* Assumption: Should never underflow */
if (unlikely(admissions_estimate > admissions_control_admitted)) panic("Admissions Estimate underflow\n");
@ -61,14 +55,11 @@ admissions_control_subtract(uint64_t admissions_estimate)
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Runtime Admitted: %lu / %lu\n", admissions_control_admitted, admissions_control_capacity);
#endif
#endif /* ADMISSIONS_CONTROL */
}
uint64_t
admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t relative_deadline)
{
#ifdef ADMISSIONS_CONTROL
assert(relative_deadline != 0);
uint64_t admissions_estimate = (estimated_execution * (uint64_t)ADMISSIONS_CONTROL_GRANULARITY)
/ relative_deadline;
@ -76,31 +67,15 @@ admissions_control_calculate_estimate(uint64_t estimated_execution, uint64_t rel
panic("Ratio of Deadline to Execution time cannot exceed %d\n", ADMISSIONS_CONTROL_GRANULARITY);
return admissions_estimate;
#else
return 0;
#endif
}
uint64_t
admissions_control_calculate_estimate_us(uint32_t estimated_execution_us, uint32_t relative_deadline_us)
{
#ifdef ADMISSIONS_CONTROL
assert(relative_deadline_us != 0);
return (uint64_t)((uint64_t)(estimated_execution_us * ADMISSIONS_CONTROL_GRANULARITY)) / relative_deadline_us;
#else
return 0;
#endif
}
void
admissions_control_log_decision(uint64_t admissions_estimate, bool admitted)
{
#ifdef ADMISSIONS_CONTROL
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Admitted: %lu, Capacity: %lu, Estimate: %lu, Admitted? %s\n", admissions_control_admitted,
admissions_control_capacity, admissions_estimate, admitted ? "yes" : "no");
#endif /* LOG_ADMISSIONS_CONTROL */
#endif /* ADMISSIONS_CONTROL */
}
uint64_t
@ -108,7 +83,6 @@ admissions_control_decide(uint64_t admissions_estimate)
{
uint64_t work_admitted = 1; /* Nominal non-zero value in case admissions control is disabled */
#ifdef ADMISSIONS_CONTROL
if (unlikely(admissions_estimate == 0)) panic("Admissions estimate should never be zero");
uint64_t total_admitted = atomic_load(&admissions_control_admitted);
@ -121,7 +95,8 @@ admissions_control_decide(uint64_t admissions_estimate)
admissions_control_add(admissions_estimate);
work_admitted = admissions_estimate;
}
#endif /* ADMISSIONS_CONTROL */
return work_admitted;
}
#endif /* ADMISSIONS_CONTROL */

@ -1,56 +0,0 @@
#include "admissions_control.h"
#include "admissions_info.h"
#include "debuglog.h"
#include "perf_window.h"
/**
* Initializes perf window
* @param admissions_info
*/
void
admissions_info_initialize(struct admissions_info *admissions_info, uint8_t percentile, uint64_t expected_execution,
uint64_t relative_deadline)
{
#ifdef ADMISSIONS_CONTROL
assert(relative_deadline > 0);
assert(expected_execution > 0);
admissions_info->relative_deadline = relative_deadline;
admissions_info->estimate = admissions_control_calculate_estimate(expected_execution, relative_deadline);
debuglog("Initial Estimate: %lu\n", admissions_info->estimate);
assert(admissions_info != NULL);
perf_window_initialize(&admissions_info->perf_window);
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid admissions percentile");
admissions_info->percentile = percentile;
admissions_info->control_index = PERF_WINDOW_CAPACITY * percentile / 100;
#ifdef LOG_ADMISSIONS_CONTROL
debuglog("Percentile: %u\n", admissions_info->percentile);
debuglog("Control Index: %d\n", admissions_info->control_index);
#endif
#endif
}
/*
* Adds an execution value to the perf window and calculates and caches and updated estimate
* @param admissions_info
* @param execution_duration
*/
void
admissions_info_update(struct admissions_info *admissions_info, uint64_t execution_duration)
{
#ifdef ADMISSIONS_CONTROL
struct perf_window *perf_window = &admissions_info->perf_window;
lock_node_t node = {};
lock_lock(&perf_window->lock, &node);
perf_window_add(perf_window, execution_duration);
uint64_t estimated_execution = perf_window_get_percentile(perf_window, admissions_info->percentile,
admissions_info->control_index);
admissions_info->estimate = admissions_control_calculate_estimate(estimated_execution,
admissions_info->relative_deadline);
lock_unlock(&perf_window->lock, &node);
#endif
}

@ -1,15 +1,14 @@
#include <threads.h>
#include <setjmp.h>
#include <threads.h>
#include "current_sandbox.h"
#include "sandbox_functions.h"
#include "sandbox_set_as_asleep.h"
#include "sandbox_set_as_complete.h"
#include "sandbox_set_as_error.h"
#include "sandbox_set_as_returned.h"
#include "sandbox_set_as_complete.h"
#include "sandbox_set_as_running_user.h"
#include "sandbox_set_as_running_sys.h"
#include "sandbox_set_as_running_user.h"
#include "scheduler.h"
#include "software_interrupt.h"
#include "wasi.h"
@ -194,5 +193,5 @@ current_sandbox_start(void)
current_sandbox_wasm_trap_handler(rc);
}
current_sandbox_fini();
if (sandbox->module->type == APP_MODULE) current_sandbox_fini();
}

@ -1,20 +1,20 @@
#include <stdlib.h>
#include "current_sandbox.h"
#include "wasm_module_instance.h"
#include "wasm_memory.h"
#include "wasm_module_instance.h"
thread_local struct wasm_module_instance sledge_abi__current_wasm_module_instance = {
.abi.memory =
(struct sledge_abi__wasm_memory){
.size = 0,
.max = 0,
.capacity = 0,
.buffer = NULL,
},
.abi.table = NULL,
.abi.wasmg_0 = 0xDEADBEEF,
.wasi_context = NULL,
.abi.memory =
(struct sledge_abi__wasm_memory){
.size = 0,
.max = 0,
.capacity = 0,
.buffer = NULL,
},
.abi.table = NULL,
.abi.wasmg_0 = 0xDEADBEEF,
.wasi_context = NULL,
};
void

@ -0,0 +1,50 @@
#ifdef EXECUTION_HISTOGRAM
#include "execution_histogram.h"
#include "debuglog.h"
#include "perf_window.h"
/**
* Initializes execution_histogram and its perf window
* @param execution_histogram
*/
void
execution_histogram_initialize(struct execution_histogram *execution_histogram, uint8_t percentile,
uint64_t expected_execution)
{
assert(expected_execution > 0);
execution_histogram->estimated_execution = expected_execution;
assert(execution_histogram != NULL);
perf_window_initialize(&execution_histogram->perf_window);
if (unlikely(percentile < 50 || percentile > 99)) panic("Invalid percentile");
execution_histogram->percentile = percentile;
execution_histogram->control_index = PERF_WINDOW_CAPACITY * percentile / 100;
#ifdef LOG_EXECUTION_HISTOGRAM
debuglog("Percentile: %u\n", execution_histogram->percentile);
debuglog("Control Index: %d\n", execution_histogram->control_index);
#endif
}
/*
* Adds an execution value to the perf window
* @param execution_histogram
* @param execution_duration
*/
void
execution_histogram_update(struct execution_histogram *execution_histogram, uint64_t execution_duration)
{
struct perf_window *perf_window = &execution_histogram->perf_window;
lock_node_t node = {};
lock_lock(&perf_window->lock, &node);
perf_window_add(perf_window, execution_duration);
uint64_t estimated_execution = perf_window_get_percentile(perf_window, execution_histogram->percentile,
execution_histogram->control_index);
execution_histogram->estimated_execution = estimated_execution;
lock_unlock(&perf_window->lock, &node);
}
#endif

@ -24,9 +24,9 @@ uninitialized_peek()
/* The global of our polymorphic interface */
static struct global_request_scheduler_config global_request_scheduler = { .add_fn = uninitialized_add,
.remove_fn = uninitialized_remove,
.peek_fn = uninitialized_peek };
static struct global_request_scheduler_config global_request_scheduler = {.add_fn = uninitialized_add,
.remove_fn = uninitialized_remove,
.peek_fn = uninitialized_peek};
/**
* Initializes the polymorphic interface with a concrete implementation

@ -1,8 +1,8 @@
#include "global_request_scheduler.h"
#include "global_request_scheduler_deque.h"
#include "global_request_scheduler.h"
#include "runtime.h"
#define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 19)
#define GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY (1 << 12)
static struct deque_sandbox *global_request_scheduler_deque;
@ -57,11 +57,10 @@ global_request_scheduler_deque_initialize()
deque_init_sandbox(global_request_scheduler_deque, GLOBAL_REQUEST_SCHEDULER_DEQUE_CAPACITY);
/* Register Function Pointers for Abstract Scheduling API */
struct global_request_scheduler_config config = {
.add_fn = global_request_scheduler_deque_add,
.remove_fn = global_request_scheduler_deque_remove,
.remove_if_earlier_fn = global_request_scheduler_deque_remove_if_earlier
};
struct global_request_scheduler_config config = {.add_fn = global_request_scheduler_deque_add,
.remove_fn = global_request_scheduler_deque_remove,
.remove_if_earlier_fn =
global_request_scheduler_deque_remove_if_earlier};
global_request_scheduler_initialize(&config);
}

@ -43,10 +43,10 @@ global_request_scheduler_minheap_remove(struct sandbox **removed_sandbox)
* @returns 0 if successful, -ENOENT if empty or if request isn't earlier than target_deadline
*/
int
global_request_scheduler_minheap_remove_if_earlier(struct sandbox **removed_sandbox, uint64_t target_deadline)
global_request_scheduler_minheap_remove_if_earlier(struct sandbox **removed_sandbox, uint64_t target_latest_start)
{
return priority_queue_dequeue_if_earlier(global_request_scheduler_minheap, (void **)removed_sandbox,
target_deadline);
target_latest_start);
}
/**
@ -65,6 +65,8 @@ uint64_t
sandbox_get_priority_fn(void *element)
{
struct sandbox *sandbox = (struct sandbox *)element;
if (scheduler == SCHEDULER_SJF) return sandbox->remaining_exec;
assert(scheduler == SCHEDULER_EDF);
return sandbox->absolute_deadline;
};
@ -77,12 +79,11 @@ global_request_scheduler_minheap_initialize()
{
global_request_scheduler_minheap = priority_queue_initialize(4096, true, sandbox_get_priority_fn);
struct global_request_scheduler_config config = {
.add_fn = global_request_scheduler_minheap_add,
.remove_fn = global_request_scheduler_minheap_remove,
.remove_if_earlier_fn = global_request_scheduler_minheap_remove_if_earlier,
.peek_fn = global_request_scheduler_minheap_peek
};
struct global_request_scheduler_config config = {.add_fn = global_request_scheduler_minheap_add,
.remove_fn = global_request_scheduler_minheap_remove,
.remove_if_earlier_fn =
global_request_scheduler_minheap_remove_if_earlier,
.peek_fn = global_request_scheduler_minheap_peek};
global_request_scheduler_initialize(&config);
}

@ -230,12 +230,11 @@ global_request_scheduler_mtds_initialize()
lock_init(&global_lock);
struct global_request_scheduler_config config = {
.add_fn = global_request_scheduler_mtds_add,
.remove_fn = global_request_scheduler_mtds_remove,
.remove_if_earlier_fn = global_request_scheduler_mtds_remove_if_earlier,
.peek_fn = global_request_scheduler_mtds_peek
};
struct global_request_scheduler_config config = {.add_fn = global_request_scheduler_mtds_add,
.remove_fn = global_request_scheduler_mtds_remove,
.remove_if_earlier_fn =
global_request_scheduler_mtds_remove_if_earlier,
.peek_fn = global_request_scheduler_mtds_peek};
global_request_scheduler_initialize(&config);
}

@ -3,8 +3,8 @@
#include "debuglog.h"
#include "http.h"
#include "http_request.h"
#include "http_parser_settings.h"
#include "http_request.h"
#include "likely.h"
http_parser_settings runtime_http_parser_settings;
@ -211,7 +211,7 @@ http_parser_settings_on_header_end(http_parser *parser)
}
}
const char *http_methods[] = { "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" };
const char *http_methods[] = {"OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT"};
/**
* http-parser callback called for HTTP Bodies

@ -18,8 +18,8 @@ http_session_perf_log_print_entry(struct http_session *http_session)
const uint64_t sent_duration = http_session->response_sent_timestamp - http_session->response_takeoff_timestamp;
const uint64_t total_lifetime = http_session->response_sent_timestamp - http_session->request_arrival_timestamp;
fprintf(http_session_perf_log, "%s,%s,%u,%lu,%lu,%lu,%lu,%lu,%u\n", http_session->tenant->name,
fprintf(http_session_perf_log, "%s,%s,%u,%lu,%lu,%lu,%lu,%lu,%lu,%u\n", http_session->tenant->name,
http_session->http_request.full_url, http_session->state, http_session->response_header_written,
http_session->response_body_written, receive_duration, sent_duration, total_lifetime,
runtime_processor_speed_MHz);
http_session->preprocessing_duration, runtime_processor_speed_MHz);
}

@ -112,8 +112,10 @@ wasi_context_init(wasi_options_t *options)
}
}
/* Seed Random */
srandom(time(NULL));
/* Seed Random
* Commented out as a temporary fix for the mutex blocking delay srandom causes in libc.
*/
// srandom(time(NULL));
/* TODO: Preopens */

@ -2,16 +2,18 @@
#include <unistd.h>
#include "arch/getcycles.h"
#include "execution_regression.h"
#include "global_request_scheduler.h"
#include "http_session_perf_log.h"
#include "listener_thread.h"
#include "metrics_server.h"
#include "module.h"
#include "runtime.h"
#include "sandbox_functions.h"
#include "sandbox_perf_log.h"
#include "tcp_session.h"
#include "tenant.h"
#include "tenant_functions.h"
#include "http_session_perf_log.h"
static void listener_thread_unregister_http_session(struct http_session *http);
static void panic_on_epoll_error(struct epoll_event *evt);
@ -193,11 +195,34 @@ on_client_request_receiving(struct http_session *session)
{
/* Read HTTP request */
int rc = http_session_receive_request(session, (void_star_cb)listener_thread_register_http_session);
if (likely(rc == 0)) {
/* Check if the route is accurate only when the URL is downloaded. Stop downloading if inaccurate. */
if (session->route == NULL && strlen(session->http_request.full_url) > 0) {
struct route *route = http_router_match_route(&session->tenant->router, session->http_request.full_url);
if (route == NULL) {
debuglog("Did not match any routes\n");
session->state = HTTP_SESSION_EXECUTION_COMPLETE;
http_session_set_response_header(session, 404);
on_client_response_header_sending(session);
return;
}
session->route = route;
}
if (rc == 0) {
#ifdef EXECUTION_REGRESSION
if (!session->did_preprocessing) tenant_preprocess(session);
#endif
on_client_request_received(session);
return;
} else if (unlikely(rc == -EAGAIN)) {
/* session blocked and registered to epoll so continue to next handle */
} else if (rc == -EAGAIN) {
/* session blocked and registered to epoll, so continue to next handle */
#ifdef EXECUTION_REGRESSION
/* try tenant preprocessing if min 4k Bytes received */
if (!session->did_preprocessing && session->http_request.body_length_read > 4096)
tenant_preprocess(session);
#endif
return;
} else if (rc < 0) {
debuglog("Failed to receive or parse request\n");
@ -215,30 +240,29 @@ on_client_request_received(struct http_session *session)
{
assert(session->state == HTTP_SESSION_RECEIVED_REQUEST);
session->request_downloaded_timestamp = __getcycles();
struct route *route = session->route;
uint64_t estimated_execution = route->execution_histogram.estimated_execution;
uint64_t work_admitted = 1;
struct route *route = http_router_match_route(&session->tenant->router, session->http_request.full_url);
if (route == NULL) {
debuglog("Did not match any routes\n");
session->state = HTTP_SESSION_EXECUTION_COMPLETE;
http_session_set_response_header(session, 404);
on_client_response_header_sending(session);
return;
}
session->route = route;
#ifdef EXECUTION_REGRESSION
estimated_execution = get_regression_prediction(session);
#endif
#ifdef ADMISSIONS_CONTROL
/*
* Perform admissions control.
* If 0, workload was rejected, so close with 429 "Too Many Requests" and continue
* TODO: Consider providing a Retry-After header
*/
uint64_t work_admitted = admissions_control_decide(route->admissions_info.estimate);
uint64_t admissions_estimate = admissions_control_calculate_estimate(estimated_execution,
route->relative_deadline);
work_admitted = admissions_control_decide(admissions_estimate);
if (work_admitted == 0) {
session->state = HTTP_SESSION_EXECUTION_COMPLETE;
http_session_set_response_header(session, 429);
on_client_response_header_sending(session);
return;
}
#endif
/* Allocate a Sandbox */
session->state = HTTP_SESSION_EXECUTING;
@ -251,9 +275,15 @@ on_client_request_received(struct http_session *session)
return;
}
sandbox->remaining_exec = estimated_execution;
/* If the global request scheduler is full, return a 429 to the client */
if (unlikely(global_request_scheduler_add(sandbox) == NULL)) {
debuglog("Failed to add sandbox to global queue\n");
// debuglog("Failed to add sandbox to global queue\n");
sandbox->response_code = 4290;
sandbox->state = SANDBOX_ERROR;
sandbox_perf_log_print_entry(sandbox);
sandbox->http = NULL;
sandbox_free(sandbox);
session->state = HTTP_SESSION_EXECUTION_COMPLETE;
http_session_set_response_header(session, 429);

@ -2,8 +2,8 @@
#include "current_sandbox.h"
#include "global_request_scheduler.h"
#include "local_runqueue_list.h"
#include "local_runqueue.h"
#include "local_runqueue_list.h"
#include "sandbox_functions.h"
thread_local static struct ps_list_head local_runqueue_list;
@ -81,9 +81,9 @@ local_runqueue_list_initialize()
ps_list_head_init(&local_runqueue_list);
/* Register Function Pointers for Abstract Scheduling API */
struct local_runqueue_config config = { .add_fn = local_runqueue_list_append,
.is_empty_fn = local_runqueue_list_is_empty,
.delete_fn = local_runqueue_list_remove,
.get_next_fn = local_runqueue_list_get_next };
struct local_runqueue_config config = {.add_fn = local_runqueue_list_append,
.is_empty_fn = local_runqueue_list_is_empty,
.delete_fn = local_runqueue_list_remove,
.get_next_fn = local_runqueue_list_get_next};
local_runqueue_initialize(&config);
};

@ -9,8 +9,8 @@
#include "local_runqueue_minheap.h"
#include "panic.h"
#include "priority_queue.h"
#include "sandbox_functions.h"
#include "runtime.h"
#include "sandbox_functions.h"
thread_local static struct priority_queue *local_runqueue_minheap;
@ -84,10 +84,10 @@ local_runqueue_minheap_initialize()
local_runqueue_minheap = priority_queue_initialize(RUNTIME_RUNQUEUE_SIZE, false, sandbox_get_priority);
/* Register Function Pointers for Abstract Scheduling API */
struct local_runqueue_config config = { .add_fn = local_runqueue_minheap_add,
.is_empty_fn = local_runqueue_minheap_is_empty,
.delete_fn = local_runqueue_minheap_delete,
.get_next_fn = local_runqueue_minheap_get_next };
struct local_runqueue_config config = {.add_fn = local_runqueue_minheap_add,
.is_empty_fn = local_runqueue_minheap_is_empty,
.delete_fn = local_runqueue_minheap_delete,
.get_next_fn = local_runqueue_minheap_get_next};
local_runqueue_initialize(&config);
}

@ -9,9 +9,9 @@
#include "local_runqueue_mtds.h"
#include "panic.h"
#include "priority_queue.h"
#include "runtime.h"
#include "sandbox_functions.h"
#include "tenant_functions.h"
#include "runtime.h"
thread_local static struct priority_queue *local_runqueue_mtds_guaranteed;
thread_local static struct priority_queue *local_runqueue_mtds_default;
@ -172,10 +172,10 @@ local_runqueue_mtds_initialize()
perworker_tenant_get_priority);
/* Register Function Pointers for Abstract Scheduling API */
struct local_runqueue_config config = { .add_fn = local_runqueue_mtds_add,
.is_empty_fn = local_runqueue_mtds_is_empty,
.delete_fn = local_runqueue_mtds_delete,
.get_next_fn = local_runqueue_mtds_get_next };
struct local_runqueue_config config = {.add_fn = local_runqueue_mtds_add,
.is_empty_fn = local_runqueue_mtds_is_empty,
.delete_fn = local_runqueue_mtds_delete,
.get_next_fn = local_runqueue_mtds_get_next};
local_runqueue_initialize(&config);
}

@ -2,25 +2,25 @@
#include <dlfcn.h>
#include <math.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef LOG_TO_FILE
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif
#include "json_parse.h"
#include "pretty_print.h"
#include "debuglog.h"
#include "json_parse.h"
#include "listener_thread.h"
#include "panic.h"
#include "pretty_print.h"
#include "runtime.h"
#include "sandbox_perf_log.h"
#include "sandbox_types.h"
@ -38,8 +38,9 @@ uint32_t runtime_worker_threads_count = 0;
enum RUNTIME_SIGALRM_HANDLER runtime_sigalrm_handler = RUNTIME_SIGALRM_HANDLER_BROADCAST;
bool runtime_preemption_enabled = true;
uint32_t runtime_quantum_us = 5000; /* 5ms */
bool runtime_preemption_enabled = true;
bool runtime_worker_spinloop_pause_enabled = false;
uint32_t runtime_quantum_us = 1000; /* 1ms */
uint64_t runtime_boot_timestamp;
pid_t runtime_pid = 0;
@ -101,32 +102,48 @@ runtime_allocate_available_cores()
* We are also assuming this value is static
* @return proceccor speed in MHz
*/
static inline uint32_t
static inline void
runtime_get_processor_speed_MHz(void)
{
uint32_t return_value;
char *proc_mhz_raw = getenv("SLEDGE_PROC_MHZ");
FILE *cmd = NULL;
FILE *cmd = popen("grep '^cpu MHz' /proc/cpuinfo | head -n 1 | awk '{print $4}'", "r");
if (unlikely(cmd == NULL)) goto err;
char buff[16];
size_t n = fread(buff, 1, sizeof(buff) - 1, cmd);
if (unlikely(n <= 0)) goto err;
buff[n] = '\0';
float processor_speed_MHz;
n = sscanf(buff, "%f", &processor_speed_MHz);
if (unlikely(n != 1)) goto err;
if (unlikely(processor_speed_MHz < 0)) goto err;
if (proc_mhz_raw != NULL) {
/* The case with manual override for the CPU freq */
runtime_processor_speed_MHz = atoi(proc_mhz_raw);
} else {
/* The case when we have to get CPU freq from */
usleep(200000); /* wait a bit for the workers to launch for more accuracy */
/* Get the average of the cpufreqs only for worker cores (no event core and reserved) */
char command[128] = {0};
sprintf(command, "grep '^cpu MHz' /proc/cpuinfo | sed -n '%u,%up' | \
awk '{ total += $4; count++ } END { print total/count }'",
runtime_first_worker_processor + 1,
runtime_first_worker_processor + runtime_worker_threads_count);
cmd = popen(command, "r");
if (unlikely(cmd == NULL)) goto err;
char buff[16];
size_t n = fread(buff, 1, sizeof(buff) - 1, cmd);
buff[n] = '\0';
pclose(cmd);
float processor_speed_MHz;
n = sscanf(buff, "%f", &processor_speed_MHz);
if (unlikely(n != 1)) goto err;
if (unlikely(processor_speed_MHz < 0)) goto err;
runtime_processor_speed_MHz = (uint32_t)nearbyintf(processor_speed_MHz);
}
return_value = (uint32_t)nearbyintf(processor_speed_MHz);
pretty_print_key_value("Worker CPU Freq", "%u MHz\n", runtime_processor_speed_MHz);
done:
pclose(cmd);
return return_value;
return;
err:
return_value = 0;
goto done;
panic("Failed to detect processor frequency");
}
/**
@ -191,10 +208,12 @@ runtime_configure()
scheduler = SCHEDULER_MTDS;
} else if (strcmp(scheduler_policy, "EDF") == 0) {
scheduler = SCHEDULER_EDF;
} else if (strcmp(scheduler_policy, "SJF") == 0) {
scheduler = SCHEDULER_SJF;
} else if (strcmp(scheduler_policy, "FIFO") == 0) {
scheduler = SCHEDULER_FIFO;
} else {
panic("Invalid scheduler policy: %s. Must be {MTDBF|MTDS|EDF|FIFO}\n", scheduler_policy);
panic("Invalid scheduler policy: %s. Must be {MTDBF|MTDS|EDF|SJF|FIFO}\n", scheduler_policy);
}
pretty_print_key_value("Scheduler Policy", "%s\n", scheduler_print(scheduler));
@ -232,6 +251,17 @@ runtime_configure()
http_session_perf_log_init();
}
void
runtime_configure_worker_spinloop_pause()
{
/* Runtime Worker-Spinloop-Pause Toggle */
char *pause_enable = getenv("SLEDGE_SPINLOOP_PAUSE_ENABLED");
if (pause_enable != NULL && strcmp(pause_enable, "true") == 0) runtime_worker_spinloop_pause_enabled = true;
pretty_print_key_value("Worker-Spinloop-Pause", "%s\n",
runtime_worker_spinloop_pause_enabled ? PRETTY_PRINT_GREEN_ENABLED
: PRETTY_PRINT_RED_DISABLED);
}
void
log_compiletime_config()
{
@ -256,6 +286,18 @@ log_compiletime_config()
pretty_print_key_disabled("Admissions Control");
#endif
#ifdef EXECUTION_HISTOGRAM
pretty_print_key_enabled("Execution Histogram");
#else
pretty_print_key_disabled("Execution Histogram");
#endif
#ifdef EXECUTION_REGRESSION
pretty_print_key_enabled("Execution Regression");
#else
pretty_print_key_disabled("Execution Regression");
#endif
/* Debugging Flags */
printf("Static Compiler Flags (Debugging):\n");
@ -448,13 +490,6 @@ main(int argc, char **argv)
printf("Runtime Environment:\n");
runtime_processor_speed_MHz = runtime_get_processor_speed_MHz();
if (unlikely(runtime_processor_speed_MHz == 0)) panic("Failed to detect processor speed\n");
int heading_length = 30;
pretty_print_key_value("Processor Speed", "%u MHz\n", runtime_processor_speed_MHz);
runtime_set_resource_limits_to_max();
runtime_allocate_available_cores();
runtime_configure();
@ -463,6 +498,8 @@ main(int argc, char **argv)
listener_thread_initialize();
runtime_start_runtime_worker_threads();
runtime_get_processor_speed_MHz();
runtime_configure_worker_spinloop_pause();
software_interrupt_arm_timer();
#ifdef LOG_TENANT_LOADING

@ -11,8 +11,8 @@
#include "metrics_server.h"
#include "proc_stat.h"
#include "runtime.h"
#include "sandbox_total.h"
#include "sandbox_state.h"
#include "sandbox_total.h"
#include "tcp_server.h"
/* We run threads on the "reserved OS core" using blocking semantics */

@ -44,7 +44,8 @@ module_init(struct module *module, char *path)
rc = sledge_abi_symbols_init(&module->abi, path);
if (rc != 0) goto err;
module->pools = calloc(runtime_worker_threads_count, sizeof(struct module_pool));
module->pools = calloc((module->type == APP_MODULE ? runtime_worker_threads_count : 1),
sizeof(struct module_pool));
module->path = path;
@ -106,7 +107,7 @@ module_free(struct module *module)
*/
struct module *
module_alloc(char *path)
module_alloc(char *path, enum module_type type)
{
size_t alignment = (size_t)CACHE_PAD;
size_t size_to_alloc = (size_t)round_to_cache_pad(sizeof(struct module));
@ -120,6 +121,7 @@ module_alloc(char *path)
};
memset(module, 0, size_to_alloc);
module->type = type;
int rc = module_init(module, path);
if (rc < 0) goto init_err;

@ -1,14 +1,13 @@
#include <arpa/inet.h>
#include <assert.h>
#include <signal.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <pthread.h>
#include "admissions_control.h"
#include "arch/context.h"
@ -19,10 +18,10 @@
#include "listener_thread.h"
#include "module.h"
#include "runtime.h"
#include "sandbox_perf_log.h"
#include "sandbox_total.h"
#include "scheduler.h"
#include "software_interrupt.h"
#include "sandbox_perf_log.h"
/***************************
* Shared Process State *
@ -63,8 +62,8 @@ runtime_set_resource_limits_to_max()
char lim[uint64_t_max_digits + 1];
char max[uint64_t_max_digits + 1];
uint64_t resources[] = { RLIMIT_DATA, RLIMIT_NOFILE };
char *resource_names[] = { "RLIMIT_DATA", "RLIMIT_NOFILE" };
uint64_t resources[] = {RLIMIT_DATA, RLIMIT_NOFILE};
char *resource_names[] = {"RLIMIT_DATA", "RLIMIT_NOFILE"};
for (int i = 0; i < sizeof(resources) / sizeof(resources[0]); i++) {
int resource = resources[i];
@ -118,7 +117,11 @@ runtime_initialize(void)
signal(SIGQUIT, runtime_cleanup);
http_parser_settings_initialize();
#ifdef ADMISSIONS_CONTROL
/* Admissions Control Setup */
admissions_control_initialize();
#endif
}
static void

@ -8,9 +8,9 @@
#include "pool.h"
#include "runtime.h"
#include "sandbox_functions.h"
#include "sandbox_set_as_allocated.h"
#include "sandbox_set_as_error.h"
#include "sandbox_set_as_initialized.h"
#include "sandbox_set_as_allocated.h"
#include "sandbox_total.h"
#include "wasm_memory.h"
#include "wasm_stack.h"
@ -154,6 +154,8 @@ sandbox_init(struct sandbox *sandbox, struct module *module, struct http_session
sandbox->route = route;
sandbox->absolute_deadline = sandbox->timestamp_of.allocation + sandbox->route->relative_deadline;
sandbox->payload_size = session->http_request.body_length;
sandbox->regression_param = session->regression_param;
/*
* Admissions Control State

@ -9,19 +9,18 @@
const char *sandbox_state_labels[SANDBOX_STATE_COUNT] = {
[SANDBOX_UNINITIALIZED] = "Uninitialized",
[SANDBOX_ALLOCATED] = "Allocated",
[SANDBOX_INITIALIZED] = "Initialized",
[SANDBOX_RUNNABLE] = "Runnable",
[SANDBOX_INTERRUPTED] = "Interrupted",
[SANDBOX_PREEMPTED] = "Preempted",
[SANDBOX_RUNNING_SYS] = "Running Sys",
[SANDBOX_RUNNING_USER] = "Running User",
[SANDBOX_ASLEEP] = "Asleep",
[SANDBOX_RETURNED] = "Returned",
[SANDBOX_COMPLETE] = "Complete",
[SANDBOX_ERROR] = "Error"
};
[SANDBOX_UNINITIALIZED] = "Uninitialized",
[SANDBOX_ALLOCATED] = "Allocated",
[SANDBOX_INITIALIZED] = "Initialized",
[SANDBOX_RUNNABLE] = "Runnable",
[SANDBOX_INTERRUPTED] = "Interrupted",
[SANDBOX_PREEMPTED] = "Preempted",
[SANDBOX_RUNNING_SYS] = "Running Sys",
[SANDBOX_RUNNING_USER] = "Running User",
[SANDBOX_ASLEEP] = "Asleep",
[SANDBOX_RETURNED] = "Returned",
[SANDBOX_COMPLETE] = "Complete",
[SANDBOX_ERROR] = "Error"};
#ifdef SANDBOX_STATE_TOTALS
_Atomic uint32_t sandbox_state_totals[SANDBOX_STATE_COUNT];

@ -9,33 +9,31 @@ sandbox_state_transition_hook_default(struct sandbox *sandbox)
/* Called while nonpreemptable */
sandbox_state_transition_hook_t sandbox_state_transition_to_hooks[SANDBOX_STATE_COUNT] = {
[SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default,
[SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default,
[SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default,
[SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default,
[SANDBOX_ASLEEP] = sandbox_state_transition_hook_default,
[SANDBOX_RETURNED] = sandbox_state_transition_hook_default,
[SANDBOX_COMPLETE] = sandbox_state_transition_hook_default,
[SANDBOX_ERROR] = sandbox_state_transition_hook_default
};
[SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default,
[SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default,
[SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default,
[SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default,
[SANDBOX_ASLEEP] = sandbox_state_transition_hook_default,
[SANDBOX_RETURNED] = sandbox_state_transition_hook_default,
[SANDBOX_COMPLETE] = sandbox_state_transition_hook_default,
[SANDBOX_ERROR] = sandbox_state_transition_hook_default};
/* Called while nonpreemptable */
sandbox_state_transition_hook_t sandbox_state_transition_from_hooks[SANDBOX_STATE_COUNT] = {
[SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default,
[SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default,
[SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default,
[SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default,
[SANDBOX_ASLEEP] = sandbox_state_transition_hook_default,
[SANDBOX_RETURNED] = sandbox_state_transition_hook_default,
[SANDBOX_COMPLETE] = sandbox_state_transition_hook_default,
[SANDBOX_ERROR] = sandbox_state_transition_hook_default
};
[SANDBOX_UNINITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_ALLOCATED] = sandbox_state_transition_hook_default,
[SANDBOX_INITIALIZED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNABLE] = sandbox_state_transition_hook_default,
[SANDBOX_INTERRUPTED] = sandbox_state_transition_hook_default,
[SANDBOX_PREEMPTED] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_SYS] = sandbox_state_transition_hook_default,
[SANDBOX_RUNNING_USER] = sandbox_state_transition_hook_default,
[SANDBOX_ASLEEP] = sandbox_state_transition_hook_default,
[SANDBOX_RETURNED] = sandbox_state_transition_hook_default,
[SANDBOX_COMPLETE] = sandbox_state_transition_hook_default,
[SANDBOX_ERROR] = sandbox_state_transition_hook_default};

@ -1,11 +1,11 @@
#include "sledge_abi.h"
#include "current_sandbox.h"
#include "map.h"
#include "sandbox_set_as_running_sys.h"
#include "sandbox_set_as_running_user.h"
#include "sledge_abi.h"
#include "wasm_memory.h"
#include "wasi.h"
#include "wasi_serdes.h"
#include "wasm_memory.h"
EXPORT void
sledge_abi__wasm_trap_raise(enum sledge_abi__wasm_trap trapno)

@ -1,14 +1,14 @@
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <threads.h>
#include <unistd.h>
#include <ucontext.h>
#include <unistd.h>
#include "arch/context.h"
#include "current_sandbox.h"
@ -18,8 +18,8 @@
#include "module.h"
#include "panic.h"
#include "runtime.h"
#include "sandbox_set_as_running_user.h"
#include "sandbox_set_as_interrupted.h"
#include "sandbox_set_as_running_user.h"
#include "sandbox_types.h"
#include "scheduler.h"
#include "software_interrupt.h"
@ -269,7 +269,7 @@ software_interrupt_initialize(void)
sigaddset(&signal_action.sa_mask, SIGFPE);
sigaddset(&signal_action.sa_mask, SIGSEGV);
const int supported_signals[] = { SIGALRM, SIGUSR1, SIGFPE, SIGSEGV };
const int supported_signals[] = {SIGALRM, SIGUSR1, SIGFPE, SIGSEGV};
const size_t supported_signals_len = 4;
for (int i = 0; i < supported_signals_len; i++) {

@ -1,4 +1,5 @@
#include "tenant.h"
#include "current_sandbox.h"
#include "tenant_functions.h"
/**
@ -23,3 +24,50 @@ err:
rc = -1;
goto done;
}
#ifdef EXECUTION_REGRESSION
void
tenant_preprocess(struct http_session *session)
{
/* No tenant preprocessing if the wasm module not provided by the tenant */
if (session->route->module_proprocess == NULL) goto done;
const uint64_t start = __getcycles();
/* Tenant Pre-processing - Extract other useful parameters */
struct sandbox *pre_sandbox = sandbox_alloc(session->route->module_proprocess, session, session->route,
session->tenant, 1);
if (sandbox_prepare_execution_environment(pre_sandbox)) panic("pre_sandbox environment setup failed");
pre_sandbox->state = SANDBOX_RUNNING_SYS;
assert(current_sandbox_get() == NULL);
current_sandbox_set(pre_sandbox);
current_sandbox_start();
auto_buf_flush(&session->response_body);
char *endptr;
long num = strtol(session->response_body.data, &endptr, 10);
if (endptr == session->response_body.data) {
printf("No digits were found\n");
} else if (*endptr != '\0' && *endptr != '\n') {
printf("Further characters after number: %s\n", endptr);
} else if ((errno == ERANGE && (num == LONG_MAX || num == LONG_MIN)) || (errno != 0 && num == 0)) {
perror("strtol");
} else {
session->regression_param = num;
}
session->http_request.cursor = 0;
pre_sandbox->http = NULL;
pre_sandbox->state = SANDBOX_COMPLETE;
auto_buf_deinit(&session->response_body);
current_sandbox_set(NULL);
sandbox_free_linear_memory(pre_sandbox);
sandbox_free(pre_sandbox);
const uint64_t end = __getcycles();
session->preprocessing_duration = end - start;
done:
session->did_preprocessing = true;
}
#endif

@ -1,14 +1,14 @@
#include <errno.h>
#include "panic.h"
#include "runtime.h"
#include "tenant.h"
#include "panic.h"
/*******************
* Tenant Database *
******************/
struct tenant *tenant_database[RUNTIME_MAX_TENANT_COUNT] = { NULL };
struct tenant *tenant_database[RUNTIME_MAX_TENANT_COUNT] = {NULL};
size_t tenant_database_count = 0;
/**

@ -1,8 +1,8 @@
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <sched.h>
#include <signal.h>
#include <stdlib.h>
#include <threads.h>
@ -12,11 +12,11 @@
#include "local_runqueue_list.h"
#include "local_runqueue_minheap.h"
#include "panic.h"
#include "priority_queue.h"
#include "runtime.h"
#include "scheduler.h"
#include "worker_thread.h"
#include "tenant_functions.h"
#include "priority_queue.h"
#include "worker_thread.h"
/***************************
* Worker Thread State *

@ -9,7 +9,6 @@
PHONY: gocr__by_dpi
gocr__by_dpi: ./runtime/bin/gocr.wasm.so
# cd ./tests/gocr/by_dpi && ./install.sh
cd ./tests/gocr/by_dpi && ./run.sh
PHONY: gocr__by_font

1
tests/.gitignore vendored

@ -1,4 +1,5 @@
res
res-*
perf.data
perf.data.old
samples

@ -14,13 +14,13 @@ debug:
.PHONY: client
client:
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/airplane1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/automobile1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/bird1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/cat1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/deer1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/dog1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/frog1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/horse1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/ship1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: text/plain" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/truck1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/airplane1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/automobile1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/bird1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/cat1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/deer1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/dog1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/frog1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/horse1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/ship1.bmp" "localhost:10000/rand"
@curl -H 'Expect:' -H "Content-Type: image/bmp" --data-binary "@../../../applications/wasm_apps/CMSIS_5_NN/images/bmp/truck1.bmp" "localhost:10000/rand"

@ -63,7 +63,7 @@ run_perf_tests() {
else
image=$same_image
fi
hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -D "${image}" "http://${hostname}:10000${route[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null &
hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -D "${image}" "http://${hostname}:10000${route[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" 2> /dev/null &
done
pids=$(pgrep hey | tr '\n' ' ')
[[ -n $pids ]] && wait -f $pids

@ -2,8 +2,6 @@
{
"name": "gwu",
"port": 10000,
"replenishment-period-us": 0,
"max-budget-us": 0,
"routes": [
{
"route": "/rand",

@ -68,7 +68,7 @@ run_perf_tests() {
done
((batch_id++))
hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m GET -D "./${workload}.dat" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" &
hey -disable-compression -disable-keepalive -disable-redirects -n $batch_size -c 1 -cpus 1 -t 0 -o csv -m POST -D "./${workload}.dat" "http://${hostname}:10000${path[$workload]}" > "$results_directory/${workload}_${batch_id}.csv" &
done
pids=$(pgrep hey | tr '\n' ' ')
[[ -n $pids ]] && wait -f $pids

@ -2,8 +2,6 @@
{
"name": "gwu",
"port": 10000,
"replenishment-period-us": 0,
"max-budget-us": 0,
"routes": [
{
"route": "/ekf_first_iter",

@ -2,8 +2,6 @@
{
"name": "gwu",
"port": 10000,
"replenishment-period-us": 0,
"max-budget-us": 0,
"routes": [
{
"route": "/ekf",

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

Loading…
Cancel
Save