--- /dev/null
+//
+// MachineCPU.hpp
+// KDBG
+//
+// Created by James McIlree on 10/26/12.
+// Copyright (c) 2014 Apple. All rights reserved.
+//
+
+//
+// Much simplified cpu/thread state model.
+//
+// 1) A thread is *always* on cpu. Always. The only excpetion is during
+// initialization, when the thread on cpu is unknown.
+//
+// 2) There are three states possible: Running, IDLE, INTR.
+// A thread may move from any state to any other state.
+// A thread may not take an INTR while in INTR.
+// It is illegal to context_switch in IDLE or INTR.
+//
+
+enum class kMachineCPUFlag : std::uint32_t {
+ IsStateIdleInitialized = 0x00000001, // Set when the idle state at event[0] has been identified.
+ IsStateINTRInitialized = 0x00000002, // Set when the INTR state at event[0] has been identified.
+ 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])
+ IsStateIdle = 0x00000008, // Set if the cpu is Idle
+ IsStateINTR = 0x00000010, // Set if the cpu is servicing an interrupt
+ 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
+ IsIOP = 0x10000000 // Set if the cpu is an IOP
+};
+
+template <typename SIZE>
+class MachineCPU {
+ protected:
+
+ class ThreadOnCPU {
+ protected:
+ MachineThread<SIZE>* _thread;
+ AbsTime _timestamp;
+ public:
+ ThreadOnCPU(MachineThread<SIZE>* thread, bool is_event_zero_init_thread, AbsTime timestamp) :
+ _thread(thread),
+ _timestamp(timestamp)
+ {
+ if (is_event_zero_init_thread)
+ _thread = (MachineThread<SIZE>*)((uintptr_t)_thread | 1);
+ }
+
+ MachineThread<SIZE>* thread() { return (MachineThread<SIZE>*)((uintptr_t)_thread & ~0x1); }
+ AbsTime timestamp() { return _timestamp; }
+ bool is_event_zero_init_thread() { return (uintptr_t)_thread & 0x1; }
+ };
+
+ int32_t _id;
+ uint32_t _flags;
+ std::string _name; // IOP's have names, AP's will be "AP"
+ std::vector<CPUActivity<SIZE>> _timeline;
+
+ // State used only during initialization
+ MachineThread<SIZE>* _thread;
+ AbsTime _begin_idle;
+ AbsTime _begin_intr;
+ std::vector<ThreadOnCPU> _cpu_runq;
+ std::vector<AbsInterval> _cpu_intr;
+ std::vector<AbsInterval> _cpu_idle;
+
+ friend class Machine<SIZE>;
+
+ bool is_running() const { return (_flags & ((uint32_t)kMachineCPUFlag::IsStateIdle | (uint32_t)kMachineCPUFlag::IsStateINTR)) == 0; }
+
+ bool is_idle() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateIdle) > 0; }
+ void set_idle(AbsTime timestamp);
+ void clear_idle(AbsTime timestamp);
+
+ bool is_deactivate_switch_to_idle_thread() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateDeactivatedForcedSwitchToIdleThread) > 0; }
+ void set_deactivate_switch_to_idle_thread();
+ void clear_deactivate_switch_to_idle_thread();
+
+ bool is_idle_state_initialized() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateIdleInitialized) > 0; }
+ void initialize_idle_state(bool value, AbsTime timestamp);
+
+ bool is_intr() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateINTR) > 0; }
+ void set_intr(AbsTime timestamp);
+ void clear_intr(AbsTime timestamp);
+
+ bool is_intr_state_initialized() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateINTRInitialized) > 0; }
+ void initialize_intr_state(bool state, AbsTime timestamp);
+
+ void context_switch(MachineThread<SIZE>* to_thread, MachineThread<SIZE>* from_thread, AbsTime timestamp);
+
+ bool is_thread_state_initialized() const { return (_flags & (uint32_t)kMachineCPUFlag::IsStateThreadInitialized) > 0; }
+ void initialize_thread_state(MachineThread<SIZE>* thread, AbsTime timestamp);
+
+ MachineThread<SIZE>* thread() { return _thread; }
+
+ // This is called after all events have been processed, to allow the
+ // cpu timelines to be collapsed and post processed.
+ void post_initialize(AbsInterval events_interval);
+
+ public:
+ MachineCPU(int32_t id, bool is_iop, std::string name) :
+ _id(id),
+ _flags(is_iop ? (uint32_t)kMachineCPUFlag::IsIOP : 0),
+ _name(name),
+ _thread(nullptr),
+ _begin_idle(AbsTime(0)),
+ _begin_intr(AbsTime(0))
+ {
+ }
+
+ int32_t id() const { return _id; }
+ void set_id(int32_t id) { ASSERT(_id = -1, "Attempt to set id twice"); _id = id; }
+
+ bool is_iop() const { return (_flags & (uint32_t)kMachineCPUFlag::IsIOP) > 0; }
+
+ bool is_active() const { return !_timeline.empty(); }
+
+ const char* name() const { return _name.c_str(); }
+
+ const std::vector<CPUActivity<SIZE>>& timeline() const { return _timeline; }
+ const CPUActivity<SIZE>* activity_for_timestamp(AbsTime timestamp) const;
+};