The Pedigree Project 0.1
TimeTracker.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/process/Process.h"
21#include "pedigree/kernel/process/Thread.h"
22#include "pedigree/kernel/process/TimeTracker.h"
23#include "pedigree/kernel/processor/Processor.h"
24#include "pedigree/kernel/processor/ProcessorInformation.h"
25
26void TimeTracker::initialise(bool entryInterruptsAlreadyDisabled) {
27 // Accounting baselines belong to the exact interrupted Thread. A Process
28 // can execute on multiple CPUs and cannot provide one shared baseline.
29 if (!m_pThread)
30 m_pThread = Processor::information().getCurrentThread();
31 if (!m_pThread) {
32 // We can get called early, so ensure we don't make any
33 // assumptions about what's present.
34 m_pProcess = nullptr;
35 return;
36 }
37
38 Process* threadProcess = m_pThread->getParent();
39 if (!threadProcess || (m_pProcess && m_pProcess != threadProcess)) {
40 m_pProcess = nullptr;
41 m_pThread = nullptr;
42 return;
43 }
44 m_pProcess = threadProcess;
45
46 // Track time already spent wherever we were previously.
47 if (entryInterruptsAlreadyDisabled) {
48 m_pThread->transitionTimeAtInterruptReturn(KernelTimeTransition::interrupted(m_bFromUserspace),
49 KernelTimeTransition::handler());
50 } else {
51 m_pThread->transitionTime(KernelTimeTransition::interrupted(m_bFromUserspace),
52 KernelTimeTransition::handler());
53 }
54}
55
56void TimeTracker::attributeSyscall(size_t rawNumber) {
57#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
58 if (!m_pProcess || !m_pThread || !m_bFromUserspace || m_bSyscallAttributed ||
59 !m_pProcess->benchmarkSyscallTimingEnabled()) {
60 return;
61 }
62
63 const size_t slot = Process::syscallTimingSlot(rawNumber);
64 m_pProcess->recordSyscallTimingCall(slot);
65 m_PreviousSyscallTimingSlot = m_pThread->installSyscallTimingSlot(slot);
66 m_bSyscallAttributed = true;
67#else
68 (void)rawNumber;
69#endif
70}
71
73 Thread* thread = m_pThread;
74 if (!m_pProcess || !thread)
75 return;
76
77 // Make completion idempotent before touching state so a no-return caller
78 // can explicitly finish without the destructor double-charging later.
79 m_pProcess = nullptr;
80 m_pThread = nullptr;
81
82 // Track time spent in the RAII section.
83 thread->transitionTime(KernelTimeTransition::handler(),
84 KernelTimeTransition::resumed(m_bFromUserspace));
85#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
86 restoreSyscallTiming(thread);
87#endif
88}
89
91 Thread* thread = m_pThread;
92 if (!m_pProcess || !thread)
93 return;
94
95 // Make completion idempotent before touching state so a no-return caller
96 // can explicitly finish without the destructor double-charging later.
97 m_pProcess = nullptr;
98 m_pThread = nullptr;
99
100 // Event return restores a saved kernel frame before the outer architecture
101 // tail makes the eventual Kernel -> User transition.
102 thread->transitionTime(KernelTimeTransition::handler(), KernelTimeTransition::handler());
103#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
104 restoreSyscallTiming(thread);
105#endif
106}
107
108#if PEDIGREE_BENCHMARK_SYSCALL_TIMING
109void TimeTracker::restoreSyscallTiming(Thread* thread) {
110 if (m_bSyscallAttributed) {
111 thread->restoreSyscallTimingSlot(m_PreviousSyscallTimingSlot);
112 m_bSyscallAttributed = false;
113 }
114}
115#endif
static ProcessorInformation & information()
ALWAYS_INLINE void transitionTimeAtInterruptReturn(CpuTimeMode from, CpuTimeMode to)
Definition Thread.h:358
Process * getParent() const
Definition Thread.h:325
void transitionTime(CpuTimeMode from, CpuTimeMode to, bool interruptsAlreadyDisabled=false)
Definition Thread.cc:386
void attributeSyscall(size_t rawNumber)
void finishInKernel()
void finish()