]>
Commit | Line | Data |
---|---|---|
bd6521f0 A |
1 | // |
2 | // MachineCPU.hpp | |
3 | // KDBG | |
4 | // | |
5 | // Created by James McIlree on 10/26/12. | |
6 | // Copyright (c) 2014 Apple. All rights reserved. | |
7 | // | |
8 | ||
9 | // | |
10 | // Much simplified cpu/thread state model. | |
11 | // | |
12 | // 1) A thread is *always* on cpu. Always. The only excpetion is during | |
13 | // initialization, when the thread on cpu is unknown. | |
14 | // | |
15 | // 2) There are three states possible: Running, IDLE, INTR. | |
16 | // A thread may move from any state to any other state. | |
17 | // A thread may not take an INTR while in INTR. | |
18 | // It is illegal to context_switch in IDLE or INTR. | |
19 | // | |
20 | ||
21 | enum class kMachineCPUFlag : std::uint32_t { | |
22 | IsStateIdleInitialized = 0x00000001, // Set when the idle state at event[0] has been identified. | |
23 | IsStateINTRInitialized = 0x00000002, // Set when the INTR state at event[0] has been identified. | |
24 | IsStateThreadInitialized = 0x00000004, // Set when the on-cpu thread at event[0] has been identified (may be NULL, for threads not known at the time of event[0]) | |
25 | IsStateIdle = 0x00000008, // Set if the cpu is Idle | |
26 | IsStateINTR = 0x00000010, // Set if the cpu is servicing an interrupt | |
27 | IsStateDeactivatedForcedSwitchToIdleThread = 0x00000020, // OSX only; set when the cpu is deactivated and on wake forces a switch to its idle thread without a context switch tracepoint | |
28 | IsIOP = 0x10000000 // Set if the cpu is an IOP | |
29 | }; | |
30 | ||
31 | template <typename SIZE> | |
32 | class MachineCPU { | |
33 | protected: | |
34 | ||
35 | class ThreadOnCPU { | |
36 | protected: | |
37 | MachineThread<SIZE>* _thread; | |
38 | AbsTime _timestamp; | |
39 | public: | |
40 | ThreadOnCPU(MachineThread<SIZE>* thread, bool is_event_zero_init_thread, AbsTime timestamp) : | |
41 | _thread(thread), | |
42 | _timestamp(timestamp) | |
43 | { | |
44 | if (is_event_zero_init_thread) | |
45 | _thread = (MachineThread<SIZE>*)((uintptr_t)_thread | 1); | |
46 | } | |
47 | ||
48 | MachineThread<SIZE>* thread() { return (MachineThread<SIZE>*)((uintptr_t)_thread & ~0x1); } | |
49 | AbsTime timestamp() { return _timestamp; } | |
50 | bool is_event_zero_init_thread() { return (uintptr_t)_thread & 0x1; } | |
51 | }; | |
52 | ||
53 | int32_t _id; | |
54 | uint32_t _flags; | |
55 | std::string _name; // IOP's have names, AP's will be "AP" | |
56 | std::vector<CPUActivity<SIZE>> _timeline; | |
57 | ||
58 | // State used only during initialization | |
59 | MachineThread<SIZE>* _thread; | |
60 | AbsTime _begin_idle; | |
61 | AbsTime _begin_intr; | |
62 | std::vector<ThreadOnCPU> _cpu_runq; | |
63 | std::vector<AbsInterval> _cpu_intr; | |
64 | std::vector<AbsInterval> _cpu_idle; | |
65 | ||
66 | friend class Machine<SIZE>; | |
67 | ||
68 | bool is_running() const { return (_flags & ((uint32_t)kMachineCPUFlag::IsStateIdle | (uint32_t)kMachineCPUFlag::IsStateINTR)) == 0; } | |
69 | ||
70 | bool is_idle() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateIdle) > 0; } | |
71 | void set_idle(AbsTime timestamp); | |
72 | void clear_idle(AbsTime timestamp); | |
73 | ||
74 | bool is_deactivate_switch_to_idle_thread() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateDeactivatedForcedSwitchToIdleThread) > 0; } | |
75 | void set_deactivate_switch_to_idle_thread(); | |
76 | void clear_deactivate_switch_to_idle_thread(); | |
77 | ||
78 | bool is_idle_state_initialized() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateIdleInitialized) > 0; } | |
79 | void initialize_idle_state(bool value, AbsTime timestamp); | |
80 | ||
81 | bool is_intr() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateINTR) > 0; } | |
82 | void set_intr(AbsTime timestamp); | |
83 | void clear_intr(AbsTime timestamp); | |
84 | ||
85 | bool is_intr_state_initialized() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateINTRInitialized) > 0; } | |
86 | void initialize_intr_state(bool state, AbsTime timestamp); | |
87 | ||
88 | void context_switch(MachineThread<SIZE>* to_thread, MachineThread<SIZE>* from_thread, AbsTime timestamp); | |
89 | ||
90 | bool is_thread_state_initialized() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateThreadInitialized) > 0; } | |
91 | void initialize_thread_state(MachineThread<SIZE>* thread, AbsTime timestamp); | |
92 | ||
93 | MachineThread<SIZE>* thread() { return _thread; } | |
94 | ||
95 | // This is called after all events have been processed, to allow the | |
96 | // cpu timelines to be collapsed and post processed. | |
97 | void post_initialize(AbsInterval events_interval); | |
98 | ||
99 | public: | |
100 | MachineCPU(int32_t id, bool is_iop, std::string name) : | |
101 | _id(id), | |
102 | _flags(is_iop ? (uint32_t)kMachineCPUFlag::IsIOP : 0), | |
103 | _name(name), | |
104 | _thread(nullptr), | |
105 | _begin_idle(AbsTime(0)), | |
106 | _begin_intr(AbsTime(0)) | |
107 | { | |
108 | } | |
109 | ||
110 | int32_t id() const { return _id; } | |
111 | void set_id(int32_t id) { ASSERT(_id = -1, "Attempt to set id twice"); _id = id; } | |
112 | ||
113 | bool is_iop() const { return (_flags & (uint32_t)kMachineCPUFlag::IsIOP) > 0; } | |
114 | ||
115 | bool is_active() const { return !_timeline.empty(); } | |
116 | ||
117 | const char* name() const { return _name.c_str(); } | |
118 | ||
119 | const std::vector<CPUActivity<SIZE>>& timeline() const { return _timeline; } | |
120 | const CPUActivity<SIZE>* activity_for_timestamp(AbsTime timestamp) const; | |
121 | }; |