Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[wasm-ep] Minimal diagnostic tracing configuration and sample #69158

Merged
merged 38 commits into from
May 19, 2022
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
8166db7
add DISABLE_WASM_USER_THREADS mono cmake option
lambdageek Apr 26, 2022
a4dd0a8
Disable Thread.StartInternal icall if DISABLE_WASM_USER_THREADS
lambdageek Apr 29, 2022
3f6af6f
add an eventpipe sample
lambdageek May 2, 2022
cc7162f
[wasm-ep] (browser-eventpipe sample) run loop for longer
lambdageek May 2, 2022
f269cee
[samples/wasm-eventpipe] make an async task sample
lambdageek May 9, 2022
18f73b9
[wasm] Add MONO.diagnostics interface
lambdageek May 9, 2022
75d33cb
if wasm threads are disabled, but perftracing is enabled, don't log
lambdageek May 10, 2022
327502d
fix whitespace and nits
lambdageek May 10, 2022
fafeced
don't need try/finally in the sample anymore
lambdageek May 10, 2022
252d06a
more whitespace
lambdageek May 10, 2022
8b54aab
add start method to EventPipeSession interface
lambdageek May 10, 2022
e2e1b66
don't run wasm-eventpipe sample on CI lanes without perftracing
lambdageek May 11, 2022
ded3aeb
more whitespace
lambdageek May 11, 2022
46c1a7c
fix eslint warnings, default rundown to true, allow callback for trac…
lambdageek May 11, 2022
c29915d
add EventPipeSession.getTraceBlob and EventPipeSession.getTraceDataURI
lambdageek May 11, 2022
8287396
[browser-eventpipe sample] remove unnecessary ref assemblies
lambdageek May 11, 2022
a7bd41b
use toBase64StringImpl instead of btoa
lambdageek May 11, 2022
be8d199
use int64_t for event pipe session IDs
lambdageek May 11, 2022
63190bd
use ep_char8_t for C decls of event pipe wasm exports
lambdageek May 11, 2022
4c50aa6
fix debug output
lambdageek May 11, 2022
a67ecd4
fix endianness issue
lambdageek May 11, 2022
f0577f4
Use stack allocation for temporaries
lambdageek May 11, 2022
99f2ddf
Use 32-bit EventPipe session ID on WASM
lambdageek May 12, 2022
cdf8909
Make the sample do more work in managed
lambdageek May 12, 2022
9c70c5c
Move withStackAlloc to memory.ts
lambdageek May 16, 2022
5af5b80
fix option description
lambdageek May 16, 2022
8fcb319
simplify VFS .nettrace file naming
lambdageek May 16, 2022
a3d681c
Add overloads to memory.withStackAlloc to avoid creating closures
lambdageek May 16, 2022
173081c
sample: explain why there's a 10s pause
lambdageek May 16, 2022
f07daea
move createEventPipeSession callback to a function
lambdageek May 16, 2022
61dbd2f
Merge remote-tracking branch 'origin/main' into wasm-ep
lambdageek May 18, 2022
886df1b
Merge branch 'main' into wasm-ep
lambdageek May 18, 2022
19f9659
fix whitespace
lambdageek May 18, 2022
c16d22c
Use a tuple type for withStackAlloc
lambdageek May 18, 2022
dc1dbad
fix whitespace
lambdageek May 18, 2022
82ba6c4
go back to explicit args for withStackAlloc insead of rest/spread
lambdageek May 18, 2022
aed3660
use unsigned 32-bit get/set in cuint64 get/set
lambdageek May 18, 2022
0a7381d
cosmetic changes to sample
lambdageek May 18, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/libraries/tests.proj
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
<ProjectExclusions Include="$(MonoProjectRoot)sample\wasm\browser-mt-eventpipe\Wasm.Browser.ThreadsEP.Sample.csproj" />
</ItemGroup>

<!-- Samples that require a perf-tracing wasm runtime -->
<ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(WasmEnablePerfTracing)' != 'true'" >
<ProjectExclusions Include="$(MonoProjectRoot)sample\wasm\browser-eventpipe\Wasm.Browser.EventPipe.Sample.csproj" />
</ItemGroup>

<!-- Wasm aot on all platforms -->
<ItemGroup Condition="'$(TargetOS)' == 'Browser' and '$(BuildAOTTestsOnHelix)' == 'true' and '$(RunDisabledWasmTests)' != 'true' and '$(RunAOTCompilation)' == 'true'">
<!-- https://github.com/dotnet/runtime/issues/66118 -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ internal sealed unsafe class OverlappedData

