Skip to content

Commit 2fa1092

Browse files
authored
Add profiler to virtual device (#3113)
***NO_CI***
1 parent 82bfee3 commit 2fa1092

File tree

15 files changed

+1539
-17
lines changed

15 files changed

+1539
-17
lines changed

src/CLR/Core/Core.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
// #include <SPOT_hardware_native.h>
2222
#include <nanoCLR_Runtime__HeapBlock.h>
2323

24-
#ifdef _WIN64
2524
#include <inttypes.h>
26-
#endif
2725

2826
#endif // NANOCLR_CORE_H

src/CLR/Diagnostics/Profiler.cpp

Lines changed: 228 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//
1+
//
22
// Copyright (c) .NET Foundation and Contributors
33
// Portions Copyright (c) Microsoft Corporation. All rights reserved.
44
// See LICENSE file in the project root for full license information.
@@ -10,6 +10,11 @@
1010
#include <stdint.h>
1111
#endif
1212

13+
#if defined(VIRTUAL_DEVICE)
14+
#include "nanoCLR_native.h"
15+
#include <format>
16+
#endif
17+
1318
#if defined(NANOCLR_PROFILE_NEW)
1419

1520
CLR_PRF_Profiler g_CLR_PRF_Profiler;
@@ -30,6 +35,11 @@ HRESULT CLR_PRF_Profiler::CreateInstance()
3035

3136
g_CLR_PRF_Profiler.m_initialized = true;
3237

38+
#if defined(VIRTUAL_DEVICE)
39+
// need to do the here to send the memory layout in the first packet
40+
g_CLR_PRF_Profiler.SendMemoryLayout();
41+
#endif
42+
3343
NANOCLR_NOCLEANUP();
3444
}
3545

@@ -55,10 +65,28 @@ void CLR_PRF_Profiler::SendMemoryLayout()
5565

5666
// Send Memory Layout
5767
m_stream->WriteBits(CLR_PRF_CMDS::c_Profiling_Memory_Layout, CLR_PRF_CMDS::Bits::CommandHeader);
68+
69+
#if defined(_WIN64)
70+
PackAndWriteBits((CLR_UINT32)((CLR_UINT64)s_CLR_RT_Heap.m_location >> 32));
71+
#endif
5872
PackAndWriteBits((CLR_UINT32)s_CLR_RT_Heap.m_location);
73+
5974
PackAndWriteBits(s_CLR_RT_Heap.m_size);
6075

6176
Stream_Send();
77+
78+
#if defined(VIRTUAL_DEVICE)
79+
if (g_ProfilerMessageCallback != NULL)
80+
{
81+
std::string memoryLayout = std::format(
82+
"** Memory layout **\r\n start:0x{:X}\r\n end:0x{:X}\r\n size:0x{:X}\r\n",
83+
(unsigned long long)s_CLR_RT_Heap.m_location,
84+
(unsigned long long)s_CLR_RT_Heap.m_location + s_CLR_RT_Heap.m_size,
85+
s_CLR_RT_Heap.m_size);
86+
87+
g_ProfilerMessageCallback(memoryLayout.c_str());
88+
}
89+
#endif
6290
}
6391

6492
HRESULT CLR_PRF_Profiler::DumpHeap()
@@ -507,7 +535,14 @@ void CLR_PRF_Profiler::DumpEndOfRefsList()
507535
void CLR_PRF_Profiler::DumpPointer(void *ptr)
508536
{
509537
NATIVE_PROFILE_CLR_DIAGNOSTICS();
538+
539+
#ifdef _WIN64
540+
CLR_UINT64 ptrVAlue = ((CLR_UINT8 *)ptr - s_CLR_RT_Heap.m_location);
541+
PackAndWriteBits((CLR_UINT32)(ptrVAlue >> 32));
542+
PackAndWriteBits((CLR_UINT32)ptrVAlue);
543+
#else
510544
PackAndWriteBits((CLR_UINT32)((CLR_UINT8 *)ptr - s_CLR_RT_Heap.m_location));
545+
#endif
511546
}
512547

513548
void CLR_PRF_Profiler::DumpSingleReference(CLR_RT_HeapBlock *ptr)
@@ -701,6 +736,29 @@ void CLR_PRF_Profiler::TrackObjectCreation(CLR_RT_HeapBlock *ptr)
701736
CLR_RT_TypeDef_Index idx = ptr->ObjectCls();
702737
PackAndWriteBits(idx);
703738

