Skip to content

Commit 9b912f8

Browse files
committed
fix gcdump
1 parent fcb9205 commit 9b912f8

File tree

10 files changed

+459
-41
lines changed

10 files changed

+459
-41
lines changed

src/mono/browser/runtime/diag/client-commands.ts

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33

44
import { SessionId } from "./common";
55

6+
export const advert1 = [65, 68, 86, 82, 95];
7+
export const dotnet_IPC_V1 = [68, 79, 84, 78, 69, 84, 95, 73, 80, 67, 95, 86, 49, 0];
8+
69

710
// this file contains the IPC commands that are sent by client (like dotnet-trace) to the diagnostic server (like Mono VM in the browser)
8-
// just formatting bytes, no sessions here
11+
// just formatting bytes, no sessions management here
912

1013
export function commandStopTracing (sessionID:SessionId) {
1114
return Uint8Array.from([
@@ -14,16 +17,26 @@ export function commandStopTracing (sessionID:SessionId) {
1417
]);
1518
}
1619

17-
export function createGcHeapDumpCommand () {
20+
export function commandResumeRuntime () {
21+
return Uint8Array.from([
22+
...serializeHeader(CommandSetId.Process, ProcessCommandId.ResumeRuntime, computeMessageByteLength(0)),
23+
]);
24+
}
25+
26+
export function commandGcHeapDump () {
1827
return commandCollectTracing2({
19-
circularBufferMB: 256 * 1024 * 1024,
28+
circularBufferMB: 256,
2029
format: 1,
2130
requestRundown: true,
2231
providers: [
2332
{
2433
keywords: [
2534
0x0000_0000,
26-
Keywords.GCHeapSnapshot,
35+
Keywords.GCHeapSnapshot, // 0x1980001
36+
// GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD 0x8000000
37+
// GC_FINALIZATION_KEYWORD 0x1000000
38+
// GC_HEAP_COLLECT_KEYWORD 0x0800000
39+
// GC_KEYWORD 0x0000001
2740
],
2841
logLevel: 5,
2942
provider_name: "Microsoft-Windows-DotNETRuntime",
@@ -33,15 +46,23 @@ export function createGcHeapDumpCommand () {
3346
});
3447
}
3548

36-
const enum CommandSetId {
37-
Reserved = 0,
38-
Dump = 1,
39-
EventPipe = 2,
40-
Profiler = 3,
41-
Process = 4,
42-
43-
// replies
44-
Server = 0xFF,
49+
function commandCollectTracing2 (payload2:PayloadV2) {
50+
const payloadLength = computeCollectTracing2PayloadByteLength(payload2);
51+
const messageLength = computeMessageByteLength(payloadLength);
52+
const message = [
53+
...serializeHeader(CommandSetId.EventPipe, EventPipeCommandId.CollectTracing2, messageLength),
54+
...serializeUint32(payload2.circularBufferMB),
55+
...serializeUint32(payload2.format),
56+
...serializeUint8(payload2.requestRundown ? 1 : 0),
57+
...serializeUint32(payload2.providers.length),
58+
];
59+
for (const provider of payload2.providers) {
60+
message.push(...serializeUint64(provider.keywords));
61+
message.push(...serializeUint32(provider.logLevel));
62+
message.push(...serializeString(provider.provider_name));
63+
message.push(...serializeString(provider.filter_data));
64+
}
65+
return Uint8Array.from(message);
4566
}
4667

4768
const enum Keywords {
@@ -225,6 +246,17 @@ const enum Keywords {
225246
GCHeapSnapshot = 0x1980001
226247
}
227248

249+
export const enum CommandSetId {
250+
Reserved = 0,
251+
Dump = 1,
252+
EventPipe = 2,
253+
Profiler = 3,
254+
Process = 4,
255+
256+
// replies
257+
Server = 0xFF,
258+
}
259+
228260
const enum EventPipeCommandId {
229261
StopTracing= 1,
230262
CollectTracing= 2,
@@ -238,13 +270,13 @@ const enum ProcessCommandId {
238270
ProcessInfo2= 4,
239271
}
240272

241-
const enum ServerCommandId {
273+
export const enum ServerCommandId {
242274
OK= 0,
243275
Error= 0xFF,
244276
}
245277

246278
function serializeMagic () {
247-
return Uint8Array.from("DOTNET_IPC_V1\0", (c) => c.codePointAt(0) ?? 0);
279+
return Uint8Array.from(dotnet_IPC_V1);
248280
}
249281

250282
function serializeUint8 (value:number) {
@@ -321,33 +353,14 @@ function computeCollectTracing2PayloadByteLength (payload2:PayloadV2) {
321353
return len;
322354
}
323355

324-
export function commandCollectTracing2 (payload2:PayloadV2) {
325-
const payloadLength = computeCollectTracing2PayloadByteLength(payload2);
326-
const messageLength = computeMessageByteLength(payloadLength);
327-
const message = [
328-
...serializeHeader(CommandSetId.EventPipe, EventPipeCommandId.CollectTracing2, messageLength),
329-
...serializeUint32(payload2.circularBufferMB),
330-
...serializeUint32(payload2.format),
331-
...serializeUint8(payload2.requestRundown ? 1 : 0),
332-
...serializeUint32(payload2.providers.length),
333-
];
334-
for (const provider of payload2.providers) {
335-
message.push(...serializeUint64(provider.keywords));
336-
message.push(...serializeUint32(provider.logLevel));
337-
message.push(...serializeString(provider.provider_name));
338-
message.push(...serializeString(provider.filter_data));
339-
}
340-
return Uint8Array.from(message);
341-
}
342-
343-
export type ProviderV2 ={
356+
type ProviderV2 ={
344357
keywords: [ 0, Keywords, ],
345358
logLevel: number,
346359
provider_name: string,
347360
filter_data: string|null
348361
}
349362

350-
export type PayloadV2 = {
363+
type PayloadV2 = {
351364
circularBufferMB: number,
352365
format: number,
353366
requestRundown: boolean,
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
import cwraps from "../cwraps";
5+
import { loaderHelpers, Module } from "../globals";
6+
import { VoidPtr } from "../types/emscripten";
7+
8+
let lastScheduledTimeoutId: any = undefined;
9+
10+
// run another cycle of the event loop, which is EP threads on MT runtime
11+
export function diagnostic_server_loop () {
12+
lastScheduledTimeoutId = undefined;
13+
if (loaderHelpers.is_runtime_running()) {
14+
try {
15+
cwraps.mono_background_exec();// give GC chance to run
16+
cwraps.mono_ep_exec();
17+
} catch (ex) {
18+
loaderHelpers.mono_exit(1, ex);
19+
}
20+
}
21+
}
22+
23+
export function schedule_diagnostic_server_loop ():void {
24+
if (!lastScheduledTimeoutId) {
25+
lastScheduledTimeoutId = Module.safeSetTimeout(diagnostic_server_loop, 100);
26+
}
27+
}
28+
29+
export class DiagConnectionBase {
30+
protected messagesToSend: Uint8Array[] = [];
31+
protected messagesReceived: Uint8Array[] = [];
32+
constructor (public client_socket:number) {
33+
}
34+
35+
store (message:Uint8Array):number {
36+
this.messagesToSend.push(message);
37+
return message.byteLength;
38+
}
39+
40+
poll ():number {
41+
return this.messagesReceived.length;
42+
}
43+
44+
recv (buffer:VoidPtr, bytes_to_read:number):number {
45+
if (this.messagesReceived.length === 0) {
46+
return 0;
47+
}
48+
const message = this.messagesReceived[0]!;
49+
const bytes_read = Math.min(message.length, bytes_to_read);
50+
Module.HEAPU8.set(message.subarray(0, bytes_read), buffer as any);
51+
if (bytes_read === message.length) {
52+
this.messagesReceived.shift();
53+
} else {
54+
this.messagesReceived[0] = message.subarray(bytes_read);
55+
}
56+
return bytes_read;
57+
}
58+
}
59+
60+
export interface IDiagConnection {
61+
send (message: Uint8Array):number ;
62+
poll ():number ;
63+
recv (buffer:VoidPtr, bytes_to_read:number):number ;
64+
close ():number ;
65+
}
66+
67+
// [hi,lo]
68+
export type SessionId=[number, number];

0 commit comments

Comments
 (0)