From 7da6d5408f4002e71c1754ecd09765dee493b84c Mon Sep 17 00:00:00 2001 From: Tobias Langer Date: Sat, 8 Oct 2016 16:43:39 +0200 Subject: [PATCH] Added template for cpp file. --- templates/normal/experiment.cpp | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/templates/normal/experiment.cpp b/templates/normal/experiment.cpp index e69de29..bd81e60 100644 --- a/templates/normal/experiment.cpp +++ b/templates/normal/experiment.cpp @@ -0,0 +1,228 @@ +#include +#include +#include + +#include + +#include + +#include "defines.h" + +#define UNUSED(x) ((void)(x)) + +#define DOMAIN_ID 1 +#define NODE_ID 1 +#define ACTION_ID 2 + +auto gcd(long long a, long long b) -> long long +{ + return b == 0 ? a : gcd(b, a % b); +} + +auto lcm(long long a, long long b) -> long long +{ + return (a * b) / gcd(a, b); +} + +auto calculate_hyperperiod() -> long long +{ + long long hyperperiod = taskset[0].period; + for(int i = 1; i < taskset_length; i++) { + hyperperiod = lcm(hyperperiod, taskset[i].period); + } + return hyperperiod; +} + +struct timestamps { + base_clock::time_point start; + base_clock::time_point end; + int core_id = 0; +}; + +base_clock::time_point start; +base_clock::time_point end; +std::vector benchmark[taskset_length]; + +void benchmark_out() +{ + using namespace std::chrono; + + std::cout << "benchmark results "; + std::cout << "start " << base_clock::to_time_t(start) << " "; + std::cout << "end " << base_clock::to_time_t(end) << std::endl; + + for(int i = 0; i < taskset_length; i++) { + std::cout << "task " << i << " "; + std::cout << "wcet " << taskset[i].wcet << " "; + std::cout << "period " << taskset[i].period << " "; + std::cout << "deadline " << taskset[i].deadline << " "; + std::cout << "executions " << taskset[i].count << std::endl; + + for(int j = 0; j < benchmark[i].size(); j++) { + auto start = base_clock::to_time_t(benchmark[i][j].start); + auto end = base_clock::to_time_t(benchmark[i][j].end); + auto core_id = benchmark[i][j].core_id; + std::cout << "instance " << i << " "; + std::cout << "start " << start << " "; + std::cout << "end " << end << " "; + std::cout << "core_id " << core_id << std::endl; + } + } +} + +/****** + * Task Declarations + ******/ + +/* Workaround helper function, the base node action is not initialized if the + * node gets attributes set. + */ +static void ActionFunction( + const void* args, + mtapi_size_t /*args_size*/, + void* /*result_buffer*/, + mtapi_size_t /*result_buffer_size*/, + const void* /*node_local_data*/, + mtapi_size_t /*node_local_data_size*/, + mtapi_task_context_t * context) { + embb::mtapi::TaskContext task_context(context); + embb::base::Function * func = + reinterpret_cast*>( + const_cast(args)); + (*func)(task_context); + embb::base::Allocation::Delete(func); +} + +static void IdleTask(const void* args, mtapi_size_t, void*, mtapi_size_t, + const void*, mtapi_size_t, mtapi_task_context_t*) +{ + using namespace std::chrono; + /* Get access to parameter data. */ + auto data = static_cast*>(args); + + auto task_id = data->first; + auto task_num = data->second; + auto start_time = base_clock::now(); + + /* idle until task completion. */ + auto idle_time = cpp_time_base(taskset[task_id].wcet); + std::this_thread::sleep_for(idle_time); + + /* Store our benchmarking data. */ + auto end_time = base_clock::now(); + int core_id = sched_getcpu(); + + benchmark[task_id][task_num - 1].start = start_time; + benchmark[task_id][task_num - 1].end = end_time; + benchmark[task_id][task_num - 1].core_id = core_id; +} + +/**** + * Main loop of task starter core. + ****/ + +static void TaskStarter() +{ + /* Initialize task starter */ + auto& node = embb::mtapi::Node::GetInstance(); + /* Storage for any task which is started. */ + std::vector running; + /* Storage for task parameters. */ + std::vector> running_num; + + auto hyperperiod = calculate_hyperperiod(); + + using namespace std::chrono; + + start = base_clock::now(); + + auto cur_time = duration_cast(base_clock::now() - start); + std::cerr << "Starting TaskStarter thread at: "; + std::cerr << base_clock::to_time_t(start) << std::endl; + + while(cur_time.count() < hyperperiod) { + auto min = cpp_time_base::max(); + + /* Check for every task if it has to be executed. */ + for(int i = 0; i < taskset_length; i++) { + auto task_period = cpp_time_base(taskset[i].period); + /* Execute always then when a next period has started, meaning when + * cur_time / task_period is bigger than for the last check. The + * first task_period is to let the tasks start at time 0 and not at + * time task_period. + */ + auto count = (cur_time + task_period) / task_period; + + /* Check how long to sleep next, either min(cur_time % period), or + * period if cur_time % period == 0 + */ + auto remaining = cur_time % task_period; + remaining = remaining.count() == 0 ? task_period : remaining; + if(remaining < min) { + min = remaining; + } + + if(count > taskset[i].count) { + embb::mtapi::ExecutionPolicy deadline_policy(embb_time_base(taskset[i].deadline)); + /* Store parameters for execution. + * The count may change during the execution, therefore we have + * to make sure that all possible running tasks can access their + * parameters. + */ + running_num.push_back(std::make_pair(i,count)); + node.CreateAction(ACTION_ID + i + 1, IdleTask); + auto job = node.GetJob(ACTION_ID + i + 1, DOMAIN_ID); + + int tmp; auto t = node.Start(job, &running_num.back(), &tmp); + + /* Store task to wait for it. */ + running.push_back(t); + taskset[i].count = count; + } + } + + std::this_thread::sleep_for(min); + cur_time = duration_cast(base_clock::now() - start); + } + + /* Wait for all started tasks to be completed. */ + for(auto& task : running) { + task.Wait(MTAPI_INFINITE); + } + + end = base_clock::now(); + std::cerr << "Finishing TaskStarter thread at: "; + std::cerr << base_clock::to_time_t(end) << std::endl; +} + +int main(int argc, char* argv[]) +{ + UNUSED(argc); + UNUSED(argv); + + /* Initialize node and set global edf as scheduling method. */ + embb::mtapi::NodeAttributes attr; + attr.SetSchedulerMode(GLOBAL_EDF); + embb::mtapi::Node::Initialize(DOMAIN_ID, NODE_ID, attr); + auto& node = embb::mtapi::Node::GetInstance(); + + /* Initialize storage for benchmarking data */ + auto hyperperiod = calculate_hyperperiod(); + for(int i = 0; i < taskset_length; i++) { + auto job_count = hyperperiod / taskset[i].period; + benchmark[i] = std::vector(job_count); + } + + /* Workaround, the base node action is not initialized if the node gets + * attributes set. + */ + node.CreateAction(ACTION_ID, ActionFunction); + + /* Start task loop */ + TaskStarter(); + + /* Print experiment results. */ + benchmark_out(); + + return 0; +} -- libgit2 0.26.0