739+
#if defined(VIRTUAL_DEVICE)
740+
if (g_ProfilerMessageCallback != NULL)
741+
{
742+
// build type name
743+
char fullTypeName[1024] = {0};
744+
char *szBuffer = fullTypeName;
745+
size_t iBuffer = MAXSTRLEN(fullTypeName);
746+
747+
g_CLR_RT_TypeSystem.BuildTypeName(idx, szBuffer, iBuffer);
748+
749+
// compose output message
750+
std::string objectCreation = std::format(
751+
"New {} {} @ 0x{:X} [{:08x}] {} bytes\r\n",
752+
c_CLR_RT_DataTypeLookup[dt].m_name,
753+
fullTypeName,
754+
(CLR_UINT64)((CLR_UINT8 *)ptr),
755+
idx.m_data,
756+
(dataSize * sizeof(struct CLR_RT_HeapBlock)));
757+
758+
g_ProfilerMessageCallback(objectCreation.c_str());
759+
}
760+
#endif
761+
704762
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
705763

706764
#ifdef _WIN64
@@ -731,6 +789,34 @@ void CLR_PRF_Profiler::TrackObjectCreation(CLR_RT_HeapBlock *ptr)
731789
PackAndWriteBits(array->ReflectionDataConst().m_data.m_type);
732790
PackAndWriteBits(array->ReflectionDataConst().m_levels);
733791

792+
#if defined(VIRTUAL_DEVICE)
793+
if (g_ProfilerMessageCallback != NULL)
794+
{
795+
// build type name
796+
char fullTypeName[1024] = {0};
797+
char *szBuffer = fullTypeName;
798+
size_t iBuffer = MAXSTRLEN(fullTypeName);
799+
800+
CLR_RT_TypeDef_Instance arrayTypeDef{};
801+
CLR_UINT32 levels;
802+
arrayTypeDef.InitializeFromReflection(array->ReflectionData(), &levels);
803+
804+
g_CLR_RT_TypeSystem.BuildTypeName(arrayTypeDef, szBuffer, iBuffer);
805+
806+
// compose output message
807+
std::string objectCreation = std::format(
808+
"New {}[] @ 0x{:X} {} bytes [{:08x}] {} elements {} level(s)\r\n",
809+
fullTypeName,
810+
(CLR_UINT64)((CLR_UINT8 *)ptr),
811+
(dataSize * sizeof(struct CLR_RT_HeapBlock)),
812+
elementIdx.m_data,
813+
array->m_numOfElements,
814+
levels);
815+
816+
g_ProfilerMessageCallback(objectCreation.c_str());
817+
}
818+
#endif
819+
734820
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
735821