success = true;
#if FEATURE_PERFTRACING
#if !(TARGET_BROWSER && !FEATURE_WASM_THREADS)
if (NativeRuntimeEventSource.Log.IsEnabled())
NativeRuntimeEventSource.Log.ThreadPoolIOPack(pNativeOverlapped);
#endif
#endif
return _pNativeOverlapped;
}
Expand Down
3 changes: 3 additions & 0 deletions src/mono/cmake/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@
/* Disable Threads */
#cmakedefine DISABLE_THREADS 1

/* Disable user thread creation on WebAssembly */
#cmakedefine DISABLE_WASM_USER_THREADS 1

/* Disable MONO_LOG_DEST */
#cmakedefine DISABLE_LOG_DEST

Expand Down
1 change: 1 addition & 0 deletions src/mono/cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ option (ENABLE_OVERRIDABLE_ALLOCATORS "Enable overridable allocator support")
option (ENABLE_SIGALTSTACK "Enable support for using sigaltstack for SIGSEGV and stack overflow handling, this doesn't work on some platforms")
option (USE_MALLOC_FOR_MEMPOOLS "Use malloc for each single mempool allocation, so tools like Valgrind can run better")
option (STATIC_COMPONENTS "Compile mono runtime components as static (not dynamic) libraries")
option (DISABLE_WASM_USER_THREADS "Disable creation of managed threads, only allow runtime internal threads")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update the message to mention that this only applies to wasm

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated. also clarified that runtime internal managed threads will be allowed (I need them to support the EventPipe counter sampling thread).


set (MONO_GC "sgen" CACHE STRING "Garbage collector implementation (sgen or boehm). Default: sgen")
set (GC_SUSPEND "default" CACHE STRING "GC suspend method (default, preemptive, coop, hybrid)")
Expand Down
63 changes: 63 additions & 0 deletions src/mono/mono/component/event_pipe-stub.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,35 @@
#include "mono/component/event_pipe.h"
#include "mono/metadata/components.h"


#ifdef HOST_WASM
#include <emscripten.h>

G_BEGIN_DECLS

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_enable (const char *output_path,
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
uint32_t circular_buffer_size_in_mb,
const char *providers,
/* EventPipeSessionType session_type = EP_SESSION_TYPE_FILE, */
/* EventPipieSerializationFormat format = EP_SERIALIZATION_FORMAT_NETTRACE_V4, */
/* bool */ gboolean rundown_requested,
/* IpcStream stream = NULL, */
/* EventPipeSessionSycnhronousCallback sync_callback = NULL, */
/* void *callback_additional_data, */
int32_t *out_session_id);
lambdageek marked this conversation as resolved.
Show resolved Hide resolved


EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_start_streaming (int32_t session_id);

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_disable (int32_t session_id);

G_END_DECLS

#endif /* HOST_WASM */

static EventPipeSessionID _dummy_session_id;

static uint8_t _max_event_pipe_type_size [256];
Expand Down Expand Up @@ -495,3 +524,37 @@ mono_component_event_pipe_init (void)
{
return component_event_pipe_stub_init ();
}

#ifdef HOST_WASM

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_enable (const char *output_path,
uint32_t circular_buffer_size_in_mb,
const char *providers,
/* EventPipeSessionType session_type = EP_SESSION_TYPE_FILE, */
/* EventPipieSerializationFormat format = EP_SERIALIZATION_FORMAT_NETTRACE_V4, */
/* bool */ gboolean rundown_requested,
/* IpcStream stream = NULL, */
/* EventPipeSessionSycnhronousCallback sync_callback = NULL, */
/* void *callback_additional_data, */
int32_t *out_session_id)
{
if (out_session_id)
*out_session_id = 0;
return 0;
}


EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_start_streaming (int32_t session_id)
{
g_assert_not_reached ();
}

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_disable (int32_t session_id)
{
g_assert_not_reached ();
}

#endif /* HOST_WASM */
84 changes: 84 additions & 0 deletions src/mono/mono/component/event_pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,39 @@
#include <mono/component/event_pipe.h>
#include <mono/utils/mono-publib.h>
#include <mono/utils/mono-compiler.h>
#include <mono/utils/mono-threads-api.h>
#include <eventpipe/ep.h>
#include <eventpipe/ep-event.h>
#include <eventpipe/ep-event-instance.h>
#include <eventpipe/ep-session.h>

