@@ -102,37 +102,93 @@ MonodroidRuntime::thread_end ([[maybe_unused]] MonoProfiler *prof, [[maybe_unuse
102
102
}
103
103
104
104
inline void
105
- MonodroidRuntime::log_jit_event (MonoMethod *method, const char *event_name )
105
+ MonodroidRuntime::log_method_event (MonoMethod *method, MethodEvent event )
106
106
{
107
- jit_time.mark_end ();
108
-
109
- if (jit_log == nullptr )
107
+ if (!method_event_map) [[unlikely]] {
110
108
return ;
109
+ }
110
+
111
+ char * name = mono_method_full_name (method, TRUE );
112
+ hash_t name_hash = xxhash::hash (name, strlen (name));
111
113
112
- char * name = mono_method_full_name (method, 1 ) ;
114
+ lock_guard write_lock { *method_event_map_write_lock. get () } ;
113
115
114
- timing_diff diff (jit_time);
115
- fprintf (jit_log, " JIT method %6s: %s elapsed: %lis:%u::%u\n " , event_name, name, static_cast <long >(diff.sec ), diff.ms , diff.ns );
116
+ auto iter = method_event_map->find (name_hash);
117
+ if (iter == method_event_map->end ()) {
118
+ (*method_event_map)[name_hash] = MethodEventRecord {
119
+ .method_name_hash = name_hash,
120
+ .method_name = name,
121
+ };
122
+ }
116
123
117
- free (name);
124
+ MethodEventRecord &record = method_event_map->at (name_hash);
125
+ switch (event) {
126
+ case MethodEvent::JitBegin:
127
+ record.jit_elapsed .mark_start ();
128
+ record.state |= MethodEventRecord::JitStateStarted;
129
+ break ;
130
+
131
+ case MethodEvent::JitDone:
132
+ record.state |= MethodEventRecord::JitStateSuccess;
133
+ [[fallthrough]];
134
+
135
+ case MethodEvent::JitFailed:
136
+ record.jit_elapsed .mark_end ();
137
+ record.state |= MethodEventRecord::JitStateCompleted;
138
+ break ;
139
+
140
+ case MethodEvent::Enter:
141
+ record.invocation_count ++;
142
+ break ;
143
+ }
118
144
}
119
145
120
146
void
121
147
MonodroidRuntime::jit_begin ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method)
122
148
{
123
- monodroidRuntime.log_jit_event (method, " begin " );
149
+ monodroidRuntime.log_method_event (method, MethodEvent::JitBegin );
124
150
}
125
151
126
152
void
127
153
MonodroidRuntime::jit_failed ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method)
128
154
{
129
- monodroidRuntime.log_jit_event (method, " failed " );
155
+ monodroidRuntime.log_method_event (method, MethodEvent::JitFailed );
130
156
}
131
157
132
158
void
133
159
MonodroidRuntime::jit_done ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoJitInfo* jinfo)
134
160
{
135
- monodroidRuntime.log_jit_event (method, " done" );
161
+ monodroidRuntime.log_method_event (method, MethodEvent::JitDone);
162
+ }
163
+
164
+ // This is called only for `mono_runtime_invoke`
165
+ void
166
+ MonodroidRuntime::prof_method_begin_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept
167
+ {
168
+ monodroidRuntime.log_method_event (method, MethodEvent::Enter);
169
+ }
170
+
171
+ void
172
+ MonodroidRuntime::prof_method_end_invoke ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method) noexcept
173
+ {}
174
+
175
+ // This is called only when the interpreter is used
176
+ void
177
+ MonodroidRuntime::prof_method_enter ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept
178
+ {
179
+ log_debug (LOG_ASSEMBLY, " prof_method_enter" );
180
+ monodroidRuntime.log_method_event (method, MethodEvent::Enter);
181
+ }
182
+
183
+ void
184
+ MonodroidRuntime::prof_method_leave ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoProfilerCallContext *context) noexcept
185
+ {}
186
+
187
+ MonoProfilerCallInstrumentationFlags
188
+ MonodroidRuntime::prof_method_filter ([[maybe_unused]] MonoProfiler *prof, [[maybe_unused]] MonoMethod *method) noexcept
189
+ {
190
+ return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER |
191
+ MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE;
136
192
}
137
193
138
194
#ifndef RELEASE
@@ -631,9 +687,11 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse
631
687
632
688
bool log_methods = FastTiming::enabled () && !FastTiming::is_bare_mode ();
633
689
if (log_methods) [[unlikely]] {
690
+ log_debug (LOG_ASSEMBLY, " Enabling method logging" );
634
691
std::unique_ptr<char > jit_log_path {Util::path_combine (AndroidSystem::override_dirs [0 ], " methods.txt" )};
692
+ log_debug (LOG_ASSEMBLY, " JIT log path: %s" , jit_log_path.get ());
635
693
Util::create_directory (AndroidSystem::override_dirs [0 ], 0755 );
636
- jit_log = Util::monodroid_fopen (jit_log_path.get (), " a " );
694
+ jit_log = Util::monodroid_fopen (jit_log_path.get (), " w " );
637
695
Util::set_world_accessable (jit_log_path.get ());
638
696
}
639
697
@@ -642,10 +700,31 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse
642
700
mono_profiler_set_thread_stopped_callback (profiler_handle, thread_end);
643
701
644
702
if (log_methods) [[unlikely]]{
645
- jit_time.mark_start ();
703
+ method_event_map_write_lock = std::make_unique<mutex> ();
704
+ method_event_map = std::make_unique<method_event_map_t > ();
705
+
646
706
mono_profiler_set_jit_begin_callback (profiler_handle, jit_begin);
647
707
mono_profiler_set_jit_done_callback (profiler_handle, jit_done);
648
708
mono_profiler_set_jit_failed_callback (profiler_handle, jit_failed);
709
+ mono_profiler_set_method_begin_invoke_callback (profiler_handle, prof_method_begin_invoke);
710
+ mono_profiler_set_method_end_invoke_callback (profiler_handle, prof_method_end_invoke);
711
+
712
+ // The method enter/leave callbacks are supported only when the interpreter is used.
713
+ switch (AndroidSystem::get_mono_aot_mode ()) {
714
+ case MonoAotMode::MONO_AOT_MODE_INTERP:
715
+ case MonoAotMode::MONO_AOT_MODE_INTERP_ONLY:
716
+ case MonoAotMode::MONO_AOT_MODE_INTERP_LLVMONLY:
717
+ case MonoAotMode::MONO_AOT_MODE_LLVMONLY_INTERP:
718
+ log_debug (LOG_ASSEMBLY, " Enabling method enter/leave profiler callbacks" );
719
+ mono_profiler_set_call_instrumentation_filter_callback (profiler_handle, prof_method_filter);
720
+ mono_profiler_set_method_enter_callback (profiler_handle, prof_method_enter);
721
+ mono_profiler_set_method_leave_callback (profiler_handle, prof_method_leave);
722
+ break ;
723
+
724
+ default :
725
+ // Other AOT modes are ignored
726
+ break ;
727
+ }
649
728
}
650
729
651
730
parse_gdb_options ();
@@ -1624,11 +1703,11 @@ MonodroidRuntime::Java_mono_android_Runtime_register (JNIEnv *env, jstring manag
1624
1703
JNIEXPORT void
1625
1704
JNICALL Java_mono_android_Runtime_dumpTimingData ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass klass)
1626
1705
{
1627
- if (internal_timing = = nullptr ) {
1628
- return ;
1706
+ if (internal_timing ! = nullptr ) {
1707
+ internal_timing-> dump () ;
1629
1708
}
1630
1709
1631
- internal_timing-> dump ();
1710
+ monodroidRuntime. dump_method_events ();
1632
1711
}
1633
1712
1634
1713
JNIEXPORT void
0 commit comments