From aafa4acf63b316f49bd3cc092dfba82e3a206a5f Mon Sep 17 00:00:00 2001 From: David Rogers Date: Wed, 4 Apr 2018 10:32:46 -0500 Subject: [PATCH] File IO profile support --- mono/metadata/profiler-events.h | 1 + mono/metadata/profiler-private.h | 1 + mono/metadata/profiler.c | 30 ++++++++++++++- mono/metadata/profiler.h | 1 + mono/metadata/w32file-unix.c | 3 ++ mono/metadata/w32file-win32.c | 3 ++ mono/profiler/log-args.c | 1 + mono/profiler/log.c | 63 +++++++++++++++++++++++++++++++- mono/profiler/log.h | 4 +- 9 files changed, 104 insertions(+), 3 deletions(-) diff --git a/mono/metadata/profiler-events.h b/mono/metadata/profiler-events.h index 5e933d0c9fbf..c603ca224323 100644 --- a/mono/metadata/profiler-events.h +++ b/mono/metadata/profiler-events.h @@ -95,6 +95,7 @@ MONO_PROFILER_EVENT_1(gc_finalized_object, GCFinalizedObject, MonoObject *, obje MONO_PROFILER_EVENT_5(gc_root_register, RootRegister, const mono_byte *, start, uintptr_t, size, MonoGCRootSource, source, const void *, key, const char *, name) MONO_PROFILER_EVENT_1(gc_root_unregister, RootUnregister, const mono_byte *, start) MONO_PROFILER_EVENT_3(gc_roots, GCRoots, uint64_t, count, const mono_byte *const *, addresses, MonoObject *const *, objects) +MONO_PROFILER_EVENT_2(fileio, FileIO, uint64_t, kind, uint64_t, size) MONO_PROFILER_EVENT_1(monitor_contention, MonitorContention, MonoObject *, object) MONO_PROFILER_EVENT_1(monitor_failed, MonitorFailed, MonoObject *, object) diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index 3c0fe896c4ff..6b5b0be860e3 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -59,6 +59,7 @@ typedef struct { guint32 sample_freq; gboolean allocations; + gboolean fileio; gboolean call_contexts; void (*context_enable) (void); diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index 705fa0cccc80..a4c7a71c6e0b 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -567,6 +567,12 @@ mono_profiler_enable_allocations (void) return mono_profiler_state.allocations = TRUE; } +mono_bool +mono_profiler_enable_fileio (void) +{ + return mono_profiler_state.fileio = TRUE; +} + /** * mono_profiler_set_call_instrumentation_filter_callback: * @@ -952,6 +958,7 @@ typedef void (*MonoLegacyProfileAllocFunc) (MonoLegacyProfiler *prof, MonoObject typedef void (*MonoLegacyProfileMethodFunc) (MonoLegacyProfiler *prof, MonoMethod *method); typedef void (*MonoLegacyProfileExceptionFunc) (MonoLegacyProfiler *prof, MonoObject *object); typedef void (*MonoLegacyProfileExceptionClauseFunc) (MonoLegacyProfiler *prof, MonoMethod *method, int clause_type, int clause_num); +typedef void (*MonoLegacyProfileFileIOFunc) (MonoLegacyProfiler *prof, int kind, int size); struct _MonoProfiler { MonoProfilerHandle handle; @@ -962,6 +969,7 @@ struct _MonoProfiler { MonoLegacyProfileGCResizeFunc gc_heap_resize; MonoLegacyProfileJitResult jit_end2; MonoLegacyProfileAllocFunc allocation; + MonoLegacyProfileFileIOFunc fileio; MonoLegacyProfileMethodFunc enter; MonoLegacyProfileMethodFunc leave; MonoLegacyProfileExceptionFunc throw_callback; @@ -978,6 +986,7 @@ MONO_API void mono_profiler_install_jit_end (MonoLegacyProfileJitResult end); MONO_API void mono_profiler_set_events (int flags); MONO_API void mono_profiler_install_allocation (MonoLegacyProfileAllocFunc callback); MONO_API void mono_profiler_install_enter_leave (MonoLegacyProfileMethodFunc enter, MonoLegacyProfileMethodFunc fleave); +MONO_API void mono_profiler_install_fileio (MonoLegacyProfileFileIOFunc callback); MONO_API void mono_profiler_install_exception (MonoLegacyProfileExceptionFunc throw_callback, MonoLegacyProfileMethodFunc exc_method_leave, MonoLegacyProfileExceptionClauseFunc clause_callback); static void @@ -1096,7 +1105,8 @@ typedef enum MONO_PROFILE_ENTER_LEAVE = 1 << 12, MONO_PROFILE_COVERAGE = 1 << 13, MONO_PROFILE_INS_COVERAGE = 1 << 14, - MONO_PROFILE_STATISTICAL = 1 << 15 + MONO_PROFILE_STATISTICAL = 1 << 15, + MONO_PROFILE_FILEIO = 1 << 16 } LegacyMonoProfileFlags; void @@ -1110,6 +1120,9 @@ mono_profiler_set_events (int flags) if (flags & MONO_PROFILE_ALLOCATIONS) mono_profiler_enable_allocations (); + + if (flags & MONO_PROFILE_FILEIO) + mono_profiler_enable_fileio (); } static void @@ -1127,6 +1140,21 @@ mono_profiler_install_allocation (MonoLegacyProfileAllocFunc callback) mono_profiler_set_gc_allocation_callback (current->handle, allocation_cb); } +static void +fileio_cb (MonoProfiler *prof, uint64_t kind, uint64_t size) +{ + prof->fileio (prof->profiler, kind, size); +} + +void +mono_profiler_install_fileio (MonoLegacyProfileFileIOFunc callback) +{ + current->fileio = callback; + + if (callback) + mono_profiler_set_fileio_callback (current->handle, fileio_cb); +} + static void enter_cb (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context) { diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h index a2110902296e..f86021698410 100644 --- a/mono/metadata/profiler.h +++ b/mono/metadata/profiler.h @@ -70,6 +70,7 @@ MONO_API mono_bool mono_profiler_set_sample_mode (MonoProfilerHandle handle, Mon MONO_API mono_bool mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq); MONO_API mono_bool mono_profiler_enable_allocations (void); +MONO_API mono_bool mono_profiler_enable_fileio (void); typedef struct _MonoProfilerCallContext MonoProfilerCallContext; diff --git a/mono/metadata/w32file-unix.c b/mono/metadata/w32file-unix.c index 94d9b547da3a..b170a3872afb 100644 --- a/mono/metadata/w32file-unix.c +++ b/mono/metadata/w32file-unix.c @@ -40,6 +40,7 @@ #include "w32file-unix-glob.h" #include "w32error.h" #include "fdhandle.h" +#include "mono/metadata/profiler-private.h" #include "utils/mono-io-portability.h" #include "utils/mono-logger-internals.h" #include "utils/mono-os-mutex.h" @@ -1037,6 +1038,7 @@ file_read(FileHandle *filehandle, gpointer buffer, guint32 numbytes, guint32 *by if (bytesread != NULL) { *bytesread = ret; + MONO_PROFILER_RAISE (fileio, (1, *bytesread)); } return(TRUE); @@ -1104,6 +1106,7 @@ file_write(FileHandle *filehandle, gconstpointer buffer, guint32 numbytes, guint } if (byteswritten != NULL) { *byteswritten = ret; + MONO_PROFILER_RAISE (fileio, (0, *byteswritten)); } return(TRUE); } diff --git a/mono/metadata/w32file-win32.c b/mono/metadata/w32file-win32.c index 7d08aefdeeb0..90fc55bfa08f 100644 --- a/mono/metadata/w32file-win32.c +++ b/mono/metadata/w32file-win32.c @@ -11,6 +11,7 @@ #include #include #include "mono/metadata/w32file-win32-internals.h" +#include "mono/metadata/profiler-private.h" void mono_w32file_init (void) @@ -87,6 +88,7 @@ mono_w32file_read(gpointer handle, gpointer buffer, guint32 numbytes, guint32 *b gboolean res; MONO_ENTER_GC_SAFE; res = ReadFile (handle, buffer, numbytes, bytesread, NULL); + MONO_PROFILER_RAISE (fileio, (1, *bytesread)); MONO_EXIT_GC_SAFE; return res; } @@ -97,6 +99,7 @@ mono_w32file_write (gpointer handle, gconstpointer buffer, guint32 numbytes, gui gboolean res; MONO_ENTER_GC_SAFE; res = WriteFile (handle, buffer, numbytes, byteswritten, NULL); + MONO_PROFILER_RAISE (fileio, (0, *byteswritten)); MONO_EXIT_GC_SAFE; return res; } diff --git a/mono/profiler/log-args.c b/mono/profiler/log-args.c index 0c8bd040a386..3c707283859d 100644 --- a/mono/profiler/log-args.c +++ b/mono/profiler/log-args.c @@ -27,6 +27,7 @@ static NameAndMask event_list[] = { { "counters", PROFLOG_COUNTER_EVENTS }, { "alloc", PROFLOG_ALLOC_ALIAS, PROFLOG_ALLOC_ALIAS | PROFLOG_GC_ROOT_EVENTS }, + { "fileio", PROFLOG_FILEIO_EVENTS }, { "legacy", PROFLOG_LEGACY_ALIAS }, }; diff --git a/mono/profiler/log.c b/mono/profiler/log.c index e0c19bed121e..c31f386edde0 100644 --- a/mono/profiler/log.c +++ b/mono/profiler/log.c @@ -112,7 +112,10 @@ static gint32 sync_points_ctr, coverage_methods_ctr, coverage_statements_ctr, coverage_classes_ctr, - coverage_assemblies_ctr; + coverage_assemblies_ctr, + fileio_reads_ctr, + fileio_writes_ctr; + // Pending data to be written to the log, for a single thread. // Threads periodically flush their own LogBuffers by calling safe_send @@ -1656,6 +1659,37 @@ finalize_object_end (MonoProfiler *prof, MonoObject *obj) EXIT_LOG; } +static void +fileio (MonoProfiler *prof, uint64_t kind, uint64_t size) +{ + if (kind == 0) + { + ENTER_LOG (&fileio_writes_ctr, buf, + EVENT_SIZE /* event */ + + LEB128_SIZE /* kind */ + + LEB128_SIZE /* size */ + ); + emit_event (buf, TYPE_FILEIO); + emit_value (buf, kind); + emit_value (buf, size); + + EXIT_LOG; + } + else + { + ENTER_LOG (&fileio_reads_ctr, buf, + EVENT_SIZE /* event */ + + LEB128_SIZE /* kind */ + + LEB128_SIZE /* size */ + ); + emit_event (buf, TYPE_FILEIO); + emit_value (buf, kind); + emit_value (buf, size); + + EXIT_LOG; + } +} + static char* push_nesting (char *p, MonoClass *klass) { @@ -4416,6 +4450,28 @@ proflog_icall_SetGCAllocationEvents (MonoBoolean value) mono_coop_mutex_unlock (&log_profiler.api_mutex); } +ICALL_EXPORT MonoBoolean +proflog_icall_GetFileIOEvents (void) +{ + return ENABLED (PROFLOG_FILEIO_EVENTS); +} + +ICALL_EXPORT void +proflog_icall_SetFileIOEvents (MonoBoolean value) +{ + mono_coop_mutex_lock (&log_profiler.api_mutex); + + if (value) { + ENABLE (PROFLOG_FILEIO_EVENTS); + mono_profiler_set_fileio_callback (log_profiler.handle, fileio); + } else { + DISABLE (PROFLOG_FILEIO_EVENTS); + mono_profiler_set_fileio_callback (log_profiler.handle, NULL); + } + + mono_coop_mutex_unlock (&log_profiler.api_mutex); +} + ICALL_EXPORT MonoBoolean proflog_icall_GetGCMoveEvents (void) { @@ -4604,6 +4660,8 @@ runtime_initialized (MonoProfiler *profiler) register_counter ("Event: Coverage statements", &coverage_statements_ctr); register_counter ("Event: Coverage classes", &coverage_classes_ctr); register_counter ("Event: Coverage assemblies", &coverage_assemblies_ctr); + register_counter ("Event: File IO reads", &fileio_reads_ctr); + register_counter ("Event: File IO writes", &fileio_writes_ctr); counters_init (); @@ -4848,6 +4906,9 @@ mono_profiler_init_log (const char *desc) mono_profiler_set_gc_finalizing_object_callback (handle, finalize_object_begin); } + if (ENABLED (PROFLOG_FILEIO_EVENTS)) + mono_profiler_set_fileio_callback (handle, fileio); + //On Demand heapshot uses the finalizer thread to force a collection and thus a heapshot mono_profiler_set_gc_finalized_callback (handle, finalize_end); diff --git a/mono/profiler/log.h b/mono/profiler/log.h index 8ea1991e36ec..7d306a764997 100644 --- a/mono/profiler/log.h +++ b/mono/profiler/log.h @@ -386,6 +386,7 @@ enum { TYPE_RUNTIME, TYPE_COVERAGE, TYPE_META, + TYPE_FILEIO, /* extended type for TYPE_HEAP */ TYPE_HEAP_START = 0 << 4, TYPE_HEAP_END = 1 << 4, @@ -491,10 +492,11 @@ typedef enum { #define PROFLOG_COUNTER_EVENTS (1 << 8) #define PROFLOG_SAMPLE_EVENTS (1 << 9) #define PROFLOG_JIT_EVENTS (1 << 10) +#define PROFLOG_FILEIO_EVENTS (1 << 11) #define PROFLOG_ALLOC_ALIAS (PROFLOG_GC_EVENTS | PROFLOG_GC_ALLOCATION_EVENTS | PROFLOG_GC_MOVE_EVENTS) #define PROFLOG_HEAPSHOT_ALIAS (PROFLOG_GC_EVENTS | PROFLOG_GC_ROOT_EVENTS) -#define PROFLOG_LEGACY_ALIAS (PROFLOG_EXCEPTION_EVENTS | PROFLOG_MONITOR_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_GC_MOVE_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_GC_HANDLE_EVENTS | PROFLOG_GC_FINALIZATION_EVENTS | PROFLOG_COUNTER_EVENTS) +#define PROFLOG_LEGACY_ALIAS (PROFLOG_EXCEPTION_EVENTS | PROFLOG_MONITOR_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_GC_MOVE_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_GC_HANDLE_EVENTS | PROFLOG_GC_FINALIZATION_EVENTS | PROFLOG_COUNTER_EVENTS | PROFLOG_FILEIO_EVENTS) typedef struct { //Events explicitly enabled