1/*
2 * Copyright 2016, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <benchmark/benchmark_utilisation.h>
9
10#ifdef CONFIG_BENCHMARK_TRACK_UTILISATION
11
12timestamp_t ksEnter;
13
14void benchmark_track_utilisation_dump(void)
15{
16    uint64_t *buffer = ((uint64_t *) & (((seL4_IPCBuffer *)lookupIPCBuffer(true, NODE_STATE(ksCurThread)))->msg[0]));
17    tcb_t *tcb = NULL;
18    word_t tcb_cptr = getRegister(NODE_STATE(ksCurThread), capRegister);
19    lookupCap_ret_t lu_ret;
20    word_t cap_type;
21
22    lu_ret = lookupCap(NODE_STATE(ksCurThread), tcb_cptr);
23    /* ensure we got a TCB cap */
24    cap_type = cap_get_capType(lu_ret.cap);
25    if (cap_type != cap_thread_cap) {
26        userError("SysBenchmarkFinalizeLog: cap is not a TCB, halting");
27        return;
28    }
29
30    tcb = TCB_PTR(cap_thread_cap_get_capTCBPtr(lu_ret.cap));
31
32    /* Selected TCB counters */
33    buffer[BENCHMARK_TCB_UTILISATION] = tcb->benchmark.utilisation; /* Requested thread utilisation */
34    buffer[BENCHMARK_TCB_NUMBER_SCHEDULES] = tcb->benchmark.number_schedules; /* Number of times scheduled */
35    buffer[BENCHMARK_TCB_KERNEL_UTILISATION] = tcb->benchmark.kernel_utilisation; /* Utilisation spent in kernel */
36    buffer[BENCHMARK_TCB_NUMBER_KERNEL_ENTRIES] = tcb->benchmark.number_kernel_entries; /* Number of kernel entries */
37
38    /* Idle counters */
39    buffer[BENCHMARK_IDLE_LOCALCPU_UTILISATION] = NODE_STATE(
40                                                      ksIdleThread)->benchmark.utilisation; /* Idle thread utilisation of current CPU */
41#ifdef ENABLE_SMP_SUPPORT
42    buffer[BENCHMARK_IDLE_TCBCPU_UTILISATION] = NODE_STATE_ON_CORE(ksIdleThread,
43                                                                   tcb->tcbAffinity)->benchmark.utilisation; /* Idle thread utilisation of CPU the TCB is running on */
44#else
45    buffer[BENCHMARK_IDLE_TCBCPU_UTILISATION] = buffer[BENCHMARK_IDLE_LOCALCPU_UTILISATION];
46#endif
47
48    buffer[BENCHMARK_IDLE_NUMBER_SCHEDULES] = NODE_STATE(
49                                                  ksIdleThread)->benchmark.number_schedules; /* Number of times scheduled */
50    buffer[BENCHMARK_IDLE_KERNEL_UTILISATION] = NODE_STATE(
51                                                    ksIdleThread)->benchmark.kernel_utilisation; /* Utilisation spent in kernel */
52    buffer[BENCHMARK_IDLE_NUMBER_KERNEL_ENTRIES] = NODE_STATE(
53                                                       ksIdleThread)->benchmark.number_kernel_entries; /* Number of kernel entries */
54
55
56    /* Total counters */
57#ifdef CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT
58    buffer[BENCHMARK_TOTAL_UTILISATION] =
59        (NODE_STATE(ccnt_num_overflows) * 0xFFFFFFFFU) + NODE_STATE(benchmark_end_time) - NODE_STATE(benchmark_start_time);
60#else
61    buffer[BENCHMARK_TOTAL_UTILISATION] = NODE_STATE(benchmark_end_time) - NODE_STATE(
62                                              benchmark_start_time); /* Overall time */
63#endif /* CONFIG_ARM_ENABLE_PMU_OVERFLOW_INTERRUPT */
64    buffer[BENCHMARK_TOTAL_NUMBER_SCHEDULES] = NODE_STATE(benchmark_kernel_number_schedules);
65    buffer[BENCHMARK_TOTAL_KERNEL_UTILISATION] = NODE_STATE(benchmark_kernel_time);
66    buffer[BENCHMARK_TOTAL_NUMBER_KERNEL_ENTRIES] = NODE_STATE(benchmark_kernel_number_entries);
67
68}
69
70void benchmark_track_reset_utilisation(tcb_t *tcb)
71{
72    tcb->benchmark.utilisation = 0;
73    tcb->benchmark.number_schedules = 0;
74    tcb->benchmark.number_kernel_entries = 0;
75    tcb->benchmark.kernel_utilisation = 0;
76    tcb->benchmark.schedule_start_time = 0;
77}
78#endif /* CONFIG_BENCHMARK_TRACK_UTILISATION */
79