@@ -15,13 +15,15 @@ struct MethodStats
1515 uint64_t call_count = 0 ;
1616 uint64_t total_allocation = 0 ;
1717 nanoseconds total_runtime = nanoseconds(0 );
18+ nanoseconds self_runtime = nanoseconds(0 );
1819};
1920
2021struct StackEntry
2122{
2223 void * method;
2324 time_point<high_resolution_clock> entry_time;
2425 uint64_t entry_alloc;
26+ nanoseconds child_runtime;
2527};
2628
2729// Per-thread profiler info.
@@ -55,7 +57,17 @@ struct ThreadProfilerInfo
5557
5658 void enter_method (void * method)
5759 {
58- stack.push_back (StackEntry{ method, high_resolution_clock::now (), mono_gc_get_used_size () });
60+ stack.push_back (StackEntry{ method, high_resolution_clock::now (), mono_gc_get_used_size (), nanoseconds (0 ) });
61+ }
62+
63+ MethodStats* get_method_stats (void * method)
64+ {
65+ table_t ::iterator it = table.find (method);
66+
67+ if (it == table.end ())
68+ it = table.insert ({ method, {} }).first ;
69+
70+ return &it->second ;
5971 }
6072
6173 void leave_method (void * method)
@@ -71,21 +83,26 @@ struct ThreadProfilerInfo
7183 return ;
7284
7385 std::lock_guard guard (stats_mut);
74- table_t ::iterator it = table.find (method);
75- if (it == table.end ())
76- {
77- it = table.insert ({ method, {} }).first ;
78- }
7986
80- it->second .total_runtime += now - top.entry_time ;
81- it->second .call_count ++;
87+ auto stats = get_method_stats (method);
88+
89+ auto time = now - top.entry_time ;
90+ stats->total_runtime += time;
91+ stats->self_runtime += time - top.child_runtime ;
92+ stats->call_count ++;
8293 uint64_t used_size = mono_gc_get_used_size ();
8394 // If a GC has happened since the method was entered, our allocation
8495 // estimate will be messed up. Here we use a simple heuristic:
8596 // ignore any negative allocation number.
8697 if (used_size > top.entry_alloc )
8798 {
88- it->second .total_allocation += used_size - top.entry_alloc ;
99+ stats->total_allocation += used_size - top.entry_alloc ;
100+ }
101+
102+ if (!stack.empty ())
103+ {
104+ StackEntry& parent = stack.back ();
105+ parent.child_runtime += time;
89106 }
90107 }
91108
@@ -103,6 +120,7 @@ struct ThreadProfilerInfo
103120 const char * name;
104121 uint64_t count;
105122 int64_t total_runtime;
123+ int64_t self_runtime;
106124 uint64_t total_allocation;
107125 };
108126
@@ -121,6 +139,7 @@ struct ThreadProfilerInfo
121139 .name = mono_method_full_name (entry.first ),
122140 .count = entry.second .call_count ,
123141 .total_runtime = entry.second .total_runtime .count (),
142+ .self_runtime = entry.second .self_runtime .count (),
124143 .total_allocation = entry.second .total_allocation });
125144 }
126145 }
@@ -136,13 +155,13 @@ struct ThreadProfilerInfo
136155 return a.total_runtime > b.total_runtime ;
137156 });
138157
139- fs << " \" Thread\" ,\" Call count\" ,\" Method name\" ,\" Total runtime (ns)\" ,\" Total allocation (bytes)\" " << std::endl;
158+ fs << " \" Thread\" ,\" Call count\" ,\" Method name\" ,\" Total runtime (ns)\" ,\" Self runtime (ns) \" , \" Total allocation (bytes)\" " << std::endl;
140159
141160 // Dump into csv
142161 for (auto & it : rows)
143162 {
144163 fs << it.thread_id << " ," << it.count << " ,\" " << it.name << " \" ," <<
145- it.total_runtime << " ," << it.total_allocation << std::endl;
164+ it.total_runtime << " ," << it.self_runtime << " , " << it. total_allocation << std::endl;
146165 }
147166
148167 fs.close ();
0 commit comments