summaryrefslogtreecommitdiff
path: root/test/network_tests/cpu_load_tests
diff options
context:
space:
mode:
Diffstat (limited to 'test/network_tests/cpu_load_tests')
-rw-r--r--test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in38
-rw-r--r--test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in38
-rw-r--r--test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in51
-rw-r--r--test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in51
-rw-r--r--test/network_tests/cpu_load_tests/cpu_load_measurer.cpp159
-rw-r--r--test/network_tests/cpu_load_tests/cpu_load_measurer.hpp35
-rw-r--r--test/network_tests/cpu_load_tests/cpu_load_test_client.cpp390
-rw-r--r--test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp18
-rwxr-xr-xtest/network_tests/cpu_load_tests/cpu_load_test_master_starter.sh75
-rw-r--r--test/network_tests/cpu_load_tests/cpu_load_test_service.cpp209
-rwxr-xr-xtest/network_tests/cpu_load_tests/cpu_load_test_slave_starter.sh52
11 files changed, 1116 insertions, 0 deletions
diff --git a/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in b/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in
new file mode 100644
index 0000000..ec9dcd7
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_master.json.in
@@ -0,0 +1,38 @@
+{
+ "unicast" : "@TEST_IP_MASTER@",
+ "netmask" : "255.255.255.0",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/var/log/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_client",
+ "id" : "0x2222"
+ }
+ ],
+ "npdu-default-timings" : {
+ "debounce-time-request" : "0",
+ "debounce-time-response" : "0",
+ "max-retention-time-request" : "0",
+ "max-retention-time-response" : "0"
+ },
+ "routing" : "cpu_load_test_client",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in b/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in
new file mode 100644
index 0000000..4da82f4
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/conf/cpu_load_test_client_slave.json.in
@@ -0,0 +1,38 @@
+{
+ "unicast" : "@TEST_IP_SLAVE@",
+ "netmask" : "255.255.255.0",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/var/log/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_client",
+ "id" : "0x2222"
+ }
+ ],
+ "npdu-default-timings" : {
+ "debounce-time-request" : "0",
+ "debounce-time-response" : "0",
+ "max-retention-time-request" : "0",
+ "max-retention-time-response" : "0"
+ },
+ "routing" : "cpu_load_test_client",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in b/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in
new file mode 100644
index 0000000..da34e22
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_master.json.in
@@ -0,0 +1,51 @@
+{
+ "unicast" : "@TEST_IP_MASTER@",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/tmp/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_service",
+ "id" : "0x1111"
+ }
+ ],
+
+ "services" :
+ [
+ {
+ "service" : "0x1111",
+ "instance" : "0x1",
+ "unreliable" : "30510",
+ "reliable" :
+ {
+ "port" : "30510",
+ "enable-magic-cookies" : "false"
+ }
+ }
+ ],
+ "npdu-default-timings" : {
+ "debounce-time-request" : "0",
+ "debounce-time-response" : "0",
+ "max-retention-time-request" : "0",
+ "max-retention-time-response" : "0"
+ },
+ "routing" : "cpu_load_test_service",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in b/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in
new file mode 100644
index 0000000..389aea0
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/conf/cpu_load_test_service_slave.json.in
@@ -0,0 +1,51 @@
+{
+ "unicast" : "@TEST_IP_SLAVE@",
+ "logging" :
+ {
+ "level" : "debug",
+ "console" : "true",
+ "file" :
+ {
+ "enable" : "false",
+ "path" : "/tmp/vsomeip.log"
+ },
+
+ "dlt" : "false"
+ },
+
+ "applications" :
+ [
+ {
+ "name" : "cpu_load_test_service",
+ "id" : "0x1111"
+ }
+ ],
+
+ "services" :
+ [
+ {
+ "service" : "0x1111",
+ "instance" : "0x1",
+ "unreliable" : "30510",
+ "reliable" :
+ {
+ "port" : "30510",
+ "enable-magic-cookies" : "false"
+ }
+ }
+ ],
+ "npdu-default-timings" : {
+ "debounce-time-request" : "0",
+ "debounce-time-response" : "0",
+ "max-retention-time-request" : "0",
+ "max-retention-time-response" : "0"
+ },
+ "routing" : "cpu_load_test_service",
+ "service-discovery" :
+ {
+ "enable" : "true",
+ "multicast" : "224.0.0.1",
+ "port" : "30490",
+ "protocol" : "udp"
+ }
+}
diff --git a/test/network_tests/cpu_load_tests/cpu_load_measurer.cpp b/test/network_tests/cpu_load_tests/cpu_load_measurer.cpp
new file mode 100644
index 0000000..d4360b3
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_measurer.cpp
@@ -0,0 +1,159 @@
+// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "cpu_load_measurer.hpp"
+
+#include <fstream>
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <stdexcept>
+#include <cstdio>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+cpu_load_measurer::~cpu_load_measurer() {
+}
+
+cpu_load_measurer::cpu_load_measurer(std::uint32_t _pid) :
+ pid_(_pid),
+ jiffies_complete_start_(0),
+ jiffies_idle_start_(0),
+ jiffies_complete_stop_(0),
+ jiffies_idle_stop_(0),
+ clock_ticks_(0),
+ jiffies_passed_pid_start_(0),
+ jiffies_passed_pid_stop_(0),
+ cpu_load_pid_(0.0),
+ cpu_load_overall_(0.0),
+ cpu_load_pid_wo_idle_(0.0) {
+}
+
+void cpu_load_measurer::start() {
+ // reset everything
+ jiffies_complete_start_ = 0;
+ jiffies_idle_start_ = 0;
+ jiffies_complete_stop_ = 0;
+ jiffies_idle_stop_ = 0;
+ clock_ticks_ = 0;
+ jiffies_passed_pid_start_ = 0;
+ jiffies_passed_pid_stop_ = 0;
+ cpu_load_pid_= 0.0;
+ cpu_load_overall_ = 0.0;
+ cpu_load_pid_wo_idle_ = 0.0;
+ //start
+ jiffies_complete_start_ = read_proc_stat(&jiffies_idle_start_);
+ jiffies_passed_pid_start_ = read_proc_pid_stat();
+}
+
+void cpu_load_measurer::stop() {
+ jiffies_complete_stop_ = read_proc_stat(&jiffies_idle_stop_);
+ jiffies_passed_pid_stop_ = read_proc_pid_stat();
+ if(jiffies_complete_stop_ < jiffies_complete_start_ || jiffies_passed_pid_stop_ < jiffies_passed_pid_start_) {
+ std::cerr << "Overflow of values in procfs occured, can't calculate load" << std::endl;
+ exit(0);
+ }
+ cpu_load_pid_ = 100.0
+ * static_cast<double>(jiffies_passed_pid_stop_
+ - jiffies_passed_pid_start_)
+ / static_cast<double>(jiffies_complete_stop_
+ - jiffies_complete_start_);
+ cpu_load_overall_ = 100.0
+ * static_cast<double>((jiffies_complete_stop_ - jiffies_idle_stop_)
+ - (jiffies_complete_start_ - jiffies_idle_start_))
+ / static_cast<double>(jiffies_complete_stop_
+ - jiffies_complete_start_);
+ cpu_load_pid_wo_idle_ = 100.0
+ * static_cast<double>(jiffies_passed_pid_stop_
+ - jiffies_passed_pid_start_)
+ / static_cast<double>((jiffies_complete_stop_ - jiffies_idle_stop_)
+ - (jiffies_complete_start_ - jiffies_idle_start_));
+
+}
+
+void cpu_load_measurer::print_cpu_load() const {
+ std::cout << "Used Jiffies complete: "
+ << jiffies_complete_stop_ - jiffies_complete_start_ << " (worked: "
+ << (jiffies_complete_stop_ - jiffies_idle_stop_)
+ - (jiffies_complete_start_ - jiffies_idle_start_)
+ << " idled: " << jiffies_idle_stop_ - jiffies_idle_start_
+ << ")" << std::endl;
+ std::cout << "Used Jiffies of pid " << pid_ << ": " << jiffies_passed_pid_stop_ - jiffies_passed_pid_start_ << std::endl;
+ std::cout << "Cpu load pid " << pid_ << " [%]: " << cpu_load_pid_ << std::endl;
+ std::cout << "Overall cpu load[%]: " << cpu_load_overall_ << std::endl;
+ std::cout << "Load caused by pid " << pid_ << " of overall cpu load [%]:" << cpu_load_pid_wo_idle_ << std::endl;
+}
+
+double cpu_load_measurer::get_cpu_load() const {
+ return cpu_load_pid_;
+}
+
+std::uint64_t cpu_load_measurer::read_proc_pid_stat() {
+ std::string path("/proc/" + std::to_string(pid_) + "/stat");
+ FILE* f = std::fopen(path.c_str(), "r");
+ if(!f) {
+ std::perror(std::string("Failed to open " + path).c_str());
+ exit(1);
+ }
+ // see Table 1-4 Contents of the stat files (as of 2.6.30-rc7)
+ // at https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/filesystems/proc.txt?id=refs/tags/v3.10.98
+ // and man proc (for conversion specifier)
+ std::uint64_t utime(0);
+ std::uint64_t stime(0);
+ std::int64_t cutime(0);
+ std::int64_t cstime(0);
+ if (std::fscanf(f, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u "
+ "%lu %lu %ld %ld", // utime, stime, cutime, cstime
+ &utime, &stime, &cutime, &cstime) == EOF) {
+ std::cerr << "Failed to read " + path << std::endl;
+ exit(1);
+ }
+ std::fclose(f);
+ return utime + stime + static_cast<std::uint64_t>(cutime) +
+ static_cast<std::uint64_t>(cstime);
+}
+
+std::uint64_t cpu_load_measurer::read_proc_stat(std::uint64_t* _idle) {
+ FILE* f = std::fopen("/proc/stat", "r");
+ if(!f) {
+ std::perror("Failed to open /proc/stat");
+ exit(1);
+ }
+
+ // see 1.8 Miscellaneous kernel statistics in /proc/stat
+ // at https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/filesystems/proc.txt?id=refs/tags/v3.10.98
+ std::uint64_t user(0);
+ std::uint64_t nice(0);
+ std::uint64_t system(0);
+ std::uint64_t idle(0);
+ std::uint64_t iowait(0);
+ std::uint64_t irq(0);
+ std::uint64_t softirq(0);
+ std::uint64_t steal(0);
+ std::uint64_t guest(0);
+ std::uint64_t guest_nice(0);
+ if (std::fscanf(f, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", &user,
+ &nice, &system, &idle, &iowait, &irq, &softirq, &steal, &guest,
+ &guest_nice) == EOF) {
+ std::cerr << "Failed to read /proc/stat" << std::endl;
+ exit(1);
+ }
+ std::fclose(f);
+ *_idle = idle;
+ return user + nice + system + idle + iowait + irq + softirq + steal + guest
+ + guest_nice;
+}
+
+bool cpu_load_measurer::read_clock_ticks() {
+ long val(::sysconf(_SC_CLK_TCK));
+ if(val < 0 && errno == EINVAL) {
+ std::perror(__func__);
+ return false;
+ }
+ clock_ticks_ = static_cast<std::uint64_t>(val);
+ return true;
+}
diff --git a/test/network_tests/cpu_load_tests/cpu_load_measurer.hpp b/test/network_tests/cpu_load_tests/cpu_load_measurer.hpp
new file mode 100644
index 0000000..dfdcf80
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_measurer.hpp
@@ -0,0 +1,35 @@
+// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+#include <cstdint>
+
+class cpu_load_measurer {
+public:
+ cpu_load_measurer(std::uint32_t _pid);
+ virtual ~cpu_load_measurer();
+ void start();
+ void stop();
+ void print_cpu_load() const;
+ double get_cpu_load() const;
+
+private:
+ std::uint64_t read_proc_stat(std::uint64_t* _idle);
+ std::uint64_t read_proc_pid_stat();
+ bool read_clock_ticks();
+private:
+ std::uint32_t pid_;
+ std::uint64_t jiffies_complete_start_;
+ std::uint64_t jiffies_idle_start_;
+ std::uint64_t jiffies_complete_stop_;
+ std::uint64_t jiffies_idle_stop_;
+ std::uint64_t clock_ticks_;
+ std::uint64_t jiffies_passed_pid_start_;
+ std::uint64_t jiffies_passed_pid_stop_;
+ double cpu_load_pid_;
+ double cpu_load_overall_;
+ double cpu_load_pid_wo_idle_;
+};
diff --git a/test/network_tests/cpu_load_tests/cpu_load_test_client.cpp b/test/network_tests/cpu_load_tests/cpu_load_test_client.cpp
new file mode 100644
index 0000000..d1d5104
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_test_client.cpp
@@ -0,0 +1,390 @@
+// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <functional>
+#include <iomanip>
+#include <numeric>
+#include <cmath> // for isfinite
+#include <atomic>
+
+#include "cpu_load_test_globals.hpp"
+#include <vsomeip/internal/logger.hpp>
+#include "cpu_load_measurer.hpp"
+
+// for getpid
+#include <sys/types.h>
+#include <unistd.h>
+
+
+enum protocol_e {
+ PR_UNKNOWN,
+ PR_TCP,
+ PR_UDP
+};
+
+class cpu_load_test_client
+{
+public:
+ cpu_load_test_client(protocol_e _protocol, std::uint32_t _number_of_calls,
+ std::uint32_t _payload_size, bool _call_service_sync,
+ bool _shutdown_service) :
+ protocol_(_protocol),
+ app_(vsomeip::runtime::get()->create_application("cpu_load_test_client")),
+ request_(vsomeip::runtime::get()->create_request(protocol_ == protocol_e::PR_TCP)),
+ call_service_sync_(_call_service_sync),
+ shutdown_service_at_end_(_shutdown_service),
+ sliding_window_size_(_number_of_calls),
+ wait_for_availability_(true),
+ is_available_(false),
+ number_of_calls_(_number_of_calls),
+ number_of_calls_current_(0),
+ number_of_sent_messages_(0),
+ number_of_sent_messages_total_(0),
+ number_of_acknowledged_messages_(0),
+ payload_size_(_payload_size),
+ wait_for_all_msg_acknowledged_(true),
+ initialized_(false),
+ sender_(std::bind(&cpu_load_test_client::run, this)) {
+ if (!app_->init()) {
+ ADD_FAILURE() << "Couldn't initialize application";
+ return;
+ }
+ initialized_ = true;
+ app_->register_state_handler(
+ std::bind(&cpu_load_test_client::on_state, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(vsomeip::ANY_SERVICE,
+ vsomeip::ANY_INSTANCE, vsomeip::ANY_METHOD,
+ std::bind(&cpu_load_test_client::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_availability_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id,
+ std::bind(&cpu_load_test_client::on_availability, this,
+ std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3));
+ VSOMEIP_INFO << "Starting...";
+ app_->start();
+ }
+
+ ~cpu_load_test_client() {
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_availability_ = false;
+ condition_.notify_one();
+ }
+ {
+ std::lock_guard<std::mutex> its_lock(all_msg_acknowledged_mutex_);
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ sender_.join();
+ }
+
+private:
+ void stop() {
+ VSOMEIP_INFO << "Stopping...";
+ // shutdown the service
+ if(shutdown_service_at_end_)
+ {
+ shutdown_service();
+ }
+ app_->clear_all_handler();
+ }
+
+ void on_state(vsomeip::state_type_e _state) {
+ if(_state == vsomeip::state_type_e::ST_REGISTERED)
+ {
+ app_->request_service(cpu_load_test::service_id,
+ cpu_load_test::instance_id);
+ }
+ }
+
+ void on_availability(vsomeip::service_t _service,
+ vsomeip::instance_t _instance, bool _is_available) {
+ VSOMEIP_INFO << "Service [" << std::setw(4) << std::setfill('0')
+ << std::hex << _service << "." << _instance << "] is "
+ << (_is_available ? "available." : "NOT available.");
+
+ if (cpu_load_test::service_id == _service
+ && cpu_load_test::instance_id == _instance) {
+ if (is_available_ && !_is_available) {
+ is_available_ = false;
+ } else if (_is_available && !is_available_) {
+ is_available_ = true;
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ wait_for_availability_ = false;
+ condition_.notify_one();
+ }
+ }
+ }
+ void on_message(const std::shared_ptr<vsomeip::message> &_response) {
+
+ number_of_acknowledged_messages_++;
+ ASSERT_EQ(_response->get_service(), cpu_load_test::service_id);
+ ASSERT_EQ(_response->get_method(), cpu_load_test::method_id);
+ if(call_service_sync_)
+ {
+ // We notify the sender thread every time a message was acknowledged
+ std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_);
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ else
+ {
+ // We notify the sender thread only if all sent messages have been acknowledged
+ if(number_of_acknowledged_messages_ == number_of_calls_current_)
+ {
+ std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_);
+ number_of_acknowledged_messages_ = 0;
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ else if(number_of_acknowledged_messages_ % sliding_window_size_ == 0)
+ {
+ std::lock_guard<std::mutex> lk(all_msg_acknowledged_mutex_);
+ wait_for_all_msg_acknowledged_ = false;
+ all_msg_acknowledged_cv_.notify_one();
+ }
+ }
+ }
+
+ void run() {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (wait_for_availability_) {
+ condition_.wait(its_lock);
+ }
+
+ request_->set_service(cpu_load_test::service_id);
+ request_->set_instance(cpu_load_test::instance_id);
+ request_->set_method(cpu_load_test::method_id);
+ std::shared_ptr<vsomeip::payload> payload = vsomeip::runtime::get()->create_payload();
+ std::vector<vsomeip::byte_t> payload_data;
+ payload_data.assign(payload_size_, cpu_load_test::load_test_data);
+ payload->set_data(payload_data);
+ request_->set_payload(payload);
+
+ // lock the mutex
+ for(std::uint32_t i=0; i <= number_of_calls_; i++) {
+ number_of_calls_current_ = i;
+ sliding_window_size_ = i;
+ std::unique_lock<std::mutex> lk(all_msg_acknowledged_mutex_);
+ call_service_sync_ ? send_messages_sync(lk, i) : send_messages_async(lk, i);
+ }
+ const double average_load(std::accumulate(results_.begin(), results_.end(), 0.0) / static_cast<double>(results_.size()));
+ VSOMEIP_INFO << "Sent: " << number_of_sent_messages_total_
+ << " messages in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load << "% load in average (average of "
+ << results_.size() << " measurements).";
+
+ std::vector<double> results_no_zero;
+ for(const auto &v : results_) {
+ if(v > 0.0) {
+ results_no_zero.push_back(v);
+ }
+ }
+ const double average_load_no_zero(std::accumulate(results_no_zero.begin(), results_no_zero.end(), 0.0) / static_cast<double>(results_no_zero.size()));
+ VSOMEIP_INFO << "Sent: " << number_of_sent_messages_total_
+ << " messages in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load_no_zero << "% load in average, if measured "
+ << "cpu load was greater zero (average of "
+ << results_no_zero.size() << " measurements).";
+
+ wait_for_availability_ = true;
+
+ stop();
+ if (initialized_) {
+ app_->stop();
+ }
+ }
+
+
+ void send_messages_sync(std::unique_lock<std::mutex>& lk, std::uint32_t _messages_to_send) {
+ cpu_load_measurer c(static_cast<std::uint32_t>(::getpid()));
+ send_service_start_measuring(true);
+ c.start();
+ for (number_of_sent_messages_ = 0;
+ number_of_sent_messages_ < _messages_to_send;
+ number_of_sent_messages_++, number_of_sent_messages_total_++)
+ {
+ app_->send(request_);
+ // wait until the send messages has been acknowledged
+ while(wait_for_all_msg_acknowledged_) {
+ all_msg_acknowledged_cv_.wait(lk);
+ }
+ wait_for_all_msg_acknowledged_ = true;
+ }
+ c.stop();
+ send_service_start_measuring(false);
+ VSOMEIP_DEBUG << "Synchronously sent " << std::setw(4) << std::setfill('0')
+ << number_of_sent_messages_ << " messages. CPU load [%]: "
+ << std::fixed << std::setprecision(2)
+ << (std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+ results_.push_back(std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+
+ }
+
+ void send_messages_async(std::unique_lock<std::mutex>& lk, std::uint32_t _messages_to_send) {
+ cpu_load_measurer c(static_cast<std::uint32_t>(::getpid()));
+ send_service_start_measuring(true);
+ c.start();
+ for (number_of_sent_messages_ = 0;
+ number_of_sent_messages_ < _messages_to_send;
+ number_of_sent_messages_++, number_of_sent_messages_total_++)
+ {
+ app_->send(request_);
+ if((number_of_sent_messages_+1) % sliding_window_size_ == 0)
+ {
+ // wait until all send messages have been acknowledged
+ while(wait_for_all_msg_acknowledged_) {
+ all_msg_acknowledged_cv_.wait(lk);
+ }
+ wait_for_all_msg_acknowledged_ = true;
+ }
+ }
+ c.stop();
+ send_service_start_measuring(false);
+ VSOMEIP_DEBUG << "Asynchronously sent " << std::setw(4) << std::setfill('0')
+ << number_of_sent_messages_ << " messages. CPU load [%]: "
+ << std::fixed << std::setprecision(2)
+ << (std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+ results_.push_back(std::isfinite(c.get_cpu_load()) ? c.get_cpu_load() : 0.0);
+ }
+
+ void send_service_start_measuring(bool _start_measuring) {
+ std::shared_ptr<vsomeip::message> m = vsomeip::runtime::get()->create_request(protocol_ == protocol_e::PR_TCP);
+ m->set_service(cpu_load_test::service_id);
+ m->set_instance(cpu_load_test::instance_id);
+ _start_measuring ? m->set_method(cpu_load_test::method_id_cpu_measure_start) : m->set_method(cpu_load_test::method_id_cpu_measure_stop);
+ app_->send(m);
+ }
+
+ void shutdown_service() {
+ request_->set_service(cpu_load_test::service_id);
+ request_->set_instance(cpu_load_test::instance_id);
+ request_->set_method(cpu_load_test::method_id_shutdown);
+ app_->send(request_);
+ }
+
+private:
+ protocol_e protocol_;
+ std::shared_ptr<vsomeip::application> app_;
+ std::shared_ptr<vsomeip::message> request_;
+ bool call_service_sync_;
+ bool shutdown_service_at_end_;
+ std::uint32_t sliding_window_size_;
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool wait_for_availability_;
+ bool is_available_;
+ const std::uint32_t number_of_calls_;
+ std::uint32_t number_of_calls_current_;
+ std::uint32_t number_of_sent_messages_;
+ std::uint32_t number_of_sent_messages_total_;
+ std::uint32_t number_of_acknowledged_messages_;
+
+ std::uint32_t payload_size_;
+
+ bool wait_for_all_msg_acknowledged_;
+ std::mutex all_msg_acknowledged_mutex_;
+ std::condition_variable all_msg_acknowledged_cv_;
+ std::vector<double> results_;
+ std::atomic<bool> initialized_;
+ std::thread sender_;
+};
+
+
+// this variables are changed via cmdline parameters
+static protocol_e protocol(protocol_e::PR_UNKNOWN);
+static std::uint32_t number_of_calls(0);
+static std::uint32_t payload_size(40);
+static bool call_service_sync(true);
+static bool shutdown_service(true);
+
+
+TEST(someip_load_test, DISABLED_send_messages_and_measure_cpu_load)
+{
+ cpu_load_test_client test_client_(protocol, number_of_calls, payload_size, call_service_sync, shutdown_service);
+}
+
+#if defined(__linux__) || defined(ANDROID)
+int main(int argc, char** argv)
+{
+ int i = 0;
+ while (i < argc) {
+ if(std::string("--protocol") == std::string(argv[i])
+ || std::string("-p") == std::string(argv[i])) {
+ if(std::string("udp") == std::string(argv[i+1]) ||
+ std::string("UDP") == std::string(argv[i+1])) {
+ protocol = protocol_e::PR_UDP;
+ i++;
+ } else if(std::string("tcp") == std::string(argv[i+1]) ||
+ std::string("TCP") == std::string(argv[i+1])) {
+ protocol = protocol_e::PR_TCP;
+ i++;
+ }
+ } else if(std::string("--calls") == std::string(argv[i])
+ || std::string("-c") == std::string(argv[i])) {
+ try {
+ number_of_calls = static_cast<std::uint32_t>(std::stoul(std::string(argv[i+1]), nullptr, 10));
+ } catch (const std::exception &e) {
+ std::cerr << "Please specify a valid value for number of calls" << std::endl;
+ return(EXIT_FAILURE);
+ }
+ i++;
+ } else if(std::string("--mode") == std::string(argv[i])
+ || std::string("-m") == std::string(argv[i])) {
+ if(std::string("sync") == std::string(argv[i+1]) ||
+ std::string("SYNC") == std::string(argv[i+1])) {
+ call_service_sync = true;
+ i++;
+ } else if(std::string("async") == std::string(argv[i+1]) ||
+ std::string("ASYNC") == std::string(argv[i+1])) {
+ call_service_sync = false;
+ i++;
+ }
+ } else if(std::string("--payload-size") == std::string(argv[i])
+ || std::string("-pl") == std::string(argv[i])) {
+ try {
+ payload_size = static_cast<std::uint32_t>(std::stoul(std::string(argv[i+1]), nullptr, 10));
+ } catch (const std::exception &e) {
+ std::cerr << "Please specify a valid values for payload size" << std::endl;
+ return(EXIT_FAILURE);
+ }
+ i++;
+ } else if(std::string("--help") == std::string(argv[i])
+ || std::string("-h") == std::string(argv[i])) {
+ std::cout << "Available options:" << std::endl;
+ std::cout << "--protocol|-p: valid values TCP or UDP" << std::endl;
+ std::cout << "--calls|-c: number of message calls to do" << std::endl;
+ std::cout << "--mode|-m: mode sync or async" << std::endl;
+ std::cout << "--payload-size|-pl: payload size in Bytes default: 40" << std::endl;
+ }
+ i++;
+ }
+
+ if(protocol == protocol_e::PR_UNKNOWN) {
+ std::cerr << "Please specify valid protocol mode, see --help" << std::endl;
+ return(EXIT_FAILURE);
+ }
+ if(!number_of_calls) {
+ std::cerr << "Please specify valid number of calls, see --help" << std::endl;
+ return(EXIT_FAILURE);
+ }
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp b/test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp
new file mode 100644
index 0000000..e6897e3
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_test_globals.hpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#pragma once
+
+namespace cpu_load_test {
+
+static constexpr vsomeip::service_t service_id(0x1111);
+static constexpr vsomeip::instance_t instance_id(0x1);
+static constexpr vsomeip::method_t method_id(0x1111);
+static constexpr vsomeip::byte_t load_test_data(0xDD);
+static constexpr vsomeip::length_t default_payload_length(40);
+static constexpr vsomeip::method_t method_id_shutdown(0x7777);
+static constexpr vsomeip::method_t method_id_cpu_measure_start(0x8888);
+static constexpr vsomeip::method_t method_id_cpu_measure_stop(0x9999);
+}
diff --git a/test/network_tests/cpu_load_tests/cpu_load_test_master_starter.sh b/test/network_tests/cpu_load_tests/cpu_load_test_master_starter.sh
new file mode 100755
index 0000000..30010c2
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_test_master_starter.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Purpose: This script is needed to start the services with
+# one command. This is necessary as ctest - which is used to run the
+# tests - isn't able to start multiple binaries for one testcase. Therefore
+# the testcase simply executes this script. This script then runs the services
+# and checks that all exit successfully.
+
+FAIL=0
+
+export VSOMEIP_CONFIGURATION=cpu_load_test_client_master.json
+./cpu_load_test_client --protocol UDP --calls 1000 &
+TEST_CLIENT_PID=$!
+sleep 1
+
+if [ ! -z "$USE_LXC_TEST" ]; then
+ echo "starting cpu load test on slave LXC"
+ ssh -tt -i $SANDBOX_ROOT_DIR/commonapi_main/lxc-config/.ssh/mgc_lxc/rsa_key_file.pub -o StrictHostKeyChecking=no root@$LXC_TEST_SLAVE_IP 'bash -ci "set -m; cd \$SANDBOX_TARGET_DIR/vsomeip_lib/test/network_tests; ./cpu_load_test_slave_starter.sh"' &
+elif [ ! -z "$USE_DOCKER" ]; then
+ docker exec $DOCKER_IMAGE sh -c "cd $DOCKER_TESTS && ./cpu_load_test_slave_starter.sh" &
+else
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Please now run:
+** cpu_load_test_slave_starter.sh
+** from an external host to successfully complete this test.
+**
+** You probably will need to adapt the 'unicast' settings in
+** cpu_load_test_client_master.json,
+** cpu_load_test_service_master.json,
+** cpu_load_test_client_client.json and
+** cpu_load_test_service_client.json to your personal setup.
+*******************************************************************************
+*******************************************************************************
+End-of-message
+fi
+
+# Fail gets incremented if either client or service exit
+# with a non-zero exit code
+wait $TEST_CLIENT_PID || FAIL=$(($FAIL+1))
+
+
+sleep 4
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Now switching roles and running service on this host (master)
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+export VSOMEIP_CONFIGURATION=cpu_load_test_service_master.json
+./cpu_load_test_service &
+sleep 1
+
+# now we can wait to all jobs to finish
+for job in $(jobs -p)
+do
+ # Fail gets incremented if either client or service exit
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi
diff --git a/test/network_tests/cpu_load_tests/cpu_load_test_service.cpp b/test/network_tests/cpu_load_tests/cpu_load_test_service.cpp
new file mode 100644
index 0000000..58c72e7
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_test_service.cpp
@@ -0,0 +1,209 @@
+// Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <gtest/gtest.h>
+
+#include <vsomeip/vsomeip.hpp>
+
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include <functional>
+#include <numeric>
+#include <cmath> // for isfinite
+
+#include "cpu_load_test_globals.hpp"
+#include <vsomeip/internal/logger.hpp>
+#include "cpu_load_measurer.hpp"
+
+// for getpid
+#include <sys/types.h>
+#include <unistd.h>
+
+class cpu_load_test_service
+{
+public:
+ cpu_load_test_service() :
+ app_(vsomeip::runtime::get()->create_application("cpu_load_test_service")),
+ is_registered_(false),
+ blocked_(false),
+ number_of_received_messages_(0),
+ number_of_received_messages_total_(0),
+ load_measurer_(static_cast<std::uint32_t>(::getpid())),
+ offer_thread_(std::bind(&cpu_load_test_service::run, this))
+ {
+ }
+
+ ~cpu_load_test_service() {
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ blocked_ = true;
+ condition_.notify_one();
+ }
+ offer_thread_.join();
+ }
+
+ bool init()
+ {
+ std::lock_guard<std::mutex> its_lock(mutex_);
+
+ if (!app_->init()) {
+ ADD_FAILURE() << "Couldn't initialize application";
+ return false;
+ }
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id,
+ std::bind(&cpu_load_test_service::on_message, this,
+ std::placeholders::_1));
+
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_shutdown,
+ std::bind(&cpu_load_test_service::on_message_shutdown, this,
+ std::placeholders::_1));
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_cpu_measure_start,
+ std::bind(&cpu_load_test_service::on_message_start_measuring, this,
+ std::placeholders::_1));
+ app_->register_message_handler(cpu_load_test::service_id,
+ cpu_load_test::instance_id, cpu_load_test::method_id_cpu_measure_stop,
+ std::bind(&cpu_load_test_service::on_message_stop_measuring, this,
+ std::placeholders::_1));
+ app_->register_state_handler(
+ std::bind(&cpu_load_test_service::on_state, this,
+ std::placeholders::_1));
+ return true;
+ }
+
+ void start()
+ {
+ VSOMEIP_INFO << "Starting...";
+ app_->start();
+ }
+
+ void stop()
+ {
+ VSOMEIP_INFO << "Stopping...";
+ app_->stop_offer_service(cpu_load_test::service_id, cpu_load_test::instance_id);
+ app_->clear_all_handler();
+ app_->stop();
+ }
+
+ void on_state(vsomeip::state_type_e _state)
+ {
+ VSOMEIP_INFO << "Application " << app_->get_name() << " is "
+ << (_state == vsomeip::state_type_e::ST_REGISTERED ? "registered." :
+ "deregistered.");
+
+ if(_state == vsomeip::state_type_e::ST_REGISTERED)
+ {
+ if(!is_registered_)
+ {
+ is_registered_ = true;
+ std::lock_guard<std::mutex> its_lock(mutex_);
+ blocked_ = true;
+ // "start" the run method thread
+ condition_.notify_one();
+ }
+ }
+ else
+ {
+ is_registered_ = false;
+ }
+ }
+
+ void on_message(const std::shared_ptr<vsomeip::message>& _request)
+ {
+ number_of_received_messages_++;
+ number_of_received_messages_total_++;
+ // send response
+ app_->send(vsomeip::runtime::get()->create_response(_request));
+ }
+
+ void on_message_start_measuring(const std::shared_ptr<vsomeip::message>& _request)
+ {
+ (void)_request;
+ load_measurer_.start();
+ }
+
+ void on_message_stop_measuring(const std::shared_ptr<vsomeip::message>& _request)
+ {
+ (void)_request;
+ load_measurer_.stop();
+ VSOMEIP_DEBUG << "Received " << std::setw(4) << std::setfill('0')
+ << number_of_received_messages_ << " messages. CPU load [%]: "
+ << std::fixed << std::setprecision(2)
+ << (std::isfinite(load_measurer_.get_cpu_load()) ? load_measurer_.get_cpu_load() : 0.0);
+ results_.push_back(std::isfinite(load_measurer_.get_cpu_load()) ? load_measurer_.get_cpu_load() : 0.0);
+ number_of_received_messages_ = 0;
+ }
+
+ void on_message_shutdown(
+ const std::shared_ptr<vsomeip::message>& _request)
+ {
+ (void)_request;
+ VSOMEIP_INFO << "Shutdown method was called, going down now.";
+ const double average_load(std::accumulate(results_.begin(), results_.end(), 0.0) / static_cast<double>(results_.size()));
+ VSOMEIP_INFO << "Received: " << number_of_received_messages_total_
+ << " in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load << "% load in average (average of "
+ << results_.size() << " measurements).";
+
+ std::vector<double> results_no_zero;
+ for(const auto &v : results_) {
+ if(v > 0.0) {
+ results_no_zero.push_back(v);
+ }
+ }
+ const double average_load_no_zero(std::accumulate(results_no_zero.begin(), results_no_zero.end(), 0.0) / static_cast<double>(results_no_zero.size()));
+ VSOMEIP_INFO << "Sent: " << number_of_received_messages_total_
+ << " messages in total (excluding control messages). This caused: "
+ << std::fixed << std::setprecision(2)
+ << average_load_no_zero << "% load in average, if measured cpu load "
+ << "was greater zero (average of "
+ << results_no_zero.size() << " measurements).";
+ stop();
+ }
+
+ void run()
+ {
+ std::unique_lock<std::mutex> its_lock(mutex_);
+ while (!blocked_) {
+ condition_.wait(its_lock);
+ }
+
+ app_->offer_service(cpu_load_test::service_id, cpu_load_test::instance_id);
+ }
+
+private:
+ std::shared_ptr<vsomeip::application> app_;
+ bool is_registered_;
+
+ std::mutex mutex_;
+ std::condition_variable condition_;
+ bool blocked_;
+ std::uint32_t number_of_received_messages_;
+ std::uint32_t number_of_received_messages_total_;
+ cpu_load_measurer load_measurer_;
+ std::vector<double> results_;
+ std::thread offer_thread_;
+};
+
+
+TEST(someip_payload_test, DISABLED_send_response_for_every_request)
+{
+ cpu_load_test_service test_service;
+ if (test_service.init()) {
+ test_service.start();
+ }
+}
+
+#if defined(__linux__) || defined(ANDROID)
+int main(int argc, char** argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+#endif
diff --git a/test/network_tests/cpu_load_tests/cpu_load_test_slave_starter.sh b/test/network_tests/cpu_load_tests/cpu_load_test_slave_starter.sh
new file mode 100755
index 0000000..83ef19d
--- /dev/null
+++ b/test/network_tests/cpu_load_tests/cpu_load_test_slave_starter.sh
@@ -0,0 +1,52 @@
+#!/bin/bash
+# Copyright (C) 2015-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# Purpose: This script is needed to start the services with
+# one command. This is necessary as ctest - which is used to run the
+# tests - isn't able to start multiple binaries for one testcase. Therefore
+# the testcase simply executes this script. This script then runs the services
+# and checks that all exit successfully.
+
+FAIL=0
+
+export VSOMEIP_CONFIGURATION=cpu_load_test_service_slave.json
+./cpu_load_test_service &
+
+# Wait until all applications are finished
+for job in $(jobs -p)
+do
+ # Fail gets incremented if one of the binaries exits
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+cat <<End-of-message
+*******************************************************************************
+*******************************************************************************
+** Now switching roles and running client on this host (slave)
+*******************************************************************************
+*******************************************************************************
+End-of-message
+
+sleep 4
+export VSOMEIP_CONFIGURATION=cpu_load_test_client_slave.json
+./cpu_load_test_client --protocol UDP --calls 1000 &
+
+for job in $(jobs -p)
+do
+ # Fail gets incremented if one of the binaries exits
+ # with a non-zero exit code
+ wait $job || FAIL=$(($FAIL+1))
+done
+
+
+# Check if both exited successfully
+if [ $FAIL -eq 0 ]
+then
+ exit 0
+else
+ exit 1
+fi