diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
index f2379fc9ff34d..6fd91975b78a8 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Directory.Build.props
@@ -220,6 +220,7 @@
+
diff --git a/src/mono/browser/browser.proj b/src/mono/browser/browser.proj
index 759fa68ae5474..669270cf332d0 100644
--- a/src/mono/browser/browser.proj
+++ b/src/mono/browser/browser.proj
@@ -385,8 +385,8 @@
$(ArtifactsObjDir)wasm/pinvoke-table.h
$(ArtifactsObjDir)wasm/wasm_m2n_invoke.g.h
- -g -Os -DDEBUG=1 -DENABLE_AOT_PROFILER=1 -DENABLE_BROWSER_PROFILER=1
- -Oz -DENABLE_BROWSER_PROFILER=1
+ -g -Os -DDEBUG=1 -DENABLE_AOT_PROFILER=1 -DENABLE_BROWSER_PROFILER=1 -DENABLE_LOG_PROFILER=1
+ -Oz
$(CMakeConfigurationEmccFlags) -s ASSERTIONS=1
-O2
diff --git a/src/mono/browser/build/BrowserWasmApp.targets b/src/mono/browser/build/BrowserWasmApp.targets
index 3b5683433fe86..79ab3cfd83313 100644
--- a/src/mono/browser/build/BrowserWasmApp.targets
+++ b/src/mono/browser/build/BrowserWasmApp.targets
@@ -314,6 +314,7 @@
<_EmccCFlags Include="-DLINK_ICALLS=1" Condition="'$(WasmLinkIcalls)' == 'true'" />
<_EmccCFlags Include="-DENABLE_AOT_PROFILER=1" Condition="$(WasmProfilers.Contains('aot'))" />
<_EmccCFlags Include="-DENABLE_BROWSER_PROFILER=1" Condition="$(WasmProfilers.Contains('browser'))" />
+ <_EmccCFlags Include="-DENABLE_LOG_PROFILER=1" Condition="$(WasmProfilers.Contains('log'))" />
<_EmccCFlags Include="-DENABLE_JS_INTEROP_BY_VALUE=1" Condition="'$(WasmEnableJsInteropByValue)' == 'true'" />
<_EmccCFlags Include="-DGEN_PINVOKE=1" />
@@ -368,6 +369,7 @@
+
diff --git a/src/mono/browser/runtime/cwraps.ts b/src/mono/browser/runtime/cwraps.ts
index 2819e0c44b7f1..c65651dd95de2 100644
--- a/src/mono/browser/runtime/cwraps.ts
+++ b/src/mono/browser/runtime/cwraps.ts
@@ -65,9 +65,10 @@ const fn_signatures: SigLine[] = [
[false, "mono_wasm_exit", "void", ["number"]],
[true, "mono_wasm_getenv", "number", ["string"]],
[true, "mono_wasm_set_main_args", "void", ["number", "number"]],
- // These two need to be lazy because they may be missing
+ // These three need to be lazy because they may be missing
[() => !runtimeHelpers.emscriptenBuildOptions.enableAotProfiler, "mono_wasm_profiler_init_aot", "void", ["string"]],
[() => !runtimeHelpers.emscriptenBuildOptions.enableBrowserProfiler, "mono_wasm_profiler_init_browser", "void", ["string"]],
+ [() => !runtimeHelpers.emscriptenBuildOptions.enableLogProfiler, "mono_wasm_profiler_init_log", "void", ["string"]],
[true, "mono_wasm_profiler_init_browser", "void", ["number"]],
[false, "mono_wasm_exec_regression", "number", ["number", "string"]],
[false, "mono_wasm_invoke_jsexport", "void", ["number", "number"]],
@@ -165,6 +166,7 @@ export interface t_ThreadingCwraps {
export interface t_ProfilerCwraps {
mono_wasm_profiler_init_aot(desc: string): void;
mono_wasm_profiler_init_browser(desc: string): void;
+ mono_wasm_profiler_init_log(desc: string): void;
}
export interface t_Cwraps {
diff --git a/src/mono/browser/runtime/driver.c b/src/mono/browser/runtime/driver.c
index 1b3663e4f3f3c..2a1d5b1dbbf16 100644
--- a/src/mono/browser/runtime/driver.c
+++ b/src/mono/browser/runtime/driver.c
@@ -430,6 +430,18 @@ mono_wasm_profiler_init_browser (const char *desc)
#endif
+#ifdef ENABLE_LOG_PROFILER
+
+void mono_profiler_init_log (const char *desc);
+
+EMSCRIPTEN_KEEPALIVE void
+mono_wasm_profiler_init_log (const char *desc)
+{
+ mono_profiler_init_log (desc);
+}
+
+#endif
+
EMSCRIPTEN_KEEPALIVE void
mono_wasm_init_finalizer_thread (void)
{
diff --git a/src/mono/browser/runtime/es6/dotnet.es6.lib.js b/src/mono/browser/runtime/es6/dotnet.es6.lib.js
index 69b6c31376f9e..687025478570e 100644
--- a/src/mono/browser/runtime/es6/dotnet.es6.lib.js
+++ b/src/mono/browser/runtime/es6/dotnet.es6.lib.js
@@ -11,6 +11,7 @@ const WASM_ENABLE_SIMD = process.env.WASM_ENABLE_SIMD === "1";
const WASM_ENABLE_EH = process.env.WASM_ENABLE_EH === "1";
const ENABLE_BROWSER_PROFILER = process.env.ENABLE_BROWSER_PROFILER === "1";
const ENABLE_AOT_PROFILER = process.env.ENABLE_AOT_PROFILER === "1";
+const ENABLE_LOG_PROFILER = process.env.ENABLE_LOG_PROFILER === "1";
const RUN_AOT_COMPILATION = process.env.RUN_AOT_COMPILATION === "1";
var methodIndexByName = undefined;
var gitHash = undefined;
@@ -88,6 +89,7 @@ function injectDependencies() {
`wasmEnableEH: ${WASM_ENABLE_EH ? "true" : "false"},` +
`enableAotProfiler: ${ENABLE_AOT_PROFILER ? "true" : "false"}, ` +
`enableBrowserProfiler: ${ENABLE_BROWSER_PROFILER ? "true" : "false"}, ` +
+ `enableLogProfiler: ${ENABLE_LOG_PROFILER ? "true" : "false"}, ` +
`runAOTCompilation: ${RUN_AOT_COMPILATION ? "true" : "false"}, ` +
`wasmEnableThreads: ${USE_PTHREADS ? "true" : "false"}, ` +
`gitHash: "${gitHash}", ` +
diff --git a/src/mono/browser/runtime/profiler.ts b/src/mono/browser/runtime/profiler.ts
index a223a7fdbf4a7..0829b3ec71a66 100644
--- a/src/mono/browser/runtime/profiler.ts
+++ b/src/mono/browser/runtime/profiler.ts
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
import { ENVIRONMENT_IS_WEB, mono_assert, runtimeHelpers } from "./globals";
-import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions } from "./types/internal";
+import { MonoMethod, AOTProfilerOptions, BrowserProfilerOptions, LogProfilerOptions } from "./types/internal";
import { profiler_c_functions as cwraps } from "./cwraps";
import { utf8ToString } from "./strings";
@@ -34,6 +34,12 @@ export function mono_wasm_init_browser_profiler (options: BrowserProfilerOptions
cwraps.mono_wasm_profiler_init_browser(arg);
}
+export function mono_wasm_init_log_profiler (options: LogProfilerOptions): void {
+ mono_assert(runtimeHelpers.emscriptenBuildOptions.enableLogProfiler, "Log profiler is not enabled, please use log; in your project file.");
+ mono_assert(options.takeHeapshot, "Log profiler is not enabled, the takeHeapshot method must be defined in LogProfilerOptions.takeHeapshot");
+ cwraps.mono_wasm_profiler_init_log( (options.configuration || "log:alloc,output=output.mlpd") + `,take-heapshot-method=${options.takeHeapshot}`);
+}
+
export const enum MeasuredBlock {
emscriptenStartup = "mono.emscriptenStartup",
instantiateWasm = "mono.instantiateWasm",
diff --git a/src/mono/browser/runtime/startup.ts b/src/mono/browser/runtime/startup.ts
index b29bbbecf2a8d..b27364136c223 100644
--- a/src/mono/browser/runtime/startup.ts
+++ b/src/mono/browser/runtime/startup.ts
@@ -9,7 +9,7 @@ import { exportedRuntimeAPI, INTERNAL, loaderHelpers, Module, runtimeHelpers, cr
import cwraps, { init_c_exports, threads_c_functions as tcwraps } from "./cwraps";
import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
import { toBase64StringImpl } from "./base64";
-import { mono_wasm_init_aot_profiler, mono_wasm_init_browser_profiler } from "./profiler";
+import { mono_wasm_init_aot_profiler, mono_wasm_init_browser_profiler, mono_wasm_init_log_profiler } from "./profiler";
import { initialize_marshalers_to_cs } from "./marshal-to-cs";
import { initialize_marshalers_to_js } from "./marshal-to-js";
import { init_polyfills_async } from "./polyfills";
@@ -543,6 +543,9 @@ export async function start_runtime () {
if (runtimeHelpers.config.browserProfilerOptions)
mono_wasm_init_browser_profiler(runtimeHelpers.config.browserProfilerOptions);
+ if (runtimeHelpers.config.logProfilerOptions)
+ mono_wasm_init_log_profiler(runtimeHelpers.config.logProfilerOptions);
+
if (WasmEnableThreads) {
// this is not mono-attached thread, so we can start it earlier
await mono_wasm_init_diagnostics();
diff --git a/src/mono/browser/runtime/types/internal.ts b/src/mono/browser/runtime/types/internal.ts
index 4ec8ced41c32a..5be1b4a617adf 100644
--- a/src/mono/browser/runtime/types/internal.ts
+++ b/src/mono/browser/runtime/types/internal.ts
@@ -77,6 +77,7 @@ export type MonoConfigInternal = MonoConfig & {
assets?: AssetEntryInternal[],
runtimeOptions?: string[], // array of runtime options as strings
aotProfilerOptions?: AOTProfilerOptions, // dictionary-style Object. If omitted, aot profiler will not be initialized.
+ logProfilerOptions?: LogProfilerOptions, // dictionary-style Object. If omitted, log profiler will not be initialized.
browserProfilerOptions?: BrowserProfilerOptions, // dictionary-style Object. If omitted, browser profiler will not be initialized.
waitForDebugger?: number,
appendElementOnExit?: boolean
@@ -273,6 +274,11 @@ export type AOTProfilerOptions = {
export type BrowserProfilerOptions = {
}
+export type LogProfilerOptions = {
+ takeHeapshot?: string,
+ configuration?: string // log profiler options string"
+}
+
// how we extended emscripten Module
export type DotnetModule = EmscriptenModule & DotnetModuleConfig;
export type DotnetModuleInternal = EmscriptenModule & DotnetModuleConfig & EmscriptenModuleInternal;
@@ -289,6 +295,7 @@ export type EmscriptenBuildOptions = {
wasmEnableEH: boolean,
enableAotProfiler: boolean,
enableBrowserProfiler: boolean,
+ enableLogProfiler: boolean,
runAOTCompilation: boolean,
wasmEnableThreads: boolean,
gitHash: string,
diff --git a/src/mono/mono.proj b/src/mono/mono.proj
index 5be3d221fd5b7..8fe15830cabb5 100644
--- a/src/mono/mono.proj
+++ b/src/mono/mono.proj
@@ -1185,6 +1185,9 @@ JS_ENGINES = [NODE_JS]
<_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true' and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-profiler-aot.a">
$(RuntimeBinDir)libmono-profiler-aot.a
+ <_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true' and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-profiler-log.a">
+ $(RuntimeBinDir)libmono-profiler-log.a
+
<_MonoRuntimeArtifacts Condition="'$(TargetsBrowser)' == 'true' and '$(BuildMonoAOTCrossCompilerOnly)' != 'true'" Include="$(MonoObjDir)out\lib\libmono-profiler-browser.a">
$(RuntimeBinDir)libmono-profiler-browser.a
diff --git a/src/mono/mono/mini/mini-wasm.c b/src/mono/mono/mini/mini-wasm.c
index db7c8b2de39a6..fa159b852a0fc 100644
--- a/src/mono/mono/mini/mini-wasm.c
+++ b/src/mono/mono/mini/mini-wasm.c
@@ -573,7 +573,6 @@ mono_init_native_crash_info (void)
void
mono_runtime_setup_stat_profiler (void)
{
- g_error ("mono_runtime_setup_stat_profiler");
}
gboolean
diff --git a/src/mono/mono/profiler/CMakeLists.txt b/src/mono/mono/profiler/CMakeLists.txt
index e172774a6ebc5..f4271dc8bd4f8 100644
--- a/src/mono/mono/profiler/CMakeLists.txt
+++ b/src/mono/mono/profiler/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories(
${PROJECT_BINARY_DIR}/../../mono/eglib
${CMAKE_CURRENT_SOURCE_DIR}/../..
${PROJECT_SOURCE_DIR}/../
+ ${PROJECT_SOURCE_DIR}/../../../native/public
${PROJECT_SOURCE_DIR}/../eglib
${PROJECT_SOURCE_DIR}/../sgen)
@@ -47,4 +48,18 @@ if(NOT DISABLE_LIBS)
set_target_properties(mono-profiler-browser-static PROPERTIES OUTPUT_NAME mono-profiler-browser)
install(TARGETS mono-profiler-browser-static LIBRARY)
endif()
+
+ if(HOST_BROWSER)
+ add_library(mono-profiler-log-static STATIC helper.c log.c log-args.c)
+ set_target_properties(mono-profiler-log-static PROPERTIES OUTPUT_NAME mono-profiler-log)
+ install(TARGETS mono-profiler-log-static LIBRARY)
+
+ if(NOT DISABLE_LOG_PROFILER_GZ)
+ if (CLR_CMAKE_USE_SYSTEM_ZLIB)
+ target_link_libraries(mono-profiler-log-static PRIVATE ${Z_LIBS})
+ else()
+ target_link_libraries(mono-profiler-log-static PRIVATE zlib)
+ endif()
+ endif()
+ endif()
endif()
diff --git a/src/mono/mono/profiler/helper.c b/src/mono/mono/profiler/helper.c
index bbff8e7bf957b..05fc31b670840 100644
--- a/src/mono/mono/profiler/helper.c
+++ b/src/mono/mono/profiler/helper.c
@@ -8,7 +8,9 @@
#include
+#if !defined (HOST_WASM)
#include
+#endif
#ifdef HAVE_UNISTD_H
#include
@@ -42,6 +44,7 @@ mono_profhelper_close_socket_fd (SOCKET fd)
void
mono_profhelper_setup_command_server (SOCKET *server_socket, int *command_port, const char* profiler_name)
{
+#if !defined (HOST_WASM)
*server_socket = socket (PF_INET, SOCK_STREAM, 0);
if (*server_socket == INVALID_SOCKET) {
@@ -77,11 +80,13 @@ mono_profhelper_setup_command_server (SOCKET *server_socket, int *command_port,
}
*command_port = ntohs (server_address.sin_port);
+#endif
}
void
mono_profhelper_add_to_fd_set (fd_set *set, SOCKET fd, int *max_fd)
{
+#if !defined (HOST_WASM)
/*
* This should only trigger for the basic FDs (server socket, pipes) at
* startup if for some mysterious reason they're too large. In this case,
@@ -99,4 +104,5 @@ mono_profhelper_add_to_fd_set (fd_set *set, SOCKET fd, int *max_fd)
if (*max_fd < GUINT64_TO_INT(fd))
*max_fd = (int)fd;
+#endif
}
diff --git a/src/mono/mono/profiler/log-args.c b/src/mono/mono/profiler/log-args.c
index c8609177d18b0..124a629a14ca3 100644
--- a/src/mono/mono/profiler/log-args.c
+++ b/src/mono/mono/profiler/log-args.c
@@ -1,4 +1,5 @@
#include
+#include
#include
#include
#include
@@ -98,6 +99,9 @@ parse_arg (const char *arg, ProfilerConfig *config)
} else if (match_option (arg, "heapshot-on-shutdown", NULL)) {
config->hs_on_shutdown = TRUE;
config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS;
+ } else if (match_option (arg, "take-heapshot-method", &val)) {
+ printf ("take-heapshot-method: %s\n", val);
+ set_log_profiler_take_heapshot_method(val);
} else if (match_option (arg, "sample", &val)) {
set_sample_freq (config, val);
config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS;
diff --git a/src/mono/mono/profiler/log.c b/src/mono/mono/profiler/log.c
index abe5f3f479f57..24d3834296604 100644
--- a/src/mono/mono/profiler/log.c
+++ b/src/mono/mono/profiler/log.c
@@ -189,6 +189,8 @@ typedef struct {
int small_id;
} MonoProfilerThread;
+static MonoMethodDesc *log_profiler_take_heapshot_method;
+
// Default value in `profiler_tls` for new threads.
#define MONO_PROFILER_THREAD_ZERO ((MonoProfilerThread *) NULL)
@@ -617,6 +619,7 @@ buffer_lock_helper (void);
static void
buffer_lock (void)
{
+#if !defined (HOST_WASM)
/*
* If the thread holding the exclusive lock tries to modify the
* reader count, just make it a no-op. This way, we also avoid
@@ -657,6 +660,8 @@ buffer_lock (void)
}
mono_memory_barrier ();
+
+#endif // HOST_WASM
}
static void
@@ -685,6 +690,7 @@ buffer_lock_helper (void)
static void
buffer_unlock (void)
{
+#if !defined (HOST_WASM)
mono_memory_barrier ();
gint32 state = mono_atomic_load_i32 (&log_profiler.buffer_lock_state);
@@ -697,6 +703,7 @@ buffer_unlock (void)
g_assert (!(state >> 16) && "Why is the exclusive lock held?");
mono_atomic_dec_i32 (&log_profiler.buffer_lock_state);
+#endif // HOST_WASM
}
static void
@@ -3499,6 +3506,7 @@ runtime_initialized (MonoProfiler *profiler)
mono_os_sem_init (&log_profiler.attach_threads_sem, 0);
+#if !defined (HOST_WASM)
/*
* We must start the helper thread before the writer thread. This is
* because start_helper_thread () sets up the command port which is written
@@ -3507,6 +3515,9 @@ runtime_initialized (MonoProfiler *profiler)
start_helper_thread ();
start_writer_thread ();
start_dumper_thread ();
+#else
+ dump_header ();
+#endif
/*
* Wait for all the internal threads to be started. If we don't do this, we
@@ -3588,7 +3599,7 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters)
}
}
if (*nf == '|') {
-#if HAVE_API_SUPPORT_WIN32_PIPE_OPEN_CLOSE && !defined (HOST_WIN32)
+#if HAVE_API_SUPPORT_WIN32_PIPE_OPEN_CLOSE && !defined (HOST_WIN32) && !defined (HOST_WASM)
log_profiler.file = popen (nf + 1, "w");
log_profiler.pipe_output = 1;
#else
@@ -3636,6 +3647,44 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters)
log_profiler.startup_time = current_time ();
}
+void
+set_log_profiler_take_heapshot_method (const char *val)
+{
+ log_profiler_take_heapshot_method = mono_method_desc_new (val, TRUE);
+
+ if (!log_profiler_take_heapshot_method) {
+ mono_profiler_printf_err ("Could not parse method description: %s", val);
+ exit (1);
+ }
+}
+
+static void
+proflog_trigger_heapshot (void);
+
+static void
+prof_jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
+{
+ MonoImage *image = mono_class_get_image (mono_method_get_class (method));
+
+ if (!image->assembly || method->wrapper_type || !log_profiler_take_heapshot_method)
+ return;
+
+ if (log_profiler_take_heapshot_method && mono_method_desc_match (log_profiler_take_heapshot_method, method)) {
+ printf ("log-profiler | taking heapshot\n");
+ proflog_trigger_heapshot ();
+ return;
+ }
+ else {
+ printf ("log-profiler not called (%p)\n", log_profiler_take_heapshot_method);
+ }
+}
+
+static void
+prof_inline_method (MonoProfiler *prof, MonoMethod *method, MonoMethod *inlined_method)
+{
+ prof_jit_done (prof, inlined_method, NULL);
+}
+
MONO_API void
mono_profiler_init_log (const char *desc);
@@ -3758,6 +3807,9 @@ mono_profiler_init_log (const char *desc)
mono_profiler_enable_allocations ();
mono_profiler_enable_clauses ();
mono_profiler_enable_sampling (handle);
+ mono_profiler_set_jit_done_callback (handle, prof_jit_done);
+ mono_profiler_set_inline_method_callback (handle, prof_inline_method);
+
/*
* If no sample option was given by the user, this just leaves the sampling
@@ -3770,3 +3822,12 @@ mono_profiler_init_log (const char *desc)
done:
;
}
+
+static void
+proflog_trigger_heapshot (void)
+{
+ trigger_heapshot ();
+
+ while (handle_writer_queue_entry ());
+ while (handle_dumper_queue_entry ());
+}
\ No newline at end of file
diff --git a/src/mono/mono/profiler/log.h b/src/mono/mono/profiler/log.h
index 9e3b320a7cfb2..a246afd1c1788 100644
--- a/src/mono/mono/profiler/log.h
+++ b/src/mono/mono/profiler/log.h
@@ -526,5 +526,6 @@ typedef struct {
} ProfilerConfig;
void proflog_parse_args (ProfilerConfig *config, const char *desc);
+void set_log_profiler_take_heapshot_method (const char *val);
#endif /* __MONO_PROFLOG_H__ */