started analysis + refactoring of code

This commit is contained in:
Niklas Halle 2025-03-29 15:20:20 +01:00
parent 9209ace569
commit 587c6d1fab
9 changed files with 11910 additions and 11421 deletions

View file

@ -33,7 +33,8 @@
"ms-vscode.cmake-tools",
"ms-azuretools.vscode-docker",
"ms-vscode.cpptools-themes",
"ms-iot.vscode-ros"
"ms-iot.vscode-ros",
"GitHub.github-vscode-theme"
]
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

View file

@ -100,28 +100,9 @@ int main(int argc, char *argv[])
{
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": " << strerror(errno) << std::endl;
}
// calibrate the dummy load
// Naive way to calibrate dummy workload for current system
int dummy_load_calib = 1;
while (1)
{
timeval ctime, ftime;
int duration_us;
gettimeofday(&ctime, NULL);
dummy_load(100); // 100ms
gettimeofday(&ftime, NULL);
duration_us = (ftime.tv_sec - ctime.tv_sec) * 1000000 + (ftime.tv_usec - ctime.tv_usec);
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "dummy_load_calib: %d (duration_us: %d ns)", dummy_load_calib, duration_us);
if (abs(duration_us - 100 * 1000) < 500)
{ // error margin: 500us
break;
}
dummy_load_calib = 100 * 1000 * dummy_load_calib / duration_us;
if (dummy_load_calib <= 0)
dummy_load_calib = 1;
DummyLoadCalibration::setCalibration(dummy_load_calib);
}
// DummyLoadCalibration::setCalibration(2900);
// calibrate the dummy load for the current system
calibrate_dummy_load();
ExperimentConfig config;
// config.chain_lengths = {4, 3, 4};

View file

@ -112,29 +112,10 @@ int main(int argc, char *argv[]) {
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": "
<< strerror(errno) << std::endl;
}
// calibrate the dummy load
// Naive way to calibrate dummy workload for current system
int dummy_load_calib = 1;
while (1) {
timeval ctime, ftime;
int duration_us;
gettimeofday(&ctime, NULL);
dummy_load(100); // 100ms
gettimeofday(&ftime, NULL);
duration_us = (ftime.tv_sec - ctime.tv_sec) * 1000000 +
(ftime.tv_usec - ctime.tv_usec);
RCLCPP_INFO(rclcpp::get_logger("rclcpp"),
"dummy_load_calib: %d (duration_us: %d ns)", dummy_load_calib,
duration_us);
if (abs(duration_us - 100 * 1000) < 500) { // error margin: 500us
break;
}
dummy_load_calib = 100 * 1000 * dummy_load_calib / duration_us;
if (dummy_load_calib <= 0)
dummy_load_calib = 1;
DummyLoadCalibration::setCalibration(dummy_load_calib);
}
// DummyLoadCalibration::setCalibration(2900);
// calibrate the dummy load for the current system
calibrate_dummy_load();
ExperimentConfig config;
// runtimes and timers subject to change

View file

@ -113,29 +113,9 @@ int main(int argc, char *argv[]) {
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": "
<< strerror(errno) << std::endl;
}
// calibrate the dummy load
// Naive way to calibrate dummy workload for current system
int dummy_load_calib = 1;
while (1) {
timeval ctime, ftime;
int duration_us;
gettimeofday(&ctime, NULL);
dummy_load(100); // 100ms
gettimeofday(&ftime, NULL);
duration_us = (ftime.tv_sec - ctime.tv_sec) * 1000000 +
(ftime.tv_usec - ctime.tv_usec);
RCLCPP_INFO(rclcpp::get_logger("rclcpp"),
"dummy_load_calib: %d (duration_us: %d ns)", dummy_load_calib,
duration_us);
if (abs(duration_us - 100 * 1000) < 500) { // error margin: 500us
break;
}
dummy_load_calib = 100 * 1000 * dummy_load_calib / duration_us;
if (dummy_load_calib <= 0)
dummy_load_calib = 1;
DummyLoadCalibration::setCalibration(dummy_load_calib);
}
// DummyLoadCalibration::setCalibration(2900);
// calibrate the dummy load for the current system
calibrate_dummy_load();
ExperimentConfig config;
// runtimes and timers subject to change

View file

