started analysis + refactoring of code
This commit is contained in:
parent
9209ace569
commit
587c6d1fab
9 changed files with 11910 additions and 11421 deletions
|
@ -33,7 +33,8 @@
|
||||||
"ms-vscode.cmake-tools",
|
"ms-vscode.cmake-tools",
|
||||||
"ms-azuretools.vscode-docker",
|
"ms-azuretools.vscode-docker",
|
||||||
"ms-vscode.cpptools-themes",
|
"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
|
@ -100,28 +100,9 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": " << strerror(errno) << std::endl;
|
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": " << strerror(errno) << std::endl;
|
||||||
}
|
}
|
||||||
// calibrate the dummy load
|
// calibrate the dummy load for the current system
|
||||||
// Naive way to calibrate dummy workload for current system
|
calibrate_dummy_load();
|
||||||
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);
|
|
||||||
ExperimentConfig config;
|
ExperimentConfig config;
|
||||||
|
|
||||||
// config.chain_lengths = {4, 3, 4};
|
// config.chain_lengths = {4, 3, 4};
|
||||||
|
|
|
@ -112,29 +112,10 @@ int main(int argc, char *argv[]) {
|
||||||
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": "
|
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": "
|
||||||
<< strerror(errno) << std::endl;
|
<< strerror(errno) << std::endl;
|
||||||
}
|
}
|
||||||
// calibrate the dummy load
|
|
||||||
// Naive way to calibrate dummy workload for current system
|
// calibrate the dummy load for the current system
|
||||||
int dummy_load_calib = 1;
|
calibrate_dummy_load();
|
||||||
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);
|
|
||||||
ExperimentConfig config;
|
ExperimentConfig config;
|
||||||
|
|
||||||
// runtimes and timers subject to change
|
// runtimes and timers subject to change
|
||||||
|
|
|
@ -113,29 +113,9 @@ int main(int argc, char *argv[]) {
|
||||||
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": "
|
std::cout << "ros_experiment: sched_setscheduler failed: " << result << ": "
|
||||||
<< strerror(errno) << std::endl;
|
<< strerror(errno) << std::endl;
|
||||||
}
|
}
|
||||||
// calibrate the dummy load
|
// calibrate the dummy load for the current system
|
||||||
// Naive way to calibrate dummy workload for current system
|
calibrate_dummy_load();
|
||||||
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);
|
|
||||||
ExperimentConfig config;
|
ExperimentConfig config;
|
||||||
|
|
||||||
// runtimes and timers subject to change
|
// runtimes and timers subject to change
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
#include "rclcpp/rclcpp.hpp"
|
#include <cmath>
|
||||||
#include "priority_executor/priority_executor.hpp"
|
#include <chrono>
|
||||||
#include "priority_executor/priority_memory_strategy.hpp"
|
|
||||||
#include "casestudy_tools/test_nodes.hpp"
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "std_msgs/msg/string.hpp"
|
|
||||||
#include "casestudy_tools/primes_workload.hpp"
|
|
||||||
#include <sys/prctl.h>
|
#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/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;
|
// bool should_do_task = true;
|
||||||
std::atomic<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, ¶m);
|
int result = sched_setscheduler(0, SCHED_FIFO, ¶m);
|
||||||
if (result != 0)
|
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 the process name to "ros_experiment" for easier identification during debugging or system monitoring.
|
||||||
// set process name
|
|
||||||
prctl(PR_SET_NAME, "ros_experiment", 0, 0, 0);
|
prctl(PR_SET_NAME, "ros_experiment", 0, 0, 0);
|
||||||
|
|
||||||
exec_fun(should_do_task);
|
exec_fun(should_do_task);
|
||||||
|
@ -59,12 +65,15 @@ int ros_experiment(int argc, char **arg, std::string file_name, ExperimentConfig
|
||||||
|
|
||||||
// TODO: move experiment configuration to main
|
// TODO: move experiment configuration to main
|
||||||
config.executor_type = executor_type;
|
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.parallel_mode = true;
|
||||||
config.nodes.push_back(node);
|
config.nodes.push_back(node);
|
||||||
|
|
||||||
Experiment experiment(config);
|
Experiment experiment(config);
|
||||||
// std::string result_log = experiment.run(should_do_task);
|
// std::string result_log = experiment.run(should_do_task);
|
||||||
std::vector<std::function<void(std::atomic<bool> &)>> exec_funs = experiment.getRunFunctions();
|
std::vector<std::function<void(std::atomic<bool> &)> > exec_funs = experiment.getRunFunctions();
|
||||||
std::cout << "got " << exec_funs.size() << " executors" << std::endl;
|
std::cout << "got " << exec_funs.size() << " executors" << std::endl;
|
||||||
std::vector<std::thread> exec_threads;
|
std::vector<std::thread> exec_threads;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -87,30 +96,9 @@ int ros_experiment(int argc, char **arg, std::string file_name, ExperimentConfig
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// calibrate the dummy load
|
// calibrate the dummy load for the current system
|
||||||
// Naive way to calibrate dummy workload for current system
|
calibrate_dummy_load();
|
||||||
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);
|
|
||||||
ExperimentConfig config;
|
ExperimentConfig config;
|
||||||
config.chain_lengths = {2, 2};
|
config.chain_lengths = {2, 2};
|
||||||
config.node_ids = {{0, 1}, {2, 3}};
|
config.node_ids = {{0, 1}, {2, 3}};
|
||||||
|
@ -126,7 +114,20 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
sanity_check_config(config);
|
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;
|
std::cout << "tasks started" << std::endl;
|
||||||
ros_task.join();
|
ros_task.join();
|
||||||
std::cout << "tasks joined" << std::endl;
|
std::cout << "tasks joined" << std::endl;
|
||||||
|
|
|
@ -1,22 +1,44 @@
|
||||||
#ifndef RTIS_PRIMES_WORKLOAD
|
#ifndef RTIS_PRIMES_WORKLOAD
|
||||||
#define RTIS_PRIMES_WORKLOAD
|
#define RTIS_PRIMES_WORKLOAD
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
typedef double ktimeunit;
|
|
||||||
ktimeunit nth_prime_silly(double millis = 100);
|
#include <time.h>
|
||||||
void dummy_load(int load_ms);
|
#include <sys/time.h>
|
||||||
// create a global variable to store the calibration value
|
|
||||||
class DummyLoadCalibration
|
// 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:
|
inline std::atomic<int> calibration{1};
|
||||||
static int getCalibration();
|
|
||||||
static void setCalibration(int calib);
|
|
||||||
|
|
||||||
private:
|
inline void setCalibration(int calib);
|
||||||
static int calibration;
|
|
||||||
};
|
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
|
#endif
|
|
@ -1,67 +1,71 @@
|
||||||
#include "casestudy_tools/primes_workload.hpp"
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
#include <iostream>
|
#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
|
#include "casestudy_tools/primes_workload.hpp"
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, currTime);
|
|
||||||
return currTime->tv_nsec / 1000000.0 + currTime->tv_sec * 1000.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#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) {
|
void DummyLoadCalibration::setCalibration(int calib) {
|
||||||
DummyLoadCalibration::calibration = calib;
|
calibration.store(calib, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DummyLoadCalibration::getCalibration() {
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue