feat: framework cleanup

master
Sean McBride 4 years ago
parent 4ce5ea918d
commit 9d0abbeb64

@ -163,4 +163,4 @@ declare -A port=(
[two_iterations]=10002
)
main "$@"
framework_init "$@"

@ -59,4 +59,4 @@ if [[ ! -f "$__run_sh__base_path/initial_state.dat" ]]; then
popd || exit 1
fi
main "$@"
framework_init "$@"

@ -151,4 +151,4 @@ declare -Ar port=(
# Sort the images by the number of labeled plates
declare -a cifar10_images=(./images/bmp/*)
main "$@"
framework_init "$@"

@ -178,4 +178,4 @@ declare -Ar port=(
[large]=10002
)
main "$@"
framework_init "$@"

@ -63,4 +63,4 @@ if [[ ! -f "./flower.jpg" ]]; then
cp "$__run_sh__project_base_absolute_path/runtime/tests/sod/bin/flower.jpg" ./flower.jpg
fi
main "$@"
framework_init "$@"

@ -165,4 +165,4 @@ while IFS= read -r image_data; do
esac
done < <(ls ./images/*.csv)
main "$@"
framework_init "$@"

@ -112,4 +112,4 @@ experiment_client() {
# Validate that required tools are in path
validate_dependencies curl shuf pango-view pngtopnm diff
main "$@"
framework_init "$@"

@ -115,4 +115,4 @@ experiment_client() {
validate_dependencies curl shuf pango-view pngtopnm diff
main "$@"
framework_init "$@"

@ -119,4 +119,4 @@ experiment_client() {
validate_dependencies curl shuf pango-view pngtopnm diff
main "$@"
framework_init "$@"

@ -51,4 +51,4 @@ experiment_client() {
validate_dependencies curl
main "$@"
framework_init "$@"

@ -49,4 +49,4 @@ experiment_client() {
validate_dependencies curl
main "$@"
framework_init "$@"

@ -48,4 +48,4 @@ experiment_client() {
validate_dependencies curl
main "$@"
framework_init "$@"

@ -3,16 +3,70 @@ if [ -n "$__framework_sh__" ]; then return; fi
__framework_sh__=$(date)
#
# This framework simplifies the scripting of experiments
# This framework simplifies the scripting of experiments.
#
# To use, import the framework source file and pass all arguments to the provided main function
# source "framework.sh"
# It is designed around the idea of static experiments composed of one or more variants expressed by
# environment variables written to .env files. The default behavior is localhost mode, which runs a background
# server daemon and then execute a client driver script. If multiple .env files are defined, the framework
# automatically sets environment variables, starts the runtime as a background process, executes the client driver,
# stops the runtime, and clears the environment variables. The framework allows you to run the same logic on separate
# client and server hosts. It also provides various options to run under perf, gdb, valgrind, etc.
#
# main "$@"
# To keep experiments relatively uniform, I suggest adding a single run.sh file inside your experiment.
#
# In your script, implement the following functions above main:
# - experiment_client
# Your run.sh file should be started with the following snippet, which sources the framework.sh file
# and delegates all external arguments to the framework via the framework_init function. The first few lines are
# used to temporary add the directory containing BASH library scripts to your PATH environment variable. You may
# need to modify __run_sh__bash_libraries_relative_path to adjust the relative path depending on the location
# of your experimental directory.
#
###############################################################################################################################
# #!/bin/bash
# __run_sh__base_path="$(dirname "$(realpath --logical "${BASH_SOURCE[0]}")")"
# __run_sh__bash_libraries_relative_path="../bash_libraries"
# __run_sh__bash_libraries_absolute_path=$(cd "$__run_sh__base_path" && cd "$__run_sh__bash_libraries_relative_path" && pwd)
# export PATH="$__run_sh__bash_libraries_absolute_path:$PATH"
#
# source framework.sh || exit 1
#
# framework_init "$@"
###############################################################################################################################
#
# Use chmod +x run.sh to make your script executable, and then run ./run.sh --help to test it.
# You should see help information if successful.
#
# At this point, your script can run the server with defaults usings the --debug, --perf, --serve, and --valgrind
#
# To run a client or the default localhost mode that runs a client and a server on the same machine, you have to
# implement a function called experiment_client in run.sh above your call to framework_init.
#
# This function receives two arguments:
# - a results directory where you should intermediate files and reports / charts
# - a target hostname where you should target requests
#
# This function is called once per experimental variant, and the results directory is adjusted accordingly to
# keep your data organized.
#
# If your server logs data that you need to process, you can execute post-processing logic by implementing
# experiment_server_post, which gets called once per variant after the server background task terminates
#
# If you want to do one time setup before executing any variants, perform this logic in run.sh before calling
# framework_init.
#
# In addition to framework.sh, the bash_libraries directory contains a number of utility functions that are useful
# for cleaning and refactoring your data and error handling. Feel free to contribute utility functions to this
# directory if you write bash functions that you believe are reusable!
#
# It is also a good idea to look at the other experiments to get ideas for your script.
#
# If you are using VSCode, you have a number of extensions that help with bash development. This includes:
# - Bash IDE - an IntelliSense langauge server for bash
# - shell-format - Auto-format on save for bash
# - ShellCheck - an excellent linter for shell scripts.
#
# If you are not using VSCode, you may need to manually run shfmt against your script to keep formatting consistent
#
# Happy Scripting!
source "fn_exists.sh" || exit 1
source "path_join.sh" || exit 1
@ -22,14 +76,14 @@ __framework_sh__usage() {
echo "$0 [options...]"
echo ""
echo "Options:"
echo " -t,--target=<target url> Execute as client against remote URL"
echo " -d,--debug Debug under GDB but do not run client"
echo " -e,--envfile=<file name> Load an Env File. No path and pass filename with *.env extension"
echo " -h,--help Display usage information"
echo " -n,--name=<experiment> Provide a unique name for this experimental run. Defaults to timestamp"
echo " -p,--perf Run under perf. Limited to running on a baremetal Linux host!"
echo " -s,--serve Serve but do not run client"
echo " -d,--debug Debug under GDB but do not run client"
echo " -t,--target=<target url> Execute as client against remote URL"
echo " -v,--valgrind Debug under Valgrind but do not run client"
echo " -p,--perf Run under perf. Limited to running on a baremetal Linux host!"
echo " -h,--help Display usage information"
echo " -n,--name=name Provide a unique name for this experimental run. Defaults to timestamp"
}
# Declares application level global state
@ -107,10 +161,6 @@ __framework_sh__parse_arguments() {
shift
;;
-n=* | --name=*)
if [[ -d "$__framework_sh__application_directory/res/${i#*=}/" ]]; then
echo "Experiment ${i#*=} already exists. Pick a unique name!"
exit 1
fi
echo "Set experiment name to ${i#*=}"
__framework_sh__experiment_name="${i#*=}"
shift
@ -136,6 +186,24 @@ __framework_sh__parse_arguments() {
esac
done
if [[ -z "$__framework_sh__envfile" ]]; then
if [[ -d "$__framework_sh__application_directory/res/$__framework_sh__experiment_name/" ]]; then
echo "Experiment $__framework_sh__experiment_name already exists. Pick a unique name!"
exit 1
fi
else
if [[ ! -f "$__framework_sh__envfile" ]]; then
echo "$__framework_sh__envfile not found!!!"
exit 1
fi
short_name="$(basename "${__framework_sh__envfile/.env/}")"
echo "$__framework_sh__application_directory/res/$__framework_sh__experiment_name/$short_name/"
if [[ -d "$__framework_sh__application_directory/res/$__framework_sh__experiment_name/$short_name/" ]]; then
echo "Variant $short_name was already run in experiment ${__framework_sh__experiment_name}."
exit 1
fi
fi
# default to both if no arguments were passed
if [[ -z "$__framework_sh__role" ]]; then
__framework_sh__role="both"
@ -149,10 +217,7 @@ __framework_sh__parse_arguments() {
# Log hardware and software info for the execution
__framework_sh__log_environment() {
if ! command -v git &> /dev/null; then
echo "git could not be found"
exit
fi
validate_dependencies git
echo "*******"
echo "* Git *"
echo "*******"
@ -216,7 +281,7 @@ __framework_sh__start_runtime() {
;;
"foreground")
sledgert "$specification"
fn_exists experiment_server_post && experiment_server_post
fn_exists experiment_server_post && experiment_server_post "$RESULTS_DIRECTORY"
;;
esac
@ -252,27 +317,20 @@ __framework_sh__run_server() {
}
__framework_sh__run_perf() {
if ! command -v perf; then
echo "perf is not present."
exit 1
fi
validate_dependencies perf
perf record -g -s sledgert "$__framework_sh__application_directory/spec.json"
fn_exists experiment_server_post && experiment_server_post
fn_exists experiment_server_post && experiment_server_post "$RESULTS_DIRECTORY"
}
__framework_sh__run_valgrind() {
if ! command -v valgrind; then
echo "valgrind is not present."
exit 1
fi
validate_dependencies valgrind
valgrind --leak-check=full sledgert "$__framework_sh__application_directory/spec.json"
fn_exists experiment_server_post && experiment_server_post
fn_exists experiment_server_post && experiment_server_post "$RESULTS_DIRECTORY"
}
# Starts the Sledge Runtime under GDB
__framework_sh__run_debug() {
validate_dependencies gdb
# shellcheck disable=SC2155
local project_directory=$(cd ../.. && pwd)
@ -294,7 +352,7 @@ __framework_sh__run_debug() {
sledgert
fi
fn_exists experiment_server_post && experiment_server_post
fn_exists experiment_server_post && experiment_server_post "$RESULTS_DIRECTORY"
return 0
}
@ -306,7 +364,7 @@ __framework_sh__run_client() {
__framework_sh__load_env_file() {
local envfile="$1"
if [[ -f "$envfile" ]]; then
if [[ -n "$envfile" ]] && [[ -f "$envfile" ]]; then
while read -r line; do
echo export "${line?}"
export "${line?}"
@ -324,44 +382,58 @@ __framework_sh__unset_env_file() {
fi
}
__framework_sh__run_both() {
__framework_sh__run_env() {
local envfile="$1"
local short_name
shopt -s nullglob
local -i envfiles_found=0
for envfile in "$__framework_sh__application_directory"/*.env; do
((envfiles_found++))
short_name="$(basename "${envfile/.env/}")"
printf "Running %s\n" "$short_name"
__framework_sh__load_env_file "$envfile"
__framework_sh__create_and_export_results_directory "$short_name"
__framework_sh__run_server background || {
panic "Error calling __framework_sh__run_server"
return 1
}
__framework_sh__run_client || {
__framework_sh__unset_env_file "$envfile"
__framework_sh__stop_runtime
return 1
}
short_name="$(basename "${envfile/.env/}")"
printf "Running %s\n" "$short_name"
__framework_sh__load_env_file "$envfile"
__framework_sh__create_and_export_results_directory "$short_name"
__framework_sh__stop_runtime || {
panic "Error calling __framework_sh__stop_runtime"
__framework_sh__unset_env_file "$envfile"
return 1
}
__framework_sh__run_server background || {
panic "Error calling __framework_sh__run_server"
return 1
}
__framework_sh__run_client || {
__framework_sh__unset_env_file "$envfile"
done
__framework_sh__stop_runtime
return 1
}
__framework_sh__stop_runtime || {
panic "Error calling __framework_sh__stop_runtime"
__framework_sh__unset_env_file "$envfile"
return 1
}
__framework_sh__unset_env_file "$envfile"
}
# If envfile explicitly passed, just run that. Otherwise, run all
__framework_sh__run_both() {
shopt -s nullglob
((envfiles_found == 0)) && echo "No *.env files found. Nothing to run!"
if [[ -n "$__framework_sh__envfile" ]]; then
__framework_sh__run_env "$__framework_sh__envfile"
else
local -i envfiles_found=0
for envfile in "$__framework_sh__application_directory"/*.env; do
((envfiles_found++))
__framework_sh__run_env "$envfile"
done
((envfiles_found == 0)) && {
echo "No *.env files found. Nothing to run!"
exit 1
}
fi
return 0
}
# Optionally accepts a subdirectory
# This is intended to namespace distinct runtime configs run in a single command
# This is intended to namespace distinct runtime configs under a single namespace
__framework_sh__create_and_export_results_directory() {
if (($# > 1)); then
printf "[ERR]\n"
@ -370,21 +442,7 @@ __framework_sh__create_and_export_results_directory() {
fi
local -r subdirectory=${1:-""}
local dir=""
# If we are running both client, and server, we need to namespace by scheduler since we run both variants
case "$__framework_sh__role" in
"both")
dir="$__framework_sh__application_directory/res/$__framework_sh__experiment_name/$subdirectory"
;;
"client" | "server" | "debug" | "perf" | "valgrind")
dir="$__framework_sh__application_directory/res/$__framework_sh__experiment_name"
;;
*)
panic "${FUNCNAME[0]} Unexpected $__framework_sh__role"
return 1
;;
esac
local dir="$__framework_sh__application_directory/res/$__framework_sh__experiment_name/$subdirectory"
mkdir -p "$dir" || {
panic "mkdir -p $dir"
@ -395,38 +453,41 @@ __framework_sh__create_and_export_results_directory() {
}
# Responsible for ensuring that the experiment file meets framework assumptions
__framework_sh__validate_experiment() {
__framework_sh__validate_client() {
if [[ $(type -t experiment_client) != "function" ]]; then
panic "function experiment_client was not defined"
return 1
fi
}
main() {
__framework_sh__validate_experiment || exit 1
framework_init() {
__framework_sh__initialize_globals || exit 1
__framework_sh__parse_arguments "$@" || exit 1
__framework_sh__create_and_export_results_directory || exit 1
[[ -n "$__framework_sh__envfile" ]] && __framework_sh__load_env_file "$__framework_sh__application_directory/$__framework_sh__envfile"
case $__framework_sh__role in
both)
__framework_sh__validate_client || exit 1
__framework_sh__run_both
;;
server)
[[ -n "$__framework_sh__envfile" ]] && __framework_sh__load_env_file "$__framework_sh__application_directory/$__framework_sh__envfile"
__framework_sh__run_server foreground
;;
debug)
[[ -n "$__framework_sh__envfile" ]] && __framework_sh__load_env_file "$__framework_sh__application_directory/$__framework_sh__envfile"
__framework_sh__run_debug
;;
perf)
[[ -n "$__framework_sh__envfile" ]] && __framework_sh__load_env_file "$__framework_sh__application_directory/$__framework_sh__envfile"
__framework_sh__run_perf
;;
valgrind)
[[ -n "$__framework_sh__envfile" ]] && __framework_sh__load_env_file "$__framework_sh__application_directory/$__framework_sh__envfile"
__framework_sh__run_valgrind
;;
client)
__framework_sh__validate_client || exit 1
__framework_sh__run_client
;;
*)
@ -452,6 +513,6 @@ __framework_sh__stop_runtime() {
exit 1
}
fn_exists experiment_server_post && experiment_server_post
fn_exists experiment_server_post && experiment_server_post "$RESULTS_DIRECTORY"
printf "[OK]\n"
}

@ -261,4 +261,4 @@ experiment_client() {
return 0
}
main "$@"
framework_init "$@"

@ -187,4 +187,4 @@ experiment_client() {
return 0
}
main "$@"
framework_init "$@"

@ -2,14 +2,48 @@
How to use with deadline_description and workload_mix_realworld
1. Start the server with deadline description
2. From the client, run the script to generate the spec.json
3. Manually copy spec.json to the server in the workload_mix_realword directory, i.e.
1. SSH into the server and run the deadline description experiment. The code snippet below is naming the experiment benchmark, so it is first deleting any previous experiments that would cause a name collision.
```sh
scp spec.json sean@192.168.7.26:~/projects/sledge-serverless-framework/runtime/experiments/workload_mix_realworld/spec.json
ssh sean@192.168.7.26
cd ~/projects/sledge-serverless-framework/runtime/experiments/deadline_description/
rm -rf ./res/benchmark
./run.sh -n=benchmark
```
4. Start workload_mix_realworld on the server with the desired scheduling policy
5. Start workload_mix_realworld from the client targeting the server
6. Repeat for steps 4,5 for each desired scheduling policy.
2. This generates a spec.json in the results directory at `./res/benchmark/spec.json`. Copy this to the `workload_mix_realword directory` on the server.
```sh
cp ./res/benchmark/fifo_nopreemption/spec.json ../workload_mix_realworld/
cd ../workload_mix_realworld/
```
3. And then on your client, go to the workload_mix_realworld directory and use scp to copy the `spec.json` file from the server. The client needs this file to understand which ports the various modules are going to be running on.
```sh
cd ~/projects/sledge-serverless-framework/runtime/experiments/workload_mix_realworld/
scp sean@192.168.7.26:~/projects/sledge-serverless-framework/runtime/experiments/workload_mix_realworld/spec.json spec.json
```
4. If the deadline interval was modified, you may need to manually modify the `mix.csv` to properly map to the module names in `spec.json`. Once complete, the experiment is ready to run
5. On the server, start the runtime using one of the configurations expressed as .env files.
```sh
rm -rf ./res/myrun/fifo_nopreemption
./run.sh -s -e=fifo_nopreemption.env --name=myrun
```
6. On the client, run the client driver script targeting the server
```
./run.sh -t=192.168.7.26 --name=myrun
```
7. Repeat for steps 5,6 for each desired scheduling policy.
8. The results are on the server. You may want to copy them to your client to more easily inspect.
```sh
scp -r sean@192.168.7.26:~/projects/sledge-serverless-framework/runtime/experiments/workload_mix_realworld/res/myrun ./res/myrun
```

@ -120,8 +120,17 @@ process_results() {
}
experiment_server_post() {
mv "$__run_sh__base_path/perf.log" "$RESULTS_DIRECTORY/perf.log"
process_results "$RESULTS_DIRECTORY"
local -r results_directory="$1"
# Only process data if SLEDGE_SANDBOX_PERF_LOG was set when running sledgert
if [[ -n "$SLEDGE_SANDBOX_PERF_LOG" ]]; then
if [[ -f "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" ]]; then
mv "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" "$results_directory/perf.log"
process_results "$results_directory" || return 1
else
echo "Perf Log was set, but perf.log not found!"
fi
fi
}
experiment_client() {
@ -131,4 +140,4 @@ experiment_client() {
profile "$hostname" "$results_directory" || return 1
}
main "$@"
framework_init "$@"

@ -184,5 +184,4 @@ experiment_client() {
return 0
}
# Delegating to main provided by framework
main "$@"
framework_init "$@"

@ -225,4 +225,4 @@ experiment_client() {
return 0
}
main "$@"
framework_init "$@"

@ -14,15 +14,12 @@ export PATH="$__run_sh__bash_libraries_absolute_path:$PATH"
source csv_to_dat.sh || exit 1
source framework.sh || exit 1
# source generate_gnuplots.sh || exit 1
source get_result_count.sh || exit 1
source panic.sh || exit 1
source path_join.sh || exit 1
source validate_dependencies.sh || exit 1
if ! command -v hey > /dev/null; then
echo "hey is not present."
exit 1
fi
validate_dependencies hey jq
declare -a workloads=()
declare -A port=()
@ -99,11 +96,11 @@ run_experiments() {
fi
# TODO: Check that workload is in spec.json
local -ir batch_size=100
local -ir batch_size=10
local -i batch_id=0
local -i roll=0
local -ir total_iterations=100000
local -ir worker_max=50
local -ir total_iterations=10000
local -ir worker_max=5
local pids
printf "Running Experiments: "
@ -224,8 +221,17 @@ process_results() {
}
experiment_server_post() {
mv "$__run_sh__base_path/perf.log" "$RESULTS_DIRECTORY/perf.log"
process_results "$RESULTS_DIRECTORY" || return 1
local -r results_directory="$1"
# Only process data if SLEDGE_SANDBOX_PERF_LOG was set when running sledgert
if [[ -n "$SLEDGE_SANDBOX_PERF_LOG" ]]; then
if [[ -f "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" ]]; then
mv "$__run_sh__base_path/$SLEDGE_SANDBOX_PERF_LOG" "$results_directory/perf.log"
process_results "$results_directory" || return 1
else
echo "Perf Log was set, but perf.log not found!"
fi
fi
}
# Client Code
@ -240,4 +246,4 @@ experiment_client() {
}
initialize_globals
main "$@"
framework_init "$@"

Loading…
Cancel
Save