]>
Commit | Line | Data |
---|---|---|
bd6521f0 A |
1 | // |
2 | // Machine.hpp | |
3 | // KDBG | |
4 | // | |
5 | // Created by James McIlree on 10/25/12. | |
6 | // Copyright (c) 2014 Apple. All rights reserved. | |
7 | // | |
8 | ||
9 | enum class kMachineFlag : std::uint32_t { | |
10 | LostEvents = 0x00000001 | |
11 | }; | |
12 | ||
13 | template <typename SIZE> | |
14 | class Machine { | |
15 | protected: | |
16 | std::vector<MachineCPU<SIZE>> _cpus; | |
17 | ||
18 | std::unordered_multimap<pid_t, MachineProcess<SIZE>> _processes_by_pid; | |
19 | std::unordered_multimap<const char*, MachineProcess<SIZE>*, ConstCharHash, ConstCharEqualTo> _processes_by_name; | |
20 | std::vector<MachineProcess<SIZE>*> _processes_by_time; | |
21 | ||
22 | std::unordered_multimap<typename SIZE::ptr_t, MachineThread<SIZE> > _threads_by_tid; | |
23 | std::vector<MachineThread<SIZE>*> _threads_by_time; | |
24 | ||
25 | std::vector<MachineMachMsg<SIZE>> _mach_msgs; | |
26 | std::unordered_map<uintptr_t, uintptr_t> _mach_msgs_by_event_index; | |
27 | std::unordered_map<typename SIZE::ptr_t, NurseryMachMsg<SIZE>> _mach_msg_nursery; | |
28 | ||
29 | // | |
30 | // Vouchers are a bit special. We install pointers to vouchers in | |
31 | // MachineThreads and MachineMachMsg. This means that vouchers cannot | |
32 | // be moved once allocated. We could do two passes to exactly size | |
33 | // the data structures, this should be investigated in the future. | |
34 | // | |
35 | // On create or first observed use, a voucher goes into the nursery. | |
36 | // It stays there until a destroy event, or the end of Machine events. | |
37 | // Once flushed from the nursery, we have a map of addresses, which | |
38 | // points to a vector sorted by time. This allows addr @ time lookups | |
39 | // later. | |
40 | // | |
41 | std::unordered_map<typename SIZE::ptr_t, std::unique_ptr<MachineVoucher<SIZE>>> _voucher_nursery; | |
42 | std::unordered_map<typename SIZE::ptr_t, std::vector<std::unique_ptr<MachineVoucher<SIZE>>>> _vouchers_by_addr; | |
43 | ||
44 | std::unordered_map<typename SIZE::ptr_t, IOActivity<SIZE>> _io_by_uid; // uid == unique id, not user id | |
45 | std::vector<IOActivity<SIZE>> _all_io; | |
46 | std::vector<AbsInterval> _all_io_active_intervals; | |
47 | ||
48 | MachineProcess<SIZE>* _kernel_task; | |
49 | const KDEvent<SIZE>* _events; | |
50 | uintptr_t _event_count; | |
51 | uint32_t _flags; | |
52 | int32_t _unknown_process_pid; // We need unique negative pid's for previously unknown TID's | |
53 | ||
54 | // | |
55 | // Protected initialization code | |
56 | // | |
57 | void raw_initialize(const KDCPUMapEntry* cpumaps, | |
58 | uint32_t cpumap_count, | |
59 | const KDThreadMapEntry<SIZE>* threadmaps, | |
60 | uint32_t threadmap_count, | |
61 | const KDEvent<SIZE>* events, | |
62 | uintptr_t event_count); | |
63 | ||
64 | void post_initialize(); | |
65 | ||
66 | // | |
67 | // Mutable API, for use during construction | |
68 | // | |
69 | ||
70 | pid_t next_unknown_pid() { return --_unknown_process_pid; } | |
71 | ||
72 | MachineProcess<SIZE>* create_process(pid_t pid, const char* name, AbsTime create_timestamp, kMachineProcessFlag flags); | |
73 | MachineThread<SIZE>* create_thread(MachineProcess<SIZE>* process, typename SIZE::ptr_t tid, MachineVoucher<SIZE>* voucher, AbsTime create_timestamp, kMachineThreadFlag flags); | |
74 | MachineVoucher<SIZE>* create_voucher(typename SIZE::ptr_t address, AbsTime create_timestamp, kMachineVoucherFlag flags, uint32_t content_bytes_capacity); | |
75 | ||
76 | void destroy_voucher(typename SIZE::ptr_t address, AbsTime timestamp); | |
77 | ||
78 | void set_flags(kMachineFlag flag) { _flags |= (uint32_t)flag; } | |
79 | ||
80 | void set_process_name(MachineProcess<SIZE>* process, const char* name); | |
81 | ||
82 | MachineProcess<SIZE>* mutable_process(pid_t pid, AbsTime time) { return const_cast<MachineProcess<SIZE>*>(process(pid, time)); } | |
83 | MachineThread<SIZE>* mutable_thread(typename SIZE::ptr_t tid, AbsTime time) { return const_cast<MachineThread<SIZE>*>(thread(tid, time)); } | |
84 | ||
85 | MachineProcess<SIZE>* youngest_mutable_process(pid_t pid); | |
86 | MachineThread<SIZE>* youngest_mutable_thread(typename SIZE::ptr_t tid); | |
87 | ||
88 | MachineVoucher<SIZE>* process_event_voucher_lookup(typename SIZE::ptr_t address, uint32_t msgh_bits); | |
89 | MachineThread<SIZE>* process_event_tid_lookup(typename SIZE::ptr_t tid, AbsTime now); | |
90 | ||
91 | MachineVoucher<SIZE>* thread_forwarding_voucher_lookup(const MachineVoucher<SIZE>* original_thread_voucher); | |
92 | ||
93 | void begin_io(MachineThread<SIZE>* thread, AbsTime time, typename SIZE::ptr_t uid, typename SIZE::ptr_t size); | |
94 | void end_io(AbsTime time, typename SIZE::ptr_t uid); | |
95 | ||
96 | bool process_event(const KDEvent<SIZE>& event); | |
97 | void process_trequested_task(pid_t pid, typename SIZE::ptr_t trequested_0, typename SIZE::ptr_t trequested_1); | |
98 | void process_trequested_thread(typename SIZE::ptr_t tid, typename SIZE::ptr_t trequested_0, typename SIZE::ptr_t trequested_1); | |
99 | ||
100 | void initialize_cpu_idle_intr_states(); | |
101 | ||
102 | public: | |
103 | static MachineVoucher<SIZE> UnsetVoucher; | |
104 | static MachineVoucher<SIZE> NullVoucher; | |
105 | ||
106 | Machine(KDCPUMapEntry* cpumaps, uint32_t cpumap_count, KDThreadMapEntry<SIZE>* threadmaps, uint32_t threadmap_count, KDEvent<SIZE>* events, uintptr_t event_count); | |
107 | // Destructive, mutates parent! | |
108 | Machine(Machine<SIZE>& parent, KDEvent<SIZE>* events, uintptr_t event_count); | |
109 | Machine(const TraceFile& file); | |
110 | ||
111 | bool lost_events() const { return (_flags & (uint32_t)kMachineFlag::LostEvents) > 0; } | |
112 | ||
113 | const MachineProcess<SIZE>* process(pid_t pid, AbsTime time) const; | |
114 | const MachineThread<SIZE>* thread(typename SIZE::ptr_t tid, AbsTime time) const; | |
115 | const MachineVoucher<SIZE>* voucher(typename SIZE::ptr_t address, AbsTime time) const; | |
116 | const MachineMachMsg<SIZE>* mach_msg(uintptr_t event_index) const; | |
117 | ||
118 | const std::vector<const MachineProcess<SIZE>*>& processes() const; | |
119 | const std::vector<const MachineThread<SIZE>*>& threads() const; | |
120 | const std::vector<const MachineCPU<SIZE>>& cpus() const; | |
121 | ||
122 | const KDEvent<SIZE>* events() const { return _events; } | |
123 | uintptr_t event_count() const { return _event_count; } | |
124 | ||
125 | AbsInterval timespan() const; | |
126 | ||
127 | // Returns the number of cpus that have timeline data. | |
128 | // (IOW, typically the number of AP(s) on a machine, but might be less if you've disabled some so they generate no trace data) | |
129 | uint32_t active_cpus() const; | |
130 | ||
131 | // If summary_cpu == NULL , all cpus are matched. | |
132 | CPUSummary<SIZE> summary_for_timespan(AbsInterval timespan, const MachineCPU<SIZE>* summary_cpu) const; | |
133 | ||
134 | // This attempts to analyze various pieces of data and guess | |
135 | // if the Machine represents an ios device or not. | |
136 | bool is_ios() const; | |
137 | ||
138 | DEBUG_ONLY(void validate() const;) | |
139 | }; | |
140 | ||
141 | template <typename SIZE> MachineVoucher<SIZE> Machine<SIZE>::UnsetVoucher(SIZE::PTRMAX, AbsInterval(AbsTime(0),AbsTime(UINT64_MAX)), kMachineVoucherFlag::IsUnsetVoucher, 0); | |
142 | template <typename SIZE> MachineVoucher<SIZE> Machine<SIZE>::NullVoucher(0, AbsInterval(AbsTime(0),AbsTime(UINT64_MAX)), kMachineVoucherFlag::IsNullVoucher, 0); | |
143 |