From 3b748b1d78ae3f88a952fa2afe2688a088453cd9 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 20 Apr 2021 16:11:46 +0200 Subject: [PATCH 1/3] [EchoClient] Add load-switch feature --- apps/EchoClient.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/apps/EchoClient.cpp b/apps/EchoClient.cpp index 1a477348..a3a7a6ea 100644 --- a/apps/EchoClient.cpp +++ b/apps/EchoClient.cpp @@ -18,7 +18,8 @@ #include // for memcmp #include #include // for operator<<, basic_ostream, endl -#include // for allocator, string, char_traits +#include +#include #include #include @@ -69,6 +70,8 @@ size_t size = SIZE; size_t server_backlog = SERVER_BACKLOG; bool linked_futures; bool histogram = false; +static ssize_t maxLowLoadClients = -1; +static std::chrono::milliseconds loadSwitchPeriod(1000); std::atomic terminate = false; @@ -225,6 +228,24 @@ class Client { } } + [[nodiscard]] auto shouldYield() const -> bool { + if (maxLowLoadClients < 0) { + return false; + } + + if (id < static_cast(maxLowLoadClients)) { + return false; + } + + auto now = std::chrono::steady_clock::now(); + auto now_ms = std::chrono::time_point_cast(now); + auto ms_since_epoch = now_ms.time_since_epoch(); + auto ms_since_epoch_duration = + std::chrono::duration_cast(ms_since_epoch); + uint64_t periodNum = ms_since_epoch_duration / loadSwitchPeriod; + return periodNum % 2; + } + public: template void run() { @@ -237,6 +258,11 @@ class Client { startSem.acquire(); while (iteration < iterations && !terminate.load(std::memory_order_relaxed)) { + if (shouldYield()) { + emper::yield(); + continue; + } + SendFuture sendFuture(sock, outBuf, size, MSG_NOSIGNAL); RecvFuture recvFuture(sock, inBuf, size, MSG_WAITALL); @@ -361,8 +387,10 @@ static void printUsage(char* name) { std::cerr << "Usage: " << name << "[-h] [-p ] [-c ] [-a
] [-s ] [-b ]" - " [-f ] [-i | -t ] [--linked-futures]" - << std::endl; + << std::endl + << "[-f ] [-i | -t ] [--linked-futures]" + << std::endl + << "[--max-low-load-clients ] [--load-switch-period-ms ]" << std::endl; } auto main(int argc, char* argv[]) -> int { @@ -446,6 +474,25 @@ auto main(int argc, char* argv[]) -> int { } } + char* max_low_load_clients = getOption(argc, argv, "--max-low-load-clients"); + if (max_low_load_clients) { + maxLowLoadClients = std::stoi(max_low_load_clients); + if (static_cast(maxLowLoadClients) >= nclients) { + DIE_MSG("--max-low-load-clients " << maxLowLoadClients + << " must be smaller than the total number of clients " + << nclients); + } + } + + char* load_switch_period_ms_string = getOption(argc, argv, "--load-switch-period-ms"); + if (load_switch_period_ms_string) { + if (!max_low_load_clients) { + DIE_MSG("Can't use --load-switch-period-ms without --max-low-load-clients"); + } + int load_switch_period_ms = std::stoi(load_switch_period_ms_string); + loadSwitchPeriod = std::chrono::milliseconds(load_switch_period_ms); + } + int err = getaddrinfo(host.c_str(), port.c_str(), nullptr, &server); if (err) { if (err == EAI_SYSTEM) { -- GitLab From ac18a7093ef7c103a4f1a81cf67bceaad0fb3053 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 21 Apr 2021 18:19:18 +0200 Subject: [PATCH 2/3] [EchoServer] Log if 'quit' was received --- apps/EchoServer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/EchoServer.cpp b/apps/EchoServer.cpp index 081f7c85..660dcdde 100644 --- a/apps/EchoServer.cpp +++ b/apps/EchoServer.cpp @@ -63,6 +63,7 @@ auto main(int argc, char* argv[]) -> int { if (unlikely(bytes_recv == 5 && strncmp("quit\n", buf, bytes_recv) == 0)) { quit = true; + std::cout << "Echoserver received 'quit' command from client" << std::endl; Runtime::getRuntime()->initiateTermination(); break; } -- GitLab From a03cafb9a2f76ce1a23f642ad15794b776b49b73 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Wed, 21 Apr 2021 18:19:06 +0200 Subject: [PATCH 3/3] Add tools/test-echo-server-and-client script --- Makefile | 4 ++ tools/test-echo-server-and-client | 101 ++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100755 tools/test-echo-server-and-client diff --git a/Makefile b/Makefile index 5081a62e..59f34ce7 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,10 @@ fix-includes: all stresstest: test ./stresstest/stresstest.sh build/tests/simplest_fib_test +PHONY: test-echo +test-echo: + ./tools/test-echo-server-and-client + # TODO: Determine how we can run also jobs from the 'test' stage, # e.g. test-gcc. .PHONY: gitlab-runner diff --git a/tools/test-echo-server-and-client b/tools/test-echo-server-and-client new file mode 100755 index 00000000..41a21521 --- /dev/null +++ b/tools/test-echo-server-and-client @@ -0,0 +1,101 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-3.0-or-later +# Copyright © 2021 Florian Schmaus +set -euo pipefail + +SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +ROOTDIR="$(readlink -f "${SCRIPTDIR}/..")" +BUILDDIR="${ROOTDIR}/build" + +echoerr() { echo "$@" 1>&2; } + +PRESERVE_TMPDIR=false +while getopts :dp OPT; do + case $OPT in + d) + PRESERVE_TMPDIR=true + set -x + ;; + p) + PRESERVE_TMPDIR=true + ;; + *) + print "usage: ${0##*/} [-d] [--] ARGS..." + exit 2 + esac +done +shift $(( OPTIND - 1 )) +OPTIND=1 + +if [[ ! -L "${BUILDDIR}" ]]; then + make -C "${ROOTDIR}" +fi + +TMPDIR=$(mktemp --directory --tmpdir=/var/tmp emper-echo-test.XXXX) +cleanup() { + if ! $PRESERVE_TMPDIR; then + rm -rf "${TMPDIR}" + fi + + # Ensure that we don't leave a stray echoserver + if pgrep --count echoserver > /dev/null; then + killall echoserver + fi +} +trap cleanup EXIT + +echo "Starting echo client/server test. Using ${TMPDIR} for logs" + +readonly ECHO_CLIENT="${BUILDDIR}/apps/echoclient" +readonly ECHO_SERVER="${BUILDDIR}/apps/echoserver" + +run_echo_client_and_server() { + local -r run_name="${1}" + local -r echo_client_opts="${2-}" + + local -r logdir="${TMPDIR}/${run_name}" + mkdir "${logdir}" + + local -r echo_server_pidfile="${logdir}/echo_server.pid" + + echo "Performing echo client/server ${run_name} run. Logdir: ${logdir}" + + "${ECHO_SERVER}" \ + > "${logdir}/server.log" \ + 2> "${logdir}/server.err" & + echo "${!}" >> "${echo_server_pidfile}" + + # Wait till the echo server port becomes accessible. + # https://stackoverflow.com/a/50055449/194894 + timeout 30 bash -c \ + 'until printf "" 2>>/dev/null >>/dev/tcp/${0}/${1}; do sleep 1; done' \ + localhost 12345 + + set +e + # shellcheck disable=SC2086 + "${ECHO_CLIENT}" \ + ${echo_client_opts} \ + > "${logdir}/client.log" \ + 2> "${logdir}/client.err" + local echo_client_ret="${?}" + set -e + + local echo_server_pid + echo_server_pid=$(cat "${echo_server_pidfile}") + if ps -p "${echo_server_pid}" > /dev/null; then + # TODO: Re-enable this warning once the client is sending a + # 'quit' once it is finished. +# echoerr "WARNING: echo server was not terminated by client" + kill "${echo_server_pid}" + fi + + if [[ "${echo_client_ret}" -ne 0 ]]; then + echoerr "ERROR: Echo client exited with ${echo_client_ret}" + PRESERVE_TMPDIR=true + exit 1 + fi +} + +run_echo_client_and_server "quicktest" "-c 10 -i 10" + +run_echo_client_and_server "load-switch" "-c 100 -i 1000 --max-low-load-clients 50 --load-switch-period-ms 250" -- GitLab