@ -1,15 +1,20 @@
#include "rclcpp/rclcpp.hpp"
#include "priority_executor/priority_executor.hpp"
#include "priority_executor/priority_memory_strategy.hpp"
#include "casestudy_tools/test_nodes.hpp"
#include <cmath>
#include <chrono>
#include <string>
#include <fstream>
#include <iostream>
#include <unistd.h>
#include "std_msgs/msg/string.hpp"
#include "casestudy_tools/primes_workload.hpp"
#include <sys/prctl.h>
#include "casestudy_tools/primes_workload.hpp"
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
#include "casestudy_tools/test_nodes.hpp"
#include "casestudy_tools/experiment.hpp"
#include "casestudy_tools/primes_workload.hpp"
#include "priority_executor/priority_executor.hpp"
#include "priority_executor/priority_memory_strategy.hpp"
// bool should_do_task = true;
std::atomic<bool> should_do_task(true);
@ -36,10 +41,11 @@ void run_one_executor(std::function<void(std::atomic<bool> &)> exec_fun, int idx
int result = sched_setscheduler(0, SCHED_FIFO, &param);
if (result != 0)
{
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": " << strerror(errno) << std::endl;
std::cerr << "ros_experiment: sched_setscheduler failed: " << result << ": " << strerror(errno) << std::endl;
std::cerr << "This operation requires root privileges. Please run the program with sufficient permissions." << std::endl;
exit(EXIT_FAILURE);
}
// set process name
// Set the process name to "ros_experiment" for easier identification during debugging or system monitoring.
prctl(PR_SET_NAME, "ros_experiment", 0, 0, 0);
exec_fun(should_do_task);
@ -59,6 +65,9 @@ int ros_experiment(int argc, char **arg, std::string file_name, ExperimentConfig
// TODO: move experiment configuration to main
config.executor_type = executor_type;
// Enable parallel mode for the experiment configuration.
// When set to true, this allows multiple executors to run concurrently,
// leveraging multi-threading to improve performance on multi-core systems.
config.parallel_mode = true;
config.nodes.push_back(node);
@ -87,30 +96,9 @@ int ros_experiment(int argc, char **arg, std::string file_name, ExperimentConfig
int main(int argc, char *argv[])
{
// calibrate the dummy load
// Naive way to calibrate dummy workload for current system
int dummy_load_calib = 1;
while (1)
{
timeval ctime, ftime;
int duration_us;
gettimeofday(&ctime, NULL);
dummy_load(100); // 100ms
gettimeofday(&ftime, NULL);
duration_us = (ftime.tv_sec - ctime.tv_sec) * 1000000 + (ftime.tv_usec - ctime.tv_usec);
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "dummy_load_calib: %d (duration_us: %d ns)", dummy_load_calib, duration_us);
if (abs(duration_us - 100 * 1000) < 500)
{ // error margin: 500us
break;
}
dummy_load_calib = 100 * 1000 * dummy_load_calib / duration_us;
if (dummy_load_calib <= 0)
{
dummy_load_calib = 1;
}
DummyLoadCalibration::setCalibration(dummy_load_calib);
}
// DummyLoadCalibration::setCalibration(2900);
// calibrate the dummy load for the current system
calibrate_dummy_load();
ExperimentConfig config;
config.chain_lengths = {2, 2};
config.node_ids = {{0, 1}, {2, 3}};
@ -126,7 +114,20 @@ int main(int argc, char *argv[])
sanity_check_config(config);
std::thread ros_task(ros_experiment, argc, argv, "cs_example", config);
std::thread ros_task([&]() {
try
{
ros_experiment(argc, argv, "cs_example", config);
}
catch (const std::exception &e)
{
std::cerr << "Exception in ros_experiment: " << e.what() << std::endl;
}
catch (...)
{
std::cerr << "Unknown exception in ros_experiment." << std::endl;
}
});
std::cout << "tasks started" << std::endl;
ros_task.join();
std::cout << "tasks joined" << std::endl;

View file

@ -1,22 +1,44 @@
#ifndef RTIS_PRIMES_WORKLOAD
#define RTIS_PRIMES_WORKLOAD
#include <time.h>
#include <sys/time.h>
#include <thread>
#include <cstdio>
typedef double ktimeunit;
ktimeunit nth_prime_silly(double millis = 100);
void dummy_load(int load_ms);
// create a global variable to store the calibration value
class DummyLoadCalibration
#include <time.h>
#include <sys/time.h>
// Parameters for the dummy load calibration
constexpr int TARGET_DURATION_MS = 100;
constexpr int MAX_ITERATIONS = 100;
constexpr int ACCEPTABLE_MARGIN_US = 500;
/**
* @brief Dummy load calibration namespace.
* This namespace contains functions and variables for calibrating the dummy load.
* It uses an atomic integer to store the calibration factor.
* The calibration factor is used to adjust the workload of the dummy load function.
*/
namespace DummyLoadCalibration
{
public:
static int getCalibration();
static void setCalibration(int calib);
inline std::atomic<int> calibration{1};
private:
static int calibration;
};
inline void setCalibration(int calib);
inline int getCalibration();
}
/**
* @brief Dummy load function to simulate a workload.
* This function performs a busy wait for a specified duration.
* It is used to calibrate the dummy load for the current system.
*/
void calibrate_dummy_load();
/**
* @brief Dummy load function to simulate a workload.
* This function performs a busy wait for a specified duration.
* It is used to calibrate the dummy load for the current system.
*/
void dummy_load(int load_ms);
ktimeunit get_thread_time(struct timespec *currTime);
#endif

View file

@ -1,67 +1,71 @@
#include "casestudy_tools/primes_workload.hpp"
#include <chrono>
#include <thread>
#include <atomic>
#include <iostream>
ktimeunit nth_prime_silly(double millis)
{
// struct tms this_thread_times;
struct timespec currTime;
int sum = 0;
int i;
int j;
ktimeunit const start_cpu_time = get_thread_time(&currTime);
ktimeunit last_iter_time = 0;
ktimeunit last_iter_start_time = start_cpu_time;
for (i = 2; i < 4294967296 - 1; i++)
{
// times(&this_thread_times);
ktimeunit cum_time = get_thread_time(&currTime);
last_iter_time = cum_time - last_iter_start_time;
last_iter_start_time = cum_time;
if ((cum_time - start_cpu_time + last_iter_time*2) > millis)
{
break;
}
for (j = 2; j < i; j++)
{
sum += j;
}
if (cum_time - start_cpu_time > millis)
{
std::cout << "Warning: Time limit exceeded" << std::endl;
}
}
// std::cout<< "took " << (get_thread_time(&currTime) - start_cpu_time) << "ms, allowed " << millis << "ms" << std::endl;
return get_thread_time(&currTime) - start_cpu_time;
}
ktimeunit get_thread_time(struct timespec *currTime)
{
// clockid_t threadClockId;
// pthread_getcpuclockid(pthread_self(), &threadClockId);
// clock_gettime(threadClockId, currTime);
// return currTime->tv_nsec / 1000000.0 + currTime->tv_sec * 1000.0;
// use the wall clock instead
clock_gettime(CLOCK_MONOTONIC_RAW, currTime);
return currTime->tv_nsec / 1000000.0 + currTime->tv_sec * 1000.0;
}
#include "casestudy_tools/primes_workload.hpp"
#define DUMMY_LOAD_ITER 100000
void dummy_load(int load_ms) {
int i, j;
int dummy_load_calib = DummyLoadCalibration::getCalibration();
// dummy_load_calib is for 100ms
dummy_load_calib = dummy_load_calib * load_ms / 100;
for (j = 0; j < dummy_load_calib; j++)
for (i = 0 ; i < DUMMY_LOAD_ITER; i++)
__asm__ volatile ("nop");
}
void DummyLoadCalibration::setCalibration(int calib) {
DummyLoadCalibration::calibration = calib;
calibration.store(calib, std::memory_order_relaxed);
}
int DummyLoadCalibration::getCalibration() {
return DummyLoadCalibration::calibration;
return calibration.load(std::memory_order_relaxed);
}
int DummyLoadCalibration::calibration = 1;
void calibrate_dummy_load()
{
int calibration_factor = 1;
for (int iteration = 0; iteration < MAX_ITERATIONS; ++iteration)
{
// Measure the time taken for the dummy load
auto start_time = std::chrono::high_resolution_clock::now();
dummy_load(TARGET_DURATION_MS); // intended workload
auto end_time = std::chrono::high_resolution_clock::now();
// Calculate duration in microseconds
auto duration_us =
std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time).count();
std::cout << "[Calibration] Iteration: " << iteration
<< ", Calibration Factor: " << calibration_factor
<< ", Measured Duration: " << duration_us << " µs" << std::endl;
// Check if within acceptable margin
if (std::abs(duration_us - TARGET_DURATION_MS * 1000) < ACCEPTABLE_MARGIN_US)
{
std::cout << "[Calibration] Converged successfully." << std::endl;
break;
}
// Adjust calibration factor proportionally
calibration_factor = (TARGET_DURATION_MS * 1000 * calibration_factor) / duration_us;
if (calibration_factor <= 0)
{
calibration_factor = 1;
}
DummyLoadCalibration::setCalibration(calibration_factor);
}
}
void dummy_load(int load_ms)
{
const int calib_factor = DummyLoadCalibration::getCalibration();
// calibration factor corresponds to 100ms load, scale it
const int scaled_factor = calib_factor * load_ms / 100;
volatile int dummy_var = 0;
constexpr int DUMMY_LOAD_ITER = 100'000;
for (int j = 0; j < scaled_factor; ++j)
{
for (int i = 0; i < DUMMY_LOAD_ITER; ++i)
{
dummy_var += i; // clearer dummy operation (optimizations prevented by volatile)
}
}
}