@@ -102,37 +102,93 @@ MonodroidRuntime::thread_end ([[maybe_unused]] MonoProfiler *prof, [[maybe_unuse
102102}
103103
104104inline void
105- MonodroidRuntime::log_jit_event (MonoMethod *method, const char *event_name )
105+ MonodroidRuntime::log_method_event (MonoMethod *method, MethodEvent event )
106106{
107- jit_time.mark_end ();
108-
109- if (jit_log == nullptr )
107+ if (!method_event_map) [[unlikely]] {
110108 return ;
109+ }
110+
111+ char * name = mono_method_full_name (method, TRUE );
112+ hash_t name_hash = xxhash::hash (name, strlen (name));
111113
112- char * name = mono_method_full_name (method, 1 ) ;
114+ lock_guard write_lock { *method_event_map_write_lock. get () } ;
113115
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+ }
116123
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+ }
118144}
119145
120146void
121147MonodroidRuntime::jit_begin ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method)
122148{
123- monodroidRuntime.log_jit_event (method, " begin " );
149+ monodroidRuntime.log_method_event (method, MethodEvent::JitBegin );
124150}
125151
126152void
127153MonodroidRuntime::jit_failed ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method)
128154{
129- monodroidRuntime.log_jit_event (method, " failed " );
155+ monodroidRuntime.log_method_event (method, MethodEvent::JitFailed );
130156}
131157
132158void
133159MonodroidRuntime::jit_done ([[maybe_unused]] MonoProfiler *prof, MonoMethod *method, [[maybe_unused]] MonoJitInfo* jinfo)
134160{
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;
136192}
137193
138194#ifndef RELEASE
@@ -631,9 +687,11 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse
631687
632688 bool log_methods = FastTiming::enabled () && !FastTiming::is_bare_mode ();
633689 if (log_methods) [[unlikely]] {
690+ log_debug (LOG_ASSEMBLY, " Enabling method logging" );
634691 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 ());
635693 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 " );
637695 Util::set_world_accessable (jit_log_path.get ());
638696 }
639697
@@ -642,10 +700,31 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse
642700 mono_profiler_set_thread_stopped_callback (profiler_handle, thread_end);
643701
644702 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+
646706 mono_profiler_set_jit_begin_callback (profiler_handle, jit_begin);
647707 mono_profiler_set_jit_done_callback (profiler_handle, jit_done);
648708 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+ }
649728 }
650729
651730 parse_gdb_options ();
@@ -1624,11 +1703,11 @@ MonodroidRuntime::Java_mono_android_Runtime_register (JNIEnv *env, jstring manag
16241703JNIEXPORT void
16251704JNICALL Java_mono_android_Runtime_dumpTimingData ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jclass klass)
16261705{
1627- if (internal_timing = = nullptr ) {
1628- return ;
1706+ if (internal_timing ! = nullptr ) {
1707+ internal_timing-> dump () ;
16291708 }
16301709
1631- internal_timing-> dump ();
1710+ monodroidRuntime. dump_method_events ();
16321711}
16331712
16341713JNIEXPORT void
0 commit comments