736822
#ifdef _WIN64
@@ -753,6 +839,17 @@ void CLR_PRF_Profiler::TrackObjectCreation(CLR_RT_HeapBlock *ptr)
753839
#endif
754840
#endif // NANOCLR_TRACE_PROFILER_MESSAGES
755841
}
842+
else
843+
{
844+
// compose output message
845+
std::string objectCreation = std::format(
846+
"New {} @ 0x{:X} {} bytes\r\n",
847+
c_CLR_RT_DataTypeLookup[dt].m_name,
848+
(CLR_UINT64)((CLR_UINT8 *)ptr),
849+
(dataSize * sizeof(struct CLR_RT_HeapBlock)));
850+
851+
g_ProfilerMessageCallback(objectCreation.c_str());
852+
}
756853
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
757854
else
758855
{
@@ -800,6 +897,74 @@ void CLR_PRF_Profiler::TrackObjectDeletion(CLR_RT_HeapBlock *ptr)
800897
m_stream->WriteBits(CLR_PRF_CMDS::c_Profiling_Allocs_Delete, CLR_PRF_CMDS::Bits::CommandHeader);
801898
DumpPointer(ptr);
802899
Stream_Send();
900+
901+
#if defined(VIRTUAL_DEVICE)
902+
if (g_ProfilerMessageCallback != NULL)
903+
{
904+
if (dt == DATATYPE_SZARRAY)
905+
{
906+
CLR_RT_HeapBlock_Array *array = (CLR_RT_HeapBlock_Array *)ptr;
907+
CLR_RT_TypeDef_Index elementIdx = array->ReflectionDataConst().m_data.m_type;
908+
909+
// build type name
910+
char fullTypeName[1024] = {0};
911+
char *szBuffer = fullTypeName;
912+
size_t iBuffer = MAXSTRLEN(fullTypeName);
913+
914+
CLR_RT_TypeDef_Instance arrayTypeDef{};
915+
CLR_UINT32 levels;
916+
arrayTypeDef.InitializeFromReflection(array->ReflectionData(), &levels);
917+
918+
g_CLR_RT_TypeSystem.BuildTypeName(arrayTypeDef, szBuffer, iBuffer);
919+
920+
// compose output message
921+
std::string objectCreation = std::format(
922+
"Delete {}[] @ 0x{:X} {} bytes [{:08x}] {} elements {} level(s)\r\n",
923+
fullTypeName,
924+
(CLR_UINT64)((CLR_UINT8 *)ptr),
925+
(ptr->DataSize() * sizeof(struct CLR_RT_HeapBlock)),
926+
elementIdx.m_data,
927+
array->m_numOfElements,
928+
levels);
929+
930+
g_ProfilerMessageCallback(objectCreation.c_str());
931+
}
932+
else if (dt == DATATYPE_CLASS || dt == DATATYPE_VALUETYPE)
933+
{
934+
CLR_RT_TypeDef_Index idx = ptr->ObjectCls();
935+
936+
// build type name
937+
char fullTypeName[1024] = {0};
938+
char *szBuffer = fullTypeName;
939+
size_t iBuffer = MAXSTRLEN(fullTypeName);
940+
941+
g_CLR_RT_TypeSystem.BuildTypeName(idx, szBuffer, iBuffer);
942+
943+
// compose output message
944+
std::string objectCreation = std::format(
945+
"Delete {} {} @ 0x{:X} [{:08x}] {} bytes\r\n",
946+
c_CLR_RT_DataTypeLookup[dt].m_name,
947+
fullTypeName,
948+
(CLR_UINT64)((CLR_UINT8 *)ptr),
949+
idx.m_data,
950+
(ptr->DataSize() * sizeof(struct CLR_RT_HeapBlock)));
951+
952+
g_ProfilerMessageCallback(objectCreation.c_str());
953+
}
954+
else
955+
{
956+
CLR_UINT16 dataSize = ptr->DataSize();
957+
958+
std::string objectDeletion = std::format(
959+
"Delete {} @ 0x{:X} {} bytes\r\n",
960+
c_CLR_RT_DataTypeLookup[dt].m_name,
961+
(CLR_UINT64)((CLR_UINT8 *)ptr),
962+
(dataSize * sizeof(struct CLR_RT_HeapBlock)));
963+
964+
g_ProfilerMessageCallback(objectDeletion.c_str());
965+
}
966+
}
967+
#endif
803968
}
804969

805970
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
@@ -849,6 +1014,19 @@ void CLR_PRF_Profiler::TrackObjectRelocation()
8491014
DumpPointer(relocBlocks[i].m_end);
8501015
PackAndWriteBits(relocBlocks[i].m_offset);
8511016

1017+
#if defined(VIRTUAL_DEVICE)
1018+
if (g_ProfilerMessageCallback != NULL)
1019+
{
1020+
std::string objectRelocation = std::format(
1021+
"Relocate 0x{:X} to 0x{:X} offset 0x{:X}\r\n",
1022+
(CLR_UINT64)relocBlocks[i].m_start,
1023+
(CLR_UINT64)relocBlocks[i].m_destination,
1024+
relocBlocks[i].m_offset);
1025+
1026+
g_ProfilerMessageCallback(objectRelocation.c_str());
1027+
}
1028+
#endif
1029+
8521030
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
8531031

8541032
#ifdef _WIN64
@@ -888,6 +1066,15 @@ void CLR_PRF_Profiler::RecordGarbageCollectionBegin()
8881066
PackAndWriteBits(g_CLR_RT_GarbageCollector.m_freeBytes);
8891067
Stream_Send();
8901068

1069+
#if defined(VIRTUAL_DEVICE)
1070+
if (g_ProfilerMessageCallback != NULL)
1071+
{
1072+
std::string garbageCollection =
1073+
std::format("GC: Starting run #{}\r\n", g_CLR_RT_GarbageCollector.m_numberOfGarbageCollections);
1074+
g_ProfilerMessageCallback(garbageCollection.c_str());
1075+
}
1076+
#endif
1077+
8911078
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
8921079

8931080
#ifdef _WIN64
@@ -926,6 +1113,18 @@ void CLR_PRF_Profiler::RecordGarbageCollectionEnd()
9261113
PackAndWriteBits(g_CLR_RT_GarbageCollector.m_freeBytes);
9271114
Stream_Send();
9281115