#ifdef HOST_WASM
#include <emscripten.h>

G_BEGIN_DECLS

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_enable (const char *output_path,
uint32_t circular_buffer_size_in_mb,
const char *providers,
/* EventPipeSessionType session_type = EP_SESSION_TYPE_FILE, */
/* EventPipieSerializationFormat format = EP_SERIALIZATION_FORMAT_NETTRACE_V4, */
/* bool */ gboolean rundown_requested,
/* IpcStream stream = NULL, */
/* EventPipeSessionSycnhronousCallback sync_callback = NULL, */
/* void *callback_additional_data, */
int32_t *out_session_id);

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_start_streaming (int32_t session_id);

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_disable (int32_t session_id);

G_END_DECLS

#endif /* HOST_WASM */

extern void ep_rt_mono_component_init (void);
static bool _event_pipe_component_inited = false;

Expand Down Expand Up @@ -327,3 +355,59 @@ mono_component_event_pipe_init (void)

return &fn_table;
}


#ifdef HOST_WASM

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_enable (const char *output_path,
uint32_t circular_buffer_size_in_mb,
const char *providers,
/* EventPipeSessionType session_type = EP_SESSION_TYPE_FILE, */
/* EventPipieSerializationFormat format = EP_SERIALIZATION_FORMAT_NETTRACE_V4, */
/* bool */ gboolean rundown_requested,
/* IpcStream stream = NULL, */
/* EventPipeSessionSycnhronousCallback sync_callback = NULL, */
/* void *callback_additional_data, */
int32_t *out_session_id)
{
MONO_ENTER_GC_UNSAFE;
EventPipeSerializationFormat format = EP_SERIALIZATION_FORMAT_NETTRACE_V4;
EventPipeSessionType session_type = EP_SESSION_TYPE_FILE;

EventPipeSessionID session;
session = ep_enable_2 (output_path,
circular_buffer_size_in_mb,
providers,
session_type,
format,
!!rundown_requested,
/* stream */NULL,
/* callback*/ NULL,
/* callback_data*/ NULL);

if (out_session_id)
*out_session_id = (int32_t)session;
MONO_EXIT_GC_UNSAFE;
return TRUE;
}

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_start_streaming (int32_t session_id)
{
MONO_ENTER_GC_UNSAFE;
ep_start_streaming ((EventPipeSessionID)session_id);
MONO_EXIT_GC_UNSAFE;
return TRUE;
}

EMSCRIPTEN_KEEPALIVE gboolean
mono_wasm_event_pipe_session_disable (int32_t session_id)
{
MONO_ENTER_GC_UNSAFE;
ep_disable ((EventPipeSessionID)session_id);
MONO_EXIT_GC_UNSAFE;
return TRUE;
}

