15
15
#import < mach-o/arch.h>
16
16
#import < sys/utsname.h>
17
17
#import < QuartzCore/QuartzCore.h>
18
+ #import " EMGStackTraceRecorder.h"
18
19
19
- static const int kMaxFramesPerStack = 512 ;
20
20
static NSThread *sStackRecordingThread = nil ;
21
- typedef struct {
22
- CFTimeInterval time;
23
- uint64_t frameCount;
24
- uintptr_t frames[kMaxFramesPerStack ];
25
- } Stack;
26
-
27
- typedef struct {
28
- std::vector<Stack> *stacks;
29
- char name[256 ];
30
- } Thread;
31
- static std::map<unsigned int , Thread *> *sThreadsMap ;
32
- static std::mutex sThreadsLock ;
33
-
34
- static BOOL sRecordAllThreads = false ;
35
21
36
22
static thread_t sMainMachThread = {0 };
37
- static thread_t sETTraceThread = {0 };
38
23
39
- extern " C" {
40
- void FIRCLSWriteThreadStack (thread_t thread, uintptr_t *frames, uint64_t framesCapacity, uint64_t *framesWritten);
24
+ // To avoid static initialization order fiasco, we access it from a function
25
+ EMGStackTraceRecorder &getRecorder () {
26
+ static EMGStackTraceRecorder recorder;
27
+ return recorder;
41
28
}
42
29
43
30
@implementation EMGTracer
@@ -55,19 +42,16 @@ + (void)stopRecording:(void (^)(NSDictionary *))stopped {
55
42
}
56
43
57
44
+ (NSDictionary *)getResults {
58
- sThreadsLock .lock ();
59
45
NSMutableDictionary <NSString *, NSDictionary <NSString *, id > *> *threads = [NSMutableDictionary dictionary ];
60
-
61
- std::map<unsigned int , Thread *>::iterator it;
62
- for (it = sThreadsMap ->begin (); it != sThreadsMap ->end (); it++) {
63
- Thread thread = *it->second ;
64
- NSString *threadId = [[NSNumber numberWithUnsignedInt: it->first] stringValue ];
46
+
47
+ auto threadSummaries = getRecorder ().collectThreadSummaries ();
48
+ for (const auto &thread : threadSummaries) {
49
+ NSString *threadId = [@(thread.threadId) stringValue ];
65
50
threads[threadId] = @{
66
- @" name" : [ NSString stringWithFormat: @" %s " , thread.name] ,
67
- @" stacks" : [self arrayFromStacks: * thread.stacks]
51
+ @" name" : @( thread.name . c_str ()) ,
52
+ @" stacks" : [self arrayFromStacks: thread.stacks]
68
53
};
69
54
}
70
- sThreadsLock .unlock ();
71
55
72
56
const NXArchInfo *archInfo = NXGetLocalArchInfo ();
73
57
NSString *cpuType = [NSString stringWithUTF8String: archInfo->description];
@@ -83,13 +67,12 @@ + (NSDictionary *)getResults {
83
67
};
84
68
}
85
69
86
- + (NSArray <NSDictionary <NSString *, id> *> *) arrayFromStacks : (std::vector<Stack> )stacks {
70
+ + (NSArray <NSDictionary <NSString *, id> *> *) arrayFromStacks : (const std::vector<StackSummary> & )stacks {
87
71
NSMutableArray <NSDictionary <NSString *, id > *> *threadStacks = [NSMutableArray array ];
88
72
for (const auto &cStack : stacks) {
89
73
NSMutableArray <NSNumber *> *stack = [NSMutableArray array ];
90
- // Add the addrs in reverse order so that they start with the lowest frame, e.g. `start`
91
- for (int j = (int )cStack.frameCount - 1 ; j >= 0 ; j--) {
92
- [stack addObject: @((NSUInteger )cStack.frames[j])];
74
+ for (const auto &address : cStack.stack ) {
75
+ [stack addObject: @((NSUInteger )address)];
93
76
}
94
77
NSDictionary *stackDictionary = @{
95
78
@" stack" : [stack copy ],
@@ -139,103 +122,6 @@ + (NSString *)deviceName {
139
122
return [NSString stringWithCString: systemInfo.machine encoding: NSUTF8StringEncoding];
140
123
}
141
124
142
- Thread* createThread (thread_t threadId)
143
- {
144
- Thread *thread = new Thread;
145
-
146
- if (threadId == sMainMachThread ) {
147
- strcpy (thread->name ," Main Thread" );
148
- } else {
149
- // Get thread Name
150
- char name[256 ];
151
- pthread_t pt = pthread_from_mach_thread_np (threadId);
152
- if (pt) {
153
- name[0 ] = ' \0 ' ;
154
- int rc = pthread_getname_np (pt, name, sizeof name);
155
- strcpy (thread->name , name);
156
- }
157
- }
158
-
159
- // Create stacks vector
160
- thread->stacks = new std::vector<Stack>;
161
- thread->stacks ->reserve (400 );
162
-
163
- return thread;
164
- }
165
-
166
- + (void )recordStackForAllThreads
167
- {
168
- thread_act_array_t threads;
169
- mach_msg_type_number_t thread_count;
170
- if (sRecordAllThreads ) {
171
- if (task_threads (mach_task_self (), &threads, &thread_count) != KERN_SUCCESS) {
172
- thread_count = 0 ;
173
- }
174
- } else {
175
- threads = &sMainMachThread ;
176
- thread_count = 1 ;
177
- }
178
-
179
- std::map<thread_t , Stack *> stackMap;
180
- for (mach_msg_type_number_t i = 0 ; i < thread_count; i++) {
181
- if (threads[i] == sETTraceThread ) {
182
- continue ;
183
- }
184
-
185
- Stack *stack = new Stack;
186
- stackMap.insert (std::pair<unsigned int , Stack *>(threads[i], stack));
187
- }
188
-
189
- // Suspend all threads but ETTrace's
190
- for (mach_msg_type_number_t i = 0 ; i < thread_count; i++) {
191
- if (threads[i] != sETTraceThread ) {
192
- thread_suspend (threads[i]);
193
- }
194
- }
195
-
196
- CFTimeInterval time = CACurrentMediaTime ();
197
- for (mach_msg_type_number_t i = 0 ; i < thread_count; i++) {
198
- if (threads[i] == sETTraceThread ) {
199
- continue ;
200
- }
201
-
202
- Stack *stack = stackMap.at (threads[i]);
203
- stack->time = time;
204
- FIRCLSWriteThreadStack (threads[i], stack->frames , kMaxFramesPerStack , &(stack->frameCount ));
205
- }
206
-
207
- for (mach_msg_type_number_t i = 0 ; i < thread_count; i++) {
208
- if (threads[i] != sETTraceThread )
209
- thread_resume (threads[i]);
210
- }
211
-
212
- std::vector<Stack> *threadStack;
213
- std::map<thread_t , Stack *>::iterator it;
214
- sThreadsLock .lock ();
215
- for (it = stackMap.begin (); it != stackMap.end (); it++) {
216
- thread_t t_id = it->first ;
217
- if (sThreadsMap ->find (t_id) == sThreadsMap ->end ()) {
218
- Thread *thread = createThread (t_id);
219
- // Add to hash map
220
- sThreadsMap ->insert (std::pair<thread_t , Thread *>(t_id, thread));
221
-
222
- threadStack = thread->stacks ;
223
- } else {
224
- threadStack = sThreadsMap ->at (t_id)->stacks ;
225
- }
226
- Stack *stack = it->second ;
227
- try {
228
- threadStack->emplace_back (*stack);
229
- } catch (const std::length_error& le) {
230
- fflush (stdout);
231
- fflush (stderr);
232
- throw le;
233
- }
234
- delete stack;
235
- }
236
- sThreadsLock .unlock ();
237
- }
238
-
239
125
+ (void )setup {
240
126
sMainMachThread = mach_thread_self ();
241
127
EMGBeginCollectingLibraries ();
@@ -256,18 +142,12 @@ + (void)setupStackRecording:(BOOL) recordAllThreads
256
142
// usleep is guaranteed to sleep more than that, in practice ~5ms. We could use a
257
143
// dispatch_timer, which at least tries to compensate for drift etc., but the
258
144
// timer's queue could theoretically end up run on the main thread
259
- sRecordAllThreads = recordAllThreads;
260
-
261
- sThreadsMap = new std::map<unsigned int , Thread *>;
262
-
263
145
sStackRecordingThread = [[NSThread alloc ] initWithBlock: ^{
264
- if (!sETTraceThread ) {
265
- sETTraceThread = mach_thread_self ();
266
- }
146
+ thread_t etTraceThread = mach_thread_self ();
267
147
268
148
NSThread *thread = [NSThread currentThread ];
269
149
while (!thread.cancelled ) {
270
- [ self recordStackForAllThreads ] ;
150
+ getRecorder (). recordStackForAllThreads (recordAllThreads, sMainMachThread , etTraceThread) ;
271
151
usleep (4500 );
272
152
}
273
153
}];
0 commit comments