started analysis + refactoring of code
This commit is contained in:
parent
9209ace569
commit
587c6d1fab
9 changed files with 11910 additions and 11421 deletions
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, ¶m);
|
||||
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,12 +65,15 @@ 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);
|
||||
|
||||
Experiment experiment(config);
|
||||
// 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::vector<std::thread> exec_threads;
|
||||
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[])
|
||||
{
|
||||
// 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;
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue