-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathexecution.h
More file actions
572 lines (484 loc) · 19.9 KB
/
execution.h
File metadata and controls
572 lines (484 loc) · 19.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
#ifndef EXECUTION_H
#define EXECUTION_H
// ----------------------------------------------------------------------
// Representation of runtime execution
// stacks, threads, time
#include <iostream>
#include <map>
#include <deque>
#include <utility>
#include "classinfo.h"
#include "heap.hpp"
using namespace std;
// Type definitions
typedef unsigned int MethodId_t;
// TODO typedef unsigned int threadId_t;
class CCNode;
typedef map<unsigned int, CCNode *> CCMap;
typedef map<Method *, CCNode *> FullCCMap;
typedef map<MethodId_t, Thread *> ThreadMap;
// TODO: This is the old context pair code:
typedef map<ContextPair, unsigned int> ContextPairCountMap;
typedef map<string, unsigned int> ContextCountMap;
typedef map<ContextPair, CPairType> ContextTypeMap_t;
// TODO: typedef map<Object *, ContextPair> ObjectContextMap;
typedef map<Object *, string> ObjectContextMap;
typedef deque<Method *> MethodDeque;
typedef deque<Thread *> ThreadDeque;
typedef set<Object *> LocalVarSet;
typedef deque<LocalVarSet *> LocalVarDeque;
// TODO typedef deque< pair<LastEvent, Object*> > LastEventDeque_t;
// TODO typedef map<threadId_t, LastEventDeque_t> LastMap_t;
// ----------------------------------------------------------------------
// Calling context tree
// This is used to indicate the stack bookkeeping mode of class ExecState
enum class ExecMode {
Full = 1,
StackOnly = 2
};
std::ostream& operator << ( std::ostream &out, const ExecMode &value );
// Self-explanatory
enum class EventKind {
Allocation = 1,
Death = 2,
};
class CCNode
{
private:
Method* m_method;
CCNode* m_parent;
// -- Map from method IDs to callee contexts
CCMap m_callees;
// Flag indicating whether simple method trace has been saved
bool m_done;
// Caching the simple_stacktrace
deque<Method *> m_simptrace;
unsigned int m_node_id;
static unsigned int m_ccnode_nextid;
unsigned int get_next_node_id() {
unsigned int result = this->m_ccnode_nextid;
this->m_ccnode_nextid++;
return result;
}
// File to output the callstack
ofstream &m_output;
public:
CCNode( ofstream &output )
: m_method(0)
, m_parent(0)
, m_done(false)
, m_node_id(this->get_next_node_id())
, m_output(output) {
}
CCNode( CCNode* parent, Method* m, ofstream &output )
: m_method(m)
, m_parent(parent)
, m_node_id(this->get_next_node_id())
, m_output(output) {
}
// -- Get method
Method* getMethod() const { return this->m_method; }
// -- Get method
MethodId_t getMethodId() const {
Method *m = this->getMethod();
return (m ? m->getId() : 0);
}
// -- Get parent context (if there is one)
CCNode* getParent() const { return m_parent; }
// -- Call a method, making a new child context if necessary
CCNode* Call(Method* m);
// -- Return from a method, returning the parent context
CCNode* Return(Method* m);
// -- Produce a string representation of the context
string info();
// -- Generate a stack trace
string stacktrace();
// -- Generate a stack trace and return the DequeId_t of function ids
DequeId_t stacktrace_using_id();
// Method name equality
bool simple_cc_equal( CCNode &other );
// TODO
deque<Method *> simple_stacktrace();
CCMap::iterator begin_callees() { return this->m_callees.begin(); }
CCMap::iterator end_callees() { return this->m_callees.end(); }
// Has simple trace been saved for this CCNode?
bool isDone() { return this->m_done; }
bool setDone() { this->m_done = true; return true; }
// Node Ids
NodeId_t get_node_id() const { return this->m_node_id; }
};
// ----------------------------------------------------------------------
// Thread representation
// Two options for representing the stack
// (1) Build a full calling context tree
// (2) Keep a stack of methods
// (I realize I could probably do this with fancy-dancy OO programming,
// but sometimes that just seems like overkill
class ExecState; // forward declaration to include into Thread
class Thread
{
private:
// -- Thread ID
unsigned int m_id;
// -- Kind of stack
ExecMode m_kind;
// -- CC tree representation
CCNode *m_curcc;
// -- Stack of methods
MethodDeque m_methods;
// -- Local stack variables that have root events in this scope
LocalVarDeque m_locals;
// -- Local stack variables that have root events and died this scope
LocalVarDeque m_deadlocals;
// -- Current context pair
ContextPair m_context;
// -- Type of ContextPair m_context
CPairType m_cptype;
// -- Map of simple Allocation site (used to be context pair)
// -> count of occurrences
ContextCountMap &m_allocCountmap;
// -- Map of simple Death death site (used to be context pair)
// -> count of occurrences
ContextPairCountMap &m_deathPairCountMap;
// Unused when we removed context pair functionality
// TODO: UNUSED // Context type map - see documentation below in ExecState
// TODO: UNUSED ContextTypeMap_t &m_contextTypeMap;
// -- Map to ExecState
ExecState &m_exec;
// File to output the callstack
ofstream &m_output;
// File to output the nodeId to method name
ofstream &m_nodefile;
public:
Thread( unsigned int id,
ExecMode kind,
ContextCountMap &allocCountmap,
ContextPairCountMap &deathCountMap,
ContextTypeMap_t &contextTypeMap,
ExecState &execstate,
ofstream &output,
ofstream &nodefile )
: m_id(id)
, m_kind(kind)
, m_rootcc(output)
, m_curcc(&m_rootcc)
, m_context( NULL, NULL )
, m_cptype(CPairType::CP_None)
, m_allocCountmap(allocCountmap)
, m_deathPairCountMap(deathCountMap)
// TODO: , m_contextTypeMap(contextTypeMap)
, m_exec(execstate)
, m_output(output)
, m_nodefile(nodefile) {
m_locals.push_back(new LocalVarSet());
m_deadlocals.push_back(new LocalVarSet());
}
unsigned int getId() const { return m_id; }
// -- Call method m
void Call(Method *m);
// -- Return from method m
void Return(Method* m);
// -- Get current CC
CCNode *TopCC();
// -- Get current method
Method *TopMethod();
// -- Get method N from the top (0 based).
// This means the TopMethod() is equivalent to TopMethod(0)
Method *TopMethod( unsigned int num );
// -- Get top N methods
MethodDeque top_N_methods(unsigned int N);
// -- Get top Java-library methods + first non-Java library method
MethodDeque top_javalib_methods();
// -- Get top non Java-library methods
MethodDeque top_nonjavalib_methods();
// -- Get the full stack
MethodDeque full_method_stack();
// -- Get current dead locals
LocalVarSet * TopLocalVarSet();
// -- Get a stack trace
string stacktrace();
// -- Get a stack trace with method ids
DequeId_t stacktrace_using_id();
// -- Root event
void objectRoot(Object *object);
// -- Check dead object
bool isLocalVariable(Object *object);
// Root CCNode
CCNode m_rootcc;
// Get root node CC
CCNode &getRootCCNode() { return m_rootcc; }
// Get simple context pair
ContextPair getContextPair() const { return m_context; }
// Set simple context pair
ContextPair setContextPair( ContextPair cpair, CPairType cptype ) {
this->m_context = cpair;
this->m_cptype = cptype;
return cpair;
}
// Get simple context pair type
CPairType getContextPairType() const { return this->m_cptype; }
// Set simple context pair type
void setContextPairType( CPairType cptype ) { this->m_cptype = cptype; }
// Debug
void debug_cpair( ContextPair cpair,
string ptype ) {
Method *m1 = std::get<0>(cpair);
Method *m2 = std::get<1>(cpair);
string method1 = (m1 ? m1->getName() : "NONAME1");
string method2 = (m2 ? m2->getName() : "NONAME2");
cout << "CPAIR-dbg< " << ptype << " >"
<< "[ " << method1 << ", " << method2 << "]" << endl;
}
};
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// Execution state
// ----------------------------------------------------------------------
class ExecState
{
private:
// -- Stack kind (CC or methods)
ExecMode m_kind;
// -- Set of threads
ThreadMap m_threads;
// -- Method Time
unsigned int m_meth_time;
// -- Method Exit Time
unsigned int m_methexit_time;
// -- Update Time
unsigned int m_uptime;
// -- Alloc Time
unsigned int m_alloc_time;
// -- Map of Object pointer -> simple allocation context pair
ObjectContextMap m_objAlloc2cmap;
// -- Map of Object pointer -> simple death context pair
ObjectContextMap m_objDeath2cmap;
// Last method called
ThreadDeque m_thread_stack;
// When main function was called
VTime_t main_func_uptime; // in logical update+method time
VTime_t main_func_alloctime; // in logical allocation time (bytes)
public:
ExecState( ExecMode kind )
: m_kind(kind)
, m_threads()
, m_meth_time(0)
, m_uptime(0)
, m_methexit_time(0)
, m_alloc_time(0)
, m_allocCountmap()
, m_deathPairCountMap()
, m_execPairCountMap()
, m_objAlloc2cmap()
, m_objDeath2cmap()
, m_thread_stack()
, m_output(NULL)
, m_nodefile(NULL) {
}
// -- Get the current method time
unsigned int MethNow() const {
return this->m_meth_time;
}
// -- Get the current method exit time
unsigned int MethExitNow() const {
return this->m_methexit_time;
}
// -- Get the current update time
unsigned int NowUp() const {
return this->m_uptime + this->m_methexit_time + this->m_meth_time;
}
// -- Get the current allocation time
unsigned int NowAlloc() const { return m_alloc_time; }
// -- Set the current allocation time
void SetAllocTime( unsigned int newtime ) { this->m_alloc_time = newtime; }
// -- Set the current update time
inline unsigned int SetUpdateTime( unsigned int newutime ) {
return this->m_uptime = newutime;
}
// -- Increment the current update time
inline unsigned int IncUpdateTime() {
return this->m_uptime++;
}
// -- Increment the current method time
inline unsigned int IncMethodTime() {
return this->m_meth_time++;
}
// -- Increment the current method EXIT time
inline unsigned int IncMethodExitTime() {
return this->m_methexit_time++;
}
// -- Look up or create a thread
Thread* getThread(unsigned int threadid);
// -- Call method m in thread t
void Call(Method* m, unsigned int threadid);
// -- Return from method m in thread t
void Return(Method* m, unsigned int threadid);
// -- Get the top method in thread t
Method *TopMethod(unsigned int threadid);
// -- Get n-th from the top method in thread t
Method *TopMethod( unsigned int threadid,
unsigned int num );
// -- Get the top calling context in thread t
CCNode * TopCC(unsigned int threadid);
// Get begin iterator of thread map
ThreadMap::iterator begin_threadmap() { return this->m_threads.begin(); }
ThreadMap::iterator end_threadmap() { return this->m_threads.end(); }
// Update the Object pointer to simple Allocation context pair map
void UpdateObj2AllocContext( Object *obj,
string alloc_site )
{
this->m_objAlloc2cmap[obj] = alloc_site;
// TODO: Old code using context pair
// TODO ContextPair cpair,
// TODO CPairType cptype ) {
// TODO: UpdateObj2Context( obj,
// TODO: cpair,
// TODO: cptype,
// TODO: EventKind::Allocation );
}
// Update the Object pointer to simple Death context pair map
void UpdateObj2DeathContext( Object *obj,
MethodDeque &methdeque );
// OLD VERSION: Update the Object pointer to simple Death context pair map
void UpdateObj2DeathContext_version_1( Object *obj,
MethodDeque &methdeque );
void UpdateContextTypeMap( ContextPair cpair,
CPairType cptype ) {
ContextTypeMap_t cptype_map = this->m_contextTypeMap;
auto it = cptype_map.find(cpair);
if ( (it != cptype_map.end()) &&
(cptype_map[cpair] != cptype) ) {
cptype_map[cpair] = CPairType::CP_Both;
} else {
cptype_map[cpair] = cptype;
}
// TODO DEBUG ONLY TODO
// cout << "XXX: " << this->_get_cptype_name( cptype_map[cpair] ) << endl;
}
void DebugContextTypeMap() {
// TODO TODO TODO TODO
}
// Get the context pair type for a given context pair
CPairType get_cptype( ContextPair cpair ) {
ContextTypeMap_t cptype_map = this->m_contextTypeMap;
auto it = cptype_map.find(cpair);
if (it != cptype_map.end()) {
return cptype_map[cpair];
} else {
return CPairType::CP_None;
}
}
static char _get_cptype_name( CPairType cptype ) {
switch (cptype) {
case CPairType::CP_Call:
return 'C';
case CPairType::CP_Return:
return 'R';
case CPairType::CP_Both:
return 'B';
default:
// None
return 'N';
}
}
char get_cptype_name( ContextPair cpair ) {
CPairType cptype = this->get_cptype(cpair);
return this->_get_cptype_name(cptype);
}
// TODO: // Update the Object pointer to simple context pair map
// TODO: void UpdateObj2Context( Object *obj,
// TODO: ContextPair cpair,
// TODO: CPairType cptype,
// TODO: EventKind ekind ) {
// TODO: assert(obj);
// TODO: // DEBUG cpair here
// TODO: // TODO debug_cpair( obj->getDeathContextPair(), obj );
// TODO: // END DEBUG
// TODO: if (ekind == EventKind::Allocation) {
// TODO: this->m_objAlloc2cmap[obj] = cpair;
// TODO: obj->setAllocContextPair( cpair, cptype );
// TODO: } else {
// TODO: assert( ekind == EventKind::Death );
// TODO: this->m_objDeath2cmap[obj] = cpair;
// TODO: obj->setDeathContextPair( cpair, cptype );
// TODO: }
// TODO: UpdateContextTypeMap( cpair, cptype );
// TODO: ContextCountMap &curcmap = ((ekind == EventKind::Allocation) ? this->m_allocCountmap
// TODO: : this->m_deathPairCountMap);
// TODO: auto it = curcmap.find( cpair );
// TODO: if (it != curcmap.end()) {
// TODO: curcmap[cpair] += 1;
// TODO: } else {
// TODO: curcmap[cpair] = 1;
// TODO: }
// TODO: }
// -- The assumption is that a context pair will be only a single
// type. See the definition for CPairType in heap.hpp. Possible values are
// Call, Return, Both. (Don't use None)
ContextTypeMap_t m_contextTypeMap;
// -- Map of simple Allocation context -> count of occurrences
// TODO: Think about hiding this in an abstraction TODO
ContextCountMap m_allocCountmap;
ContextCountMap::iterator begin_allocCountmap() { return this->m_allocCountmap.begin(); }
ContextCountMap::iterator end_allocCountmap() { return this->m_allocCountmap.end(); }
// -- Map of simple Death context -> count of occurrences
// TODO: Think about hiding this in an abstraction TODO
ContextPairCountMap m_deathPairCountMap;
ContextPairCountMap::iterator begin_deathCountMap() {
return this->m_deathPairCountMap.begin();
}
ContextPairCountMap::iterator end_deathCountMap() {
return this->m_deathPairCountMap.end();
}
// -- Map of execution context Pair -> count of occurrences
// TODO: Think about hiding this in an abstraction TODO
ContextPairCountMap m_execPairCountMap;
ContextPairCountMap::iterator begin_execPairCountMap() {
return this->m_execPairCountMap.begin();
}
ContextPairCountMap::iterator end_execPairCountMap() {
return this->m_execPairCountMap.end();
}
void IncCallContext( MethodDeque &top_2_methods ) {
ContextPair cpair = std::make_pair( top_2_methods[0], top_2_methods[1] );
this->m_execPairCountMap[cpair]++;
}
// Get last global thread called
Thread *get_last_thread() const {
return ( (this->m_thread_stack.size() > 0)
? this->m_thread_stack.back()
: NULL );
}
ExecMode get_kind() const { return m_kind; }
// File to output the callstack
ofstream *m_output;
void set_output( ofstream *out ) { this->m_output = out; }
// File to output the node id to method name map
ofstream *m_nodefile;
void set_nodefile( ofstream *nfile ) { this->m_nodefile = nfile; }
// Related to getting the time when the main function was called
inline VTime_t get_main_func_uptime() {
return this->main_func_uptime; // in logical update+method time
}
inline VTime_t get_main_func_alloctime() {
return this->main_func_alloctime; // in logical allocation time (bytes)
}
inline void set_main_func_uptime(VTime_t new_uptime) {
this->main_func_uptime = new_uptime; // in logical update+method time
}
VTime_t set_main_func_alloctime(VTime_t new_alloctime) {
this->main_func_alloctime = new_alloctime; // in logical allocation time (bytes)
return new_alloctime;
}
private:
void debug_cpair( ContextPair cpair,
Object *object ) {
Method *m1 = std::get<0>(cpair);
Method *m2 = std::get<1>(cpair);
string method1 = (m1 ? m1->getName() : "NONAME1");
string method2 = (m2 ? m2->getName() : "NONAME2");
cout << "CPAIR-update< " << object->getType() << " >"
<< "[ " << method1 << ", " << method2 << "]" << endl;
}
};
#endif