#endif /* HOST_WASM */
2 changes: 1 addition & 1 deletion src/mono/mono/metadata/threads.c
Original file line number Diff line number Diff line change
Expand Up @@ -4815,7 +4815,7 @@ ves_icall_System_Threading_Thread_StartInternal (MonoThreadObjectHandle thread_h
MonoThread *internal = MONO_HANDLE_RAW (thread_handle);
gboolean res;

#ifdef DISABLE_THREADS
#if defined (DISABLE_THREADS) || defined (DISABLE_WASM_USER_THREADS)
mono_error_set_platform_not_supported (error, "Cannot start threads on this runtime.");
kg marked this conversation as resolved.
Show resolved Hide resolved
return;
#endif
Expand Down
11 changes: 11 additions & 0 deletions src/mono/sample/wasm/browser-eventpipe/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
TOP=../../../../..

include ../wasm.mk

ifneq ($(AOT),)
override MSBUILD_ARGS+=/p:RunAOTCompilation=true
endif

PROJECT_NAME=Wasm.Browser.EventPipe.Sample.csproj

run: run-browser
65 changes: 65 additions & 0 deletions src/mono/sample/wasm/browser-eventpipe/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;


namespace Sample
{
public class Test
{
public static void Main(string[] args)
{
Console.WriteLine ("Hello, World!");
kg marked this conversation as resolved.
Show resolved Hide resolved
}

private static int iterations;
private static CancellationTokenSource cts;

public static CancellationToken GetCancellationToken()
{
if (cts == null) {
cts = new CancellationTokenSource ();
}
return cts.Token;
}

[MethodImpl(MethodImplOptions.NoInlining)]
public static async Task<int> StartAsyncWork()
{
CancellationToken ct = GetCancellationToken();
int a;
int b;
const int N = 30;
const int expected = 832040;
while (true)
{
a = 0; b = 1;
for (int i = 1; i < N; i++)
{
int tmp = a + b;
a = b;
b = tmp;
await Task.Delay(1).ConfigureAwait(false);
}
if (ct.IsCancellationRequested)
break;
iterations++;
}
return b == expected ? 42 : 0;
}

public static void StopWork()
{
cts.Cancel();
}

public static string GetIterationsDone()
{
return iterations.ToString();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<WasmCopyAppZipToHelixTestDir Condition="'$(ArchiveTests)' == 'true'">true</WasmCopyAppZipToHelixTestDir>
<WasmMainJSPath>main.js</WasmMainJSPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>embedded</DebugType>
<WasmDebugLevel>1</WasmDebugLevel>
<WasmEnableES6>false</WasmEnableES6>
<WasmBuildNative>true</WasmBuildNative>
<GenerateRunScriptForSample Condition="'$(ArchiveTests)' == 'true'">true</GenerateRunScriptForSample>
<RunScriptCommand>$(ExecXHarnessCmd) wasm test-browser --app=. --browser=Chrome $(XHarnessBrowserPathArg) --html-file=index.html --output-directory=$(XHarnessOutput) -- $(MSBuildProjectName).dll</RunScriptCommand>
<FeatureWasmPerfTracing>true</FeatureWasmPerfTracing>
</PropertyGroup>

<ItemGroup>
<WasmExtraFilesToDeploy Include="index.html" />
<WasmExtraConfig Condition="false" Include="environment_variables" Value='
{
"MONO_LOG_LEVEL": "debug",
"MONO_LOG_MASK": "diagnostics"
}' />
</ItemGroup>

<PropertyGroup>
<_SampleProject>Wasm.Browser.CJS.Sample.csproj</_SampleProject>
</PropertyGroup>


<PropertyGroup>
<RunAnalyzers>true</RunAnalyzers>
</PropertyGroup>

<!-- set the condition to false and you will get a CA1416 error about the call to Thread.Start from a browser-wasm project -->
<ItemGroup Condition="true">
<!-- TODO: some .props file that automates this. Unfortunately just adding a ProjectReference to Microsoft.NET.WebAssembly.Threading.proj doesn't work - it ends up bundling the ref assemblies into the publish directory and breaking the app. -->
<!-- it's a reference assembly, but the project system doesn't know that - include it during compilation, but don't publish it -->
<ProjectReference Include="$(LibrariesProjectRoot)\System.Threading.Thread.WebAssembly.Threading\ref\System.Threading.Thread.WebAssembly.Threading.csproj" IncludeAssets="compile" PrivateAssets="none" ExcludeAssets="runtime" Private="false" />
<ProjectReference Include="$(LibrariesProjectRoot)\System.Threading.ThreadPool.WebAssembly.Threading\ref\System.Threading.ThreadPool.WebAssembly.Threading.csproj" IncludeAssets="compile" PrivateAssets="none" ExcludeAssets="runtime" Private="false" />
<ProjectReference Include="$(LibrariesProjectRoot)\System.Diagnostics.Tracing.WebAssembly.PerfTracing\ref\System.Diagnostics.Tracing.WebAssembly.PerfTracing.csproj" IncludeAssets="compile" PrivateAssets="none" ExcludeAssets="runtime" Private="false" />
</ItemGroup>

<Target Name="RunSample" DependsOnTargets="RunSampleWithBrowser" />
</Project>
20 changes: 20 additions & 0 deletions src/mono/sample/wasm/browser-eventpipe/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<!-- Licensed to the .NET Foundation under one or more agreements. -->
<!-- The .NET Foundation licenses this file to you under the MIT license. -->
<html>

<head>
<title>Sample EventPipe profile session</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
<h3 id="header">Wasm Browser EventPipe profiling Sample</h3>
Answer to the Ultimate Question of Life, the Universe, and Everything is : <span id="out"></span>
kg marked this conversation as resolved.
Show resolved Hide resolved
<script type="text/javascript" src="./dotnet.js"></script>
<script type="text/javascript" src="./dotnet.worker.js"></script>
<script type="text/javascript" src="./main.js"></script>
</body>

</html>
Loading