1116+
#if defined(VIRTUAL_DEVICE)
1117+
if (g_ProfilerMessageCallback != NULL)
1118+
{
1119+
std::string garbageCollection = std::format(
1120+
"GC: Finished run #{} - {} bytes free\r\n",
1121+
g_CLR_RT_GarbageCollector.m_numberOfGarbageCollections,
1122+
g_CLR_RT_GarbageCollector.m_freeBytes);
1123+
1124+
g_ProfilerMessageCallback(garbageCollection.c_str());
1125+
}
1126+
#endif
1127+
9291128
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
9301129

9311130
#ifdef _WIN64
@@ -976,6 +1175,16 @@ void CLR_PRF_Profiler::RecordHeapCompactionBegin()
9761175
PackAndWriteBits(g_CLR_RT_GarbageCollector.m_freeBytes);
9771176
Stream_Send();
9781177

1178+
#if defined(VIRTUAL_DEVICE)
1179+
if (g_ProfilerMessageCallback != NULL)
1180+
{
1181+
std::string heapCompaction =
1182+
std::format("Heap compaction: Starting run #{} \r\n", g_CLR_RT_GarbageCollector.m_numberOfCompactions);
1183+
1184+
g_ProfilerMessageCallback(heapCompaction.c_str());
1185+
}
1186+
#endif
1187+
9791188
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
9801189

9811190
#ifdef _WIN64
@@ -1014,6 +1223,17 @@ void CLR_PRF_Profiler::RecordHeapCompactionEnd()
10141223
PackAndWriteBits(g_CLR_RT_GarbageCollector.m_freeBytes);
10151224
Stream_Send();
10161225

1226+
#if defined(VIRTUAL_DEVICE)
1227+
if (g_ProfilerMessageCallback != NULL)
1228+
{
1229+
std::string heapCompaction = std::format(
1230+
"Heap compaction: Finished run #{}\r\n",
1231+
g_CLR_RT_GarbageCollector.m_numberOfGarbageCollections);
1232+
1233+
g_ProfilerMessageCallback(heapCompaction.c_str());
1234+
}
1235+
#endif
1236+
10171237
#ifdef NANOCLR_TRACE_PROFILER_MESSAGES
10181238

10191239
#ifdef _WIN64
@@ -1163,6 +1383,13 @@ HRESULT CLR_PRF_Profiler::Stream_Flush()
11631383
_ASSERTE(false);
11641384
NANOCLR_SET_AND_LEAVE(CLR_E_FAIL);
11651385
}
1386+
1387+
#if defined(VIRTUAL_DEVICE)
1388+
if (g_ProfilerDataCallback != NULL)
1389+
{
1390+
g_ProfilerDataCallback(ptr->m_payload, payloadLength);
1391+
}
1392+
#endif
11661393
}
11671394

11681395
// Don't go past the cursor.

targets/netcore/nanoFramework.nanoCLR.CLI/ExecuteCommandLineOptions.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// See LICENSE file in the project root for full license information.
44
//
55

6-
using CommandLine;
76
using System.Collections.Generic;
7+
using CommandLine;
88

99
namespace nanoFramework.nanoCLR.CLI
1010
{
@@ -65,6 +65,20 @@ public class ExecuteCommandLineOptions : CommonOptions
6565
HelpText = "Trace wire protocol packets.")]
6666
public bool TraceWireProtocol { get; set; }
6767

68+
[Option(
69+
"profiler",
70+
Required = false,
71+
Default = false,
72+
HelpText = "Enable profiler.")]
73+
public bool EnableProfiler { get; set; }
74+
75+
[Option(
76+
"dumpprofilerdata",
77+
Required = false,
78+
Default = false,
79+
HelpText = "Dump profiler raw data to a file.")]
80+
public bool DumpProfilerData { get; set; }
81+
6882
[Option(
6983
'r',
7084
"resolve",

targets/netcore/nanoFramework.nanoCLR.CLI/ExecuteCommandProcessor.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ public static int ProcessVerb(
125125
hostBuilder.UsePortTrace();
126126
}
127127

128+
if (options.EnableProfiler)
129+
{
130+
hostBuilder.EnableProfiler();
131+
}
132+
133+
if(options.DumpProfilerData)
134+
{
135+
hostBuilder.DumpProfilerLogData();
136+
}
137+
128138
hostBuilder.WaitForDebugger = options.WaitForDebugger;
129139
hostBuilder.EnterDebuggerLoopAfterExit = options.EnterDebuggerLoopAfterExit;
130140
hostBuilder.PerformGarbageCollection = options.PerformGarbageCollection;

0 commit comments

Comments
 (0)