1/*
2 * Copyright 2016, General Dynamics C4 Systems
3 *
4 * This software may be distributed and modified according to the terms of
5 * the GNU General Public License version 2. Note that NO WARRANTY is provided.
6 * See "LICENSE_GPLv2.txt" for details.
7 *
8 * @TAG(GD_GPL)
9 */
10
11#ifndef BENCHMARK_UTILISATION_H
12#define BENCHMARK_UTILISATION_H
13
14#include <config.h>
15#include <arch/benchmark.h>
16#include <benchmark/benchmark_utilisation_types.h>
17#include <arch/api/constants.h>
18#include <model/statedata.h>
19
20#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
21#include <armv/benchmark_irqHandler.h>
22#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
23
24#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
25extern bool_t benchmark_log_utilisation_enabled;
26extern timestamp_t ksEnter;
27extern timestamp_t benchmark_start_time;
28extern timestamp_t benchmark_end_time;
29
30void benchmark_track_utilisation_dump(void);
31
32void benchmark_track_reset_utilisation(void);
33/* Calculate and add the utilisation time from when the heir started to run i.e. scheduled
34 * and until it's being kicked off
35 */
36static inline void benchmark_utilisation_switch(tcb_t *heir, tcb_t *next)
37{
38    /* Add heir thread utilisation */
39    if (likely(benchmark_log_utilisation_enabled)) {
40
41        /* Check if an overflow occurred while we have been in the kernel */
42        if (likely(ksEnter > heir->benchmark.schedule_start_time)) {
43
44            heir->benchmark.utilisation += (ksEnter - heir->benchmark.schedule_start_time);
45
46        } else {
47#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
48            heir->benchmark.utilisation += (0xFFFFFFFFU - heir->benchmark.schedule_start_time) + ksEnter;
49            armv_handleOverflowIRQ();
50#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
51        }
52
53        /* Reset next thread utilisation */
54        next->benchmark.schedule_start_time = ksEnter;
55
56    }
57}
58
59static inline void benchmark_utilisation_kentry_stamp(void)
60{
61    ksEnter = timestamp();
62}
63
64/* Add the time between the last thread got scheduled and when to stop
65 * benchmarks
66 */
67static inline void benchmark_utilisation_finalise(void)
68{
69    /* Add the time between when NODE_STATE(ksCurThread), and benchmark finalise */
70    benchmark_utilisation_switch(NODE_STATE(ksCurThread), NODE_STATE(ksIdleThread));
71
72    benchmark_end_time = ksEnter;
73    benchmark_log_utilisation_enabled = false;
74}
75
76#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
77#endif /* BENCHMARK_UTILISATION_H */
78