mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-30 00:00:15 +01:00
150 lines
3.7 KiB
C
150 lines
3.7 KiB
C
// Copyright (c) 2018 Colin Finck, RWTH Aachen University
|
|
//
|
|
// MIT License
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
////////////////////////////////////
|
|
//// HERMITCORE C-SPECIFIC CODE ////
|
|
|
|
#include <hermit/syscall.h>
|
|
|
|
#define NORMAL_PRIO 8
|
|
typedef int (*entry_point_t)(void*);
|
|
int create_kernel_task_on_core(tid_t* id, entry_point_t ep, void* args, uint8_t prio, uint32_t core_id);
|
|
void reschedule(void);
|
|
|
|
inline static void create_second_task(void (*entry_point)(void*))
|
|
{
|
|
create_kernel_task_on_core(NULL, (entry_point_t)entry_point, NULL, NORMAL_PRIO, 0);
|
|
}
|
|
|
|
inline static void consume_task_time(void)
|
|
{
|
|
// Not required for the HermitCore C version.
|
|
}
|
|
|
|
inline static void switch_task(void)
|
|
{
|
|
reschedule();
|
|
}
|
|
|
|
|
|
///////////////////////////////////
|
|
//// THE ACTUAL BENCHMARK CODE ////
|
|
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
// You can enable this for debugging without any effect on the measurement.
|
|
//#define DEBUG_MESSAGES
|
|
|
|
#define N 1000
|
|
static bool finished;
|
|
static unsigned long long start;
|
|
static unsigned long long sum;
|
|
|
|
inline static unsigned long long rdtsc(void)
|
|
{
|
|
unsigned long lo, hi;
|
|
asm volatile ("rdtsc" : "=a"(lo), "=d"(hi) :: "memory");
|
|
return ((unsigned long long) hi << 32ULL | (unsigned long long) lo);
|
|
}
|
|
|
|
void second_task(void* arg)
|
|
{
|
|
unsigned long long end;
|
|
|
|
for(;;)
|
|
{
|
|
// Calculate the cycle difference and add it to the sum.
|
|
end = rdtsc();
|
|
sum += (end - start);
|
|
|
|
// Check if the benchmark has finished and we can end the second task.
|
|
if (finished)
|
|
{
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUG_MESSAGES
|
|
printf("Hello from task 2\n");
|
|
#endif
|
|
|
|
consume_task_time();
|
|
|
|
// Save the current Time Stamp Counter value and switch back to the
|
|
// first task.
|
|
start = rdtsc();
|
|
switch_task();
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
int i;
|
|
unsigned long long end;
|
|
|
|
// Start the second task with the same priority on the boot processor.
|
|
create_second_task(second_task);
|
|
|
|
// Initialize the benchmark.
|
|
printf("taskswitch test\n");
|
|
printf("===============\n");
|
|
|
|
finished = false;
|
|
sum = 0;
|
|
|
|
// Warm up
|
|
switch_task();
|
|
switch_task();
|
|
|
|
// Run the benchmark.
|
|
sum = 0;
|
|
for(i = 0; i < N; i++)
|
|
{
|
|
#ifdef DEBUG_MESSAGES
|
|
printf("Hello from task 1\n");
|
|
#endif
|
|
|
|
consume_task_time();
|
|
|
|
// Save the current Time Stamp Counter value and switch to the second
|
|
// task.
|
|
start = rdtsc();
|
|
switch_task();
|
|
|
|
// Calculate the cycle difference and add it to the sum.
|
|
end = rdtsc();
|
|
sum += (end - start);
|
|
}
|
|
|
|
// Calculate and print the results.
|
|
// In every loop iteration, task 1 switches to task 2 and task 2 switches
|
|
// back to task 1.
|
|
// Therefore, the total number needs to be divided by 2.
|
|
printf("Average time for a task switch: %lld cycles\n", sum / (N * 2));
|
|
|
|
// Finish the second task gracefully.
|
|
finished = true;
|
|
switch_task();
|
|
|
|
return 0;
|
|
}
|