- [Thread records](#thread-records)
- [Thread Created: `thr crt`](#thread-created-thr-crt)
- [Thread Assigned To OS Thread: `thr aos`](#thread-assigned-to-os-thread-thr-aos)
- - [Thread Destroyed: `thr crt`](#thread-destroyed-thr-crt)
+ - [Thread Destroyed: `thr dst`](#thread-destroyed-thr-dst)
- [Thread CPU Usage: `thr cpu`](#thread-cpu-usage-thr-cpu)
- [Execution Engine records](#execution-engine-records)
- [Module Load Finished: `mod ldf`](#module-load-finished-mod-ldf)
| Item | Format | Description |
| -------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------- |
+| `<str>` | `%s` | Text string |
+| `<qtn>` | `"%s"` | Quoted text string |
| `<num>` | `%d` | Decimal number |
| `<hex>` | `0x%x` | Hexadecimal number |
| `<hex32>` | `0x%08X` | 32-bit hexadecimal number |
| `<hex64>` | `0x%016X` | 64-bit hexadecimal number |
-| `<str>` | `%s` | Text string |
-| `<qtn>` | `"%s"` | Quoted text string |
| `<systime>` | `%Y-%m-%d %H:%M:%S.%03f` | System time in format of year, month, day, hour, minute, seconds and milliseconds |
| `<ms>` | `<num>` | Time (in milliseconds) |
| `<us>` | `<num>` | Time (in microseconds) |
| `<pid>` | `<num>` | System process identifier |
| `<ip>` | `<ptr>∣?` | Instruction pointer, `?` if undefined |
| `<hr>` | `<hex32>` | HRESULT |
+| `<token>` | `<hex32>` | .NET Metadata Token |
| `<id>` | `<hex64>` | Profiling API ID |
| `<iid>` | `<hex32>∣?` | Internal CoreProfiler ID, `?` if undefined |
-| `<token>` | `<hex32>` | .NET Metadata Token |
| `<code_info>` | `<start_addr:hex64>:<size:hex>` | Item of Code Info table |
| `<il_map>` | `<ilOffset:hex>:<nativeStart:hex>:<nativeEnd:hex>` | Item of IL mapping table |
-| `<alt_item>` | `<classIid:iid>:<allocCount:num>:<memSize:num>` | Item of GC allocation table |
+| `<alt_item>` | `<classIid:hex>:<allocCount:num>:<memSize:num>` | Item of GC allocation table |
| `<frame>` | `<functionIid:iid>[:<ip>]` | Call stack frame |
-| `<alloc_item>` | `<classIid:iid>:<allocCount:num>:<memSize:num>[:<ip>]` | Item of memory sample |
+| `<alloc_item>` | `<classIid:hex>:<allocCount:num>:<memSize:num>[:<ip>]` | Item of memory sample |
Many records have special attribute named 'Internal ID'. The internal ID
can be used as link to such objects as threads, classes, functions, etc.
* `threadIid` - the Internal ID of the managed thread.
* `osThreadId` - the PID of the operating system thread.
-### Thread Destroyed: `thr crt`
+### Thread Destroyed: `thr dst`
```
-thr crt <threadIid:iid>
+thr dst <threadIid:iid>
```
Notifies that a thread has been destroyed.
storage
sync
trace
+ tracelog
)
add_library(coreprof
trace/cputrace.cpp
trace/executiontrace.cpp
trace/memorytrace.cpp
- tracelog.cpp
+ tracelog/tracelog.cpp
arch/${ARCH_SOURCES_DIR}/asmhelpers.S
arch/${ARCH_SOURCES_DIR}/archhelpers.cpp
)
// Announce names of the special functions.
//
- TRACE().DumpJITFunctionName(*m_pUnmanagedFunctionInfo);
- TRACE().DumpJITFunctionName(*m_pJitFunctionInfo);
+ TRACE().DumpFunctionName(*m_pUnmanagedFunctionInfo);
+ TRACE().DumpFunctionName(*m_pJitFunctionInfo);
//
// Event Mask calculation.
if (!funcInfo.isInfoPrinted)
{
- TRACE().DumpJITFunctionInfo(funcInfo);
- TRACE().DumpJITFunctionName(funcInfo);
+ TRACE().DumpFunctionInfo(funcInfo);
+ TRACE().DumpFunctionName(funcInfo);
funcInfo.isInfoPrinted = true;
}
+++ /dev/null
-/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <system_error>
-#include <utility>
-#include <mutex>
-
-#include <errno.h>
-
-#include <pal.h>
-
-#include "commonconfigconversions.h"
-#include "profilerconfigconversions.h"
-#include "tracelog.h"
-
-class TraceLog final : public ITraceLog
-{
-public:
- TraceLog(StdOutStream_t)
- : m_pStream(PAL_stdout)
- , m_bIsOwner(false)
- {}
-
- TraceLog(StdErrStream_t)
- : m_pStream(PAL_stderr)
- , m_bIsOwner(false)
- {}
-
- TraceLog(FileStream_t, const std::string &filename)
- {
- m_pStream = PAL_fopen(filename.c_str(), "w");
- if (m_pStream == nullptr)
- {
- throw std::system_error(errno, std::system_category(),
- "can't create TraceLog object");
- }
- m_bIsOwner = true;
- }
-
- virtual ~TraceLog()
- {
- if (m_bIsOwner)
- PAL_fclose(m_pStream);
- }
-
- virtual void DumpStartTime(
- const SYSTEMTIME &systime) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "prf stm %04hu-%02hu-%02hu %02hu:%02hu:%02hu.%03hu\n",
- systime.wYear, systime.wMonth, systime.wDay,
- systime.wHour, systime.wMinute, systime.wSecond,
- systime.wMilliseconds
- );
- }
-
- virtual void DumpProfilerConfig(
- const ProfilerConfig &config) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "prf cfg CollectionMethod %s\n",
- convert<LPCSTR>(config.CollectionMethod)
- );
- PAL_fprintf(
- m_pStream, "prf cfg SamplingTimeoutMs %lu\n",
- config.SamplingTimeoutMs
- );
- PAL_fprintf(
- m_pStream, "prf cfg HighGranularityEnabled %s\n",
- convert<LPCSTR>(config.HighGranularityEnabled)
- );
- PAL_fprintf(
- m_pStream, "prf cfg TracingSuspendedOnStart %s\n",
- convert<LPCSTR>(config.TracingSuspendedOnStart)
- );
- PAL_fprintf(
- m_pStream, "prf cfg LineTraceEnabled %s\n",
- convert<LPCSTR>(config.LineTraceEnabled)
- );
- PAL_fprintf(
- m_pStream, "prf cfg CpuTraceProcessEnabled %s\n",
- convert<LPCSTR>(config.CpuTraceProcessEnabled)
- );
- PAL_fprintf(
- m_pStream, "prf cfg CpuTraceThreadEnabled %s\n",
- convert<LPCSTR>(config.CpuTraceThreadEnabled)
- );
- PAL_fprintf(
- m_pStream, "prf cfg CpuTraceTimeoutMs %lu\n",
- config.CpuTraceTimeoutMs
- );
- PAL_fprintf(
- m_pStream, "prf cfg ExecutionTraceEnabled %s\n",
- convert<LPCSTR>(config.ExecutionTraceEnabled)
- );
- PAL_fprintf(
- m_pStream, "prf cfg MemoryTraceEnabled %s\n",
- convert<LPCSTR>(config.MemoryTraceEnabled)
- );
- PAL_fprintf(
- m_pStream, "prf cfg StackTrackingEnabled %s\n",
- convert<LPCSTR>(config.StackTrackingEnabled)
- );
- }
-
- virtual void DumpProfilerTracingPause(
- DWORD ticks) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(m_pStream, "prf tps %d\n", ticks);
- }
-
- virtual void DumpProfilerTracingResume(
- DWORD ticks) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(m_pStream, "prf trs %d\n", ticks);
- }
-
- virtual void DumpProcessTimes(
- DWORD ticksFromStart,
- DWORD64 userTime) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(m_pStream, "prc cpu %d %I64u\n",
- ticksFromStart, userTime);
- }
-
- virtual void DumpAppDomainCreationFinished(
- AppDomainID appDomainId,
- LPCWCH appDomainName,
- ProcessID processId,
- HRESULT hrStatus) override
- {
- if (appDomainName == nullptr)
- appDomainName = W("UNKNOWN");
-
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "apd crf 0x%p 0x%p 0x%08x \"%S\"\n",
- appDomainId, processId, hrStatus, appDomainName
- );
- }
-
- virtual void DumpAssemblyLoadFinished(
- AssemblyID assemblyId,
- LPCWCH assemblyName,
- AppDomainID appDomainId,
- ModuleID moduleId,
- HRESULT hrStatus) override
- {
- if (assemblyName == nullptr)
- assemblyName = W("UNKNOWN");
-
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "asm ldf 0x%p 0x%p 0x%p 0x%08x \"%S\"\n",
- assemblyId, appDomainId, moduleId, hrStatus, assemblyName
- );
- }
-
- virtual void DumpModuleLoadFinished(
- ModuleID moduleId,
- LPCBYTE baseLoadAddress,
- LPCWCH moduleName,
- AssemblyID assemblyId,
- HRESULT hrStatus) override
- {
- if (moduleName == nullptr)
- moduleName = W("UNKNOWN");
-
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "mod ldf 0x%p 0x%p 0x%p 0x%08x \"%S\"\n",
- moduleId, baseLoadAddress, assemblyId, hrStatus, moduleName
- );
- }
-
- virtual void DumpModuleAttachedToAssembly(
- ModuleID moduleId,
- AssemblyID assemblyId) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "mod ata 0x%p 0x%p\n", moduleId, assemblyId
- );
- }
-
- virtual void DumpClassLoadFinished(
- const ClassInfo &info,
- HRESULT hrStatus) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "cls ldf 0x%p 0x%08x 0x%p 0x%08x 0x%08x\n",
- info.id, info.internalId.id, info.moduleId, info.classToken,
- hrStatus
- );
- }
-
- virtual void DumpClassName(
- const ClassInfo &info) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "cls nam 0x%08x \"%S\"\n",
- info.internalId.id, info.fullName.c_str()
- );
- }
-
- virtual void DumpJITCompilationStarted(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- if (threadIid.id == -1)
- {
- PAL_fprintf(
- m_pStream, "jit cms ? %d 0x%p\n",
- ticksFromStart, functionId
- );
- }
- else
- {
- PAL_fprintf(
- m_pStream, "jit cms 0x%08x %d 0x%p\n",
- threadIid.id, ticksFromStart, functionId
- );
- }
- }
-
- virtual void DumpJITCompilationFinished(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId,
- HRESULT hrStatus) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- if (threadIid.id == -1)
- {
- PAL_fprintf(
- m_pStream, "jit cmf ? %d 0x%p 0x%08x\n",
- ticksFromStart, functionId, hrStatus
- );
- }
- else
- {
- PAL_fprintf(
- m_pStream, "jit cmf 0x%08x %d 0x%p 0x%08x\n",
- threadIid.id, ticksFromStart, functionId, hrStatus
- );
- }
- }
-
- virtual void DumpJITCachedFunctionSearchStarted(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- if (threadIid.id == -1)
- {
- PAL_fprintf(
- m_pStream, "jit css ? %d 0x%p\n",
- ticksFromStart, functionId
- );
- }
- else
- {
- PAL_fprintf(
- m_pStream, "jit css 0x%08x %d 0x%p\n",
- threadIid.id, ticksFromStart, functionId
- );
- }
- }
-
- virtual void DumpJITCachedFunctionSearchFinished(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- if (threadIid.id == -1)
- {
- PAL_fprintf(
- m_pStream, "jit csf ? %d 0x%p\n",
- ticksFromStart, functionId
- );
- }
- else
- {
- PAL_fprintf(
- m_pStream, "jit csf 0x%08x %d 0x%p\n",
- threadIid.id, ticksFromStart, functionId
- );
- }
- }
-
- virtual void DumpJITFunctionInfo(
- const FunctionInfo &info) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "fun inf 0x%08x 0x%p 0x%p 0x%p 0x%08x",
- info.internalId.id, info.id, info.classId, info.moduleId,
- info.funcToken
- );
- for (const auto &ci : info.codeInfo)
- {
- PAL_fprintf(m_pStream, " 0x%p:0x%x",
- ci.startAddress, ci.size);
- }
- for (const auto &m : info.ILToNativeMapping)
- {
- PAL_fprintf(m_pStream, " 0x%x:0x%x:0x%x",
- m.ilOffset, m.nativeStartOffset, m.nativeEndOffset);
- }
- PAL_fprintf(m_pStream, "\n");
- }
-
- virtual void DumpJITFunctionName(
- const FunctionInfo &info) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "fun nam 0x%08x \"%S\" \"%S\" \"%S\"\n",
- info.internalId.id, info.fullName.c_str(),
- info.returnType.c_str(), info.signature.c_str()
- );
- }
-
- virtual void DumpThreadCreated(
- ThreadID threadId,
- InternalID threadIid) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(m_pStream, "thr crt 0x%p 0x%08x\n", threadId, threadIid.id);
- }
-
- virtual void DumpThreadDestroyed(
- InternalID threadIid) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(m_pStream, "thr dst 0x%08x\n", threadIid.id);
- }
-
- virtual void DumpThreadAssignedToOSThread(
- InternalID managedThreadIid,
- DWORD osThreadId) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(
- m_pStream, "thr aos 0x%08x %d\n", managedThreadIid.id, osThreadId
- );
- }
-
- virtual void DumpThreadTimes(
- InternalID threadIid,
- DWORD ticksFromStart,
- DWORD64 userTime) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- PAL_fprintf(m_pStream, "thr cpu 0x%08x %d %I64u\n",
- threadIid.id, ticksFromStart, userTime);
- }
-
- virtual void DumpSample(
- InternalID threadIid,
- const EventSummary &summary) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
-
- if (summary.HasStackSample())
- {
- PAL_fprintf(
- m_pStream, "sam str 0x%08x %d %lu",
- threadIid.id, summary.ticks, summary.count
- );
- PAL_fprintf(m_pStream, " %d:%d",
- summary.matchPrefixSize, summary.stackSize);
- if (summary.ipIsChanged)
- {
- PAL_fprintf(m_pStream, summary.ip != 0 ? ":%p" : ":?", summary.ip);
- }
- for (const auto &frame : summary.newFrames)
- {
- PAL_fprintf(m_pStream, frame.ip != 0 ? " 0x%x:%p" : " 0x%x",
- frame.pFuncInfo->internalId.id, frame.ip);
- }
- PAL_fprintf(m_pStream, "\n");
- }
-
- if (summary.HasAllocSample())
- {
- PAL_fprintf(
- m_pStream, "sam mem 0x%08x %d", threadIid.id, summary.ticks
- );
- for (const auto &classIidIpAllocInfo : summary.allocIpTable)
- {
- for (const auto &IpAllocInfo : classIidIpAllocInfo.second)
- {
- PAL_fprintf(
- m_pStream,
- IpAllocInfo.first != 0 ?
- " 0x%x:%Iu:%Iu:%p" : " 0x%x:%Iu:%Iu",
- classIidIpAllocInfo.first,
- IpAllocInfo.second.allocCount,
- IpAllocInfo.second.memSize,
- IpAllocInfo.first
- );
- }
- }
- PAL_fprintf(m_pStream, "\n");
- }
- }
-
- virtual void DumpGarbageCollectionStarted(
- InternalID threadIid,
- DWORD ticksFromStart,
- int cGenerations,
- BOOL generationCollected[],
- COR_PRF_GC_REASON reason) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- if (threadIid.id == -1)
- {
- PAL_fprintf(m_pStream, "gch gcs ? %d", ticksFromStart);
- }
- else
- {
- PAL_fprintf(m_pStream, "gch gcs 0x%08x %d", threadIid.id,
- ticksFromStart);
- }
- switch (reason)
- {
- case COR_PRF_GC_INDUCED:
- PAL_fprintf(m_pStream, " induced");
- break;
- default:
- PAL_fprintf(m_pStream, " ?");
- break;
- }
- PAL_fprintf(m_pStream, cGenerations > 0 ? " " : "");
- for (int i = 0; i < cGenerations; ++i)
- {
- PAL_fprintf(m_pStream, generationCollected[i] ? "t" : "f");
- }
- PAL_fprintf(m_pStream, "\n");
- }
-
- virtual void DumpGarbageCollectionFinished(
- InternalID threadIid,
- DWORD ticksFromStart) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
- if (threadIid.id == -1)
- {
- PAL_fprintf(m_pStream, "gch gcf ? %d", ticksFromStart);
- }
- else
- {
- PAL_fprintf(m_pStream, "gch gcf 0x%08x %d", threadIid.id,
- ticksFromStart);
- }
- PAL_fprintf(m_pStream, "\n");
- }
-
- virtual void DumpGcHeapAllocTable(
- DWORD ticksFromStart,
- const AllocTable &allocInfoByTypes) override
- {
- std::lock_guard<std::mutex> streamLock(m_mStream);
-
- PAL_fprintf(m_pStream, "gch alt %d", ticksFromStart);
- for (const auto &classIidAllocInfo : allocInfoByTypes)
- {
- PAL_fprintf(
- m_pStream,
- " 0x%x:%Iu:%Iu",
- classIidAllocInfo.first,
- classIidAllocInfo.second.allocCount,
- classIidAllocInfo.second.memSize
- );
- }
- PAL_fprintf(m_pStream, "\n");
- }
-
-private:
- PAL_FILE *m_pStream;
- std::mutex m_mStream;
- bool m_bIsOwner;
-};
-
-// static
-ITraceLog *ITraceLog::Create(StdOutStream_t StdOutStream)
-{
- return new TraceLog(StdOutStream);
-}
-
-// static
-ITraceLog *ITraceLog::Create(StdErrStream_t StdErrStream)
-{
- return new TraceLog(StdErrStream);
-}
-
-// static
-ITraceLog *ITraceLog::Create(
- FileStream_t FileStream, const std::string &filename)
-{
- return new TraceLog(FileStream, filename);
-}
+++ /dev/null
-/*
- * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the License);
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an AS IS BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _TRACE_LOG_H_
-#define _TRACE_LOG_H_
-
-#include <windows.h>
-
-#include <cor.h>
-#include <corhdr.h>
-#include <corprof.h>
-
-#include "profilerconfig.h"
-#include "functioninfo.h"
-#include "classinfo.h"
-#include "eventchannel.h"
-
-class ITraceLog
-{
-protected:
- class StdOutStream_t {};
-
- class StdErrStream_t {};
-
- class FileStream_t {};
-
-public:
- static StdOutStream_t StdOutStream;
-
- static StdErrStream_t StdErrStream;
-
- static FileStream_t FileStream;
-
- ITraceLog() = default;
-
- ITraceLog(const ITraceLog&) = delete;
-
- ITraceLog &operator=(const ITraceLog&) = delete;
-
- virtual ~ITraceLog() = default;
-
- static ITraceLog *Create(StdOutStream_t);
-
- static ITraceLog *Create(StdErrStream_t);
-
- static ITraceLog *Create(FileStream_t, const std::string &filename);
-
- // TODO: different methods to dump information.
-
- virtual void DumpStartTime(
- const SYSTEMTIME &systime) = 0;
-
- virtual void DumpProfilerConfig(
- const ProfilerConfig &config) = 0;
-
- virtual void DumpProfilerTracingPause(
- DWORD ticks) = 0;
-
- virtual void DumpProfilerTracingResume(
- DWORD ticks) = 0;
-
- virtual void DumpProcessTimes(
- DWORD ticksFromStart,
- DWORD64 userTime) = 0;
-
- virtual void DumpAppDomainCreationFinished(
- AppDomainID appDomainId,
- LPCWCH appDomainName,
- ProcessID processId,
- HRESULT hrStatus) = 0;
-
- virtual void DumpAssemblyLoadFinished(
- AssemblyID assemblyId,
- LPCWCH assemblyName,
- AppDomainID appDomainId,
- ModuleID moduleId,
- HRESULT hrStatus) = 0;
-
- virtual void DumpModuleLoadFinished(
- ModuleID moduleId,
- LPCBYTE baseLoadAddress,
- LPCWCH moduleName,
- AssemblyID assemblyId,
- HRESULT hrStatus) = 0;
-
- virtual void DumpModuleAttachedToAssembly(
- ModuleID moduleId,
- AssemblyID assemblyId) = 0;
-
- virtual void DumpClassLoadFinished(
- const ClassInfo &info,
- HRESULT hrStatus) = 0;
-
- virtual void DumpClassName(
- const ClassInfo &info) = 0;
-
- virtual void DumpJITCompilationStarted(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId) = 0;
-
- virtual void DumpJITCompilationFinished(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId,
- HRESULT hrStatus) = 0;
-
- virtual void DumpJITCachedFunctionSearchStarted(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId) = 0;
-
- virtual void DumpJITCachedFunctionSearchFinished(
- InternalID threadIid,
- DWORD ticksFromStart,
- FunctionID functionId) = 0;
-
- virtual void DumpJITFunctionInfo(
- const FunctionInfo &info) = 0;
-
- virtual void DumpJITFunctionName(
- const FunctionInfo &info) = 0;
-
- virtual void DumpThreadCreated(
- ThreadID threadId,
- InternalID threadIid) = 0;
-
- virtual void DumpThreadDestroyed(
- InternalID threadIid) = 0;
-
- virtual void DumpThreadAssignedToOSThread(
- InternalID managedThreadIid,
- DWORD osThreadId) = 0;
-
- virtual void DumpThreadTimes(
- InternalID threadIid,
- DWORD ticksFromStart,
- DWORD64 userTime) = 0;
-
- virtual void DumpSample(
- InternalID threadIid,
- const EventSummary &summary) = 0;
-
- virtual void DumpGarbageCollectionStarted(
- InternalID threadIid,
- DWORD ticksFromStart,
- int cGenerations,
- BOOL generationCollected[],
- COR_PRF_GC_REASON reason) = 0;
-
- virtual void DumpGarbageCollectionFinished(
- InternalID threadIid,
- DWORD ticksFromStart) = 0;
-
- virtual void DumpGcHeapAllocTable(
- DWORD ticksFromStart,
- const AllocTable &allocInfoByTypes) = 0;
-};
-
-#endif // _TRACE_LOG_H_
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _TRACE_FMT_H_
+#define _TRACE_FMT_H_
+
+#include <ostream>
+#include <iomanip>
+#include <locale>
+#include <codecvt>
+#include <utility>
+#include <memory>
+#include <mutex>
+
+#include <windows.h>
+
+#include <cor.h>
+#include <corhdr.h>
+#include <corprof.h>
+
+#include "baseinfo.h"
+#include "commonconfigconversions.h"
+#include "profilerconfigconversions.h"
+
+#include "eventchannel.h"
+
+namespace
+{
+
+template<typename T>
+struct wrap
+{
+ T value;
+
+ wrap(T value) : value(value) {}
+
+ operator T() const { return value; }
+};
+
+
+struct hexnum32 : wrap<DWORD> { using wrap::wrap; };
+struct hexnum64 : wrap<DWORD64> { using wrap::wrap; };
+struct hexnum : wrap<DWORD64> { using wrap::wrap; };
+
+std::ostream& operator<<(std::ostream& os, hexnum32 value)
+{
+ char fill = os.fill('0');
+ auto flags = os.flags();
+ os << std::hex << std::uppercase << std::noshowbase
+ << "0x" << std::setw(8) << value.value;
+ os.flags(flags);
+ os.fill(fill);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, hexnum64 value)
+{
+ char fill = os.fill('0');
+ auto flags = os.flags();
+ os << std::hex << std::uppercase << std::noshowbase
+ << "0x" << std::setw(16) << value.value;
+ os.flags(flags);
+ os.fill(fill);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, hexnum value)
+{
+ auto flags = os.flags();
+ os << std::hex << std::nouppercase << std::noshowbase
+ << "0x" << value.value;
+ os.flags(flags);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, LPCWCH str)
+{
+ std::wstring_convert<std::codecvt_utf8<WCHAR>, WCHAR> cvt;
+ return os << cvt.to_bytes(str);
+}
+
+std::ostream& operator<<(std::ostream& os, std::basic_string<WCHAR> str)
+{
+ return os << str.c_str();
+}
+
+std::ostream& operator<<(std::ostream& os, InternalID id)
+{
+ if (id)
+ {
+ // FIXME: unchecked overflow possible.
+ return os << hexnum32(id.id);
+ }
+ else
+ {
+ return os << '?';
+ }
+}
+
+class tracefmt
+{
+private:
+ class record
+ {
+ private:
+ struct deleter
+ {
+ void operator()(std::ostream *stream)
+ {
+ *stream << std::endl;
+ }
+ };
+
+ public:
+ record(const char *str, std::ostream *stream, std::mutex &mutex)
+ : m_lock(mutex)
+ , m_stream(stream)
+ {
+ *m_stream << str;
+ }
+
+ template<typename T>
+ record& str(T&& value)
+ {
+ sep();
+ *m_stream << std::forward<T>(value);
+ return *this;
+ }
+
+ record& str(COR_PRF_GC_REASON reason)
+ {
+ switch (reason)
+ {
+ case COR_PRF_GC_INDUCED:
+ return str("induced");
+ default:
+ return str('?');
+ }
+ }
+
+ template<typename T>
+ record& qtn(T&& value)
+ {
+ sep();
+ *m_stream << '"' << std::forward<T>(value) << '"';
+ return *this;
+ }
+
+ template<typename T>
+ record& num(T&& value)
+ {
+ return str(std::forward<T>(value));
+ }
+
+ record& hex(DWORD64 value)
+ {
+ sep();
+ *m_stream << hexnum(value);
+ return *this;
+ }
+
+ record& hex32(DWORD value)
+ {
+ sep();
+ *m_stream << hexnum32(value);
+ return *this;
+ }
+
+ record& hex64(DWORD64 value)
+ {
+ sep();
+ *m_stream << hexnum64(value);
+ return *this;
+ }
+
+ record& systime(const SYSTEMTIME& systime)
+ {
+ char fill = m_stream->fill('0');
+ sep();
+ *m_stream
+ << std::setw(4) << systime.wYear
+ << '-' << std::setw(2) << systime.wMonth
+ << '-' << std::setw(2) << systime.wDay
+ << ' ' << std::setw(2) << systime.wHour
+ << ':' << std::setw(2) << systime.wMinute
+ << ':' << std::setw(2) << systime.wSecond
+ << '.' << std::setw(3) << systime.wMilliseconds;
+ m_stream->fill(fill);
+ return *this;
+ }
+
+ template<typename T>
+ record& config(T&& value)
+ {
+ sep();
+ *m_stream << convert<LPCSTR>(std::forward<T>(value));
+ return *this;
+ }
+
+ record& config(unsigned long value)
+ {
+ return num(value);
+ }
+
+ record& ms(DWORD ms)
+ {
+ return num(ms);
+ }
+
+ record& us(DWORD64 us)
+ {
+ return num(us);
+ }
+
+ record& ptr(UINT_PTR p)
+ {
+ return hex64(p);
+ }
+
+ record& ptr(const void *p)
+ {
+ return ptr(reinterpret_cast<UINT_PTR>(p));
+ }
+
+ record& pid(DWORD pid)
+ {
+ return num(pid);
+ }
+
+ record& ip(UINT_PTR ip)
+ {
+ if (ip == 0)
+ {
+ sep();
+ *m_stream << '?';
+ return *this;
+ }
+ else
+ {
+ return ptr(ip);
+ }
+ }
+
+ record& hr(HRESULT hr)
+ {
+ return hex32(hr);
+ }
+
+ record& token(mdToken token)
+ {
+ return hex32(token);
+ }
+
+ record& id(UINT_PTR id)
+ {
+ return hex64(id);
+ }
+
+ record& id(InternalID id)
+ {
+ sep();
+ *m_stream << id;
+ return *this;
+ }
+
+ record& code_info(const COR_PRF_CODE_INFO& ci)
+ {
+ return grps(':').hex64(ci.startAddress).hex(ci.size).grpe();
+ }
+
+ record& il_map(const COR_DEBUG_IL_TO_NATIVE_MAP& m)
+ {
+ grps(':');
+ hex(m.ilOffset).hex(m.nativeStartOffset).hex(m.nativeEndOffset);
+ grpe();
+ return *this;
+ }
+
+ record& alt_item(InternalID classIid, AllocInfo allocInfo)
+ {
+ grps(':');
+ hex(classIid).num(allocInfo.allocCount).num(allocInfo.memSize);
+ grpe();
+ return *this;
+ }
+
+ record& frame(Frame f)
+ {
+ grps(':');
+ hex(f.pFuncInfo->internalId);
+ if (f.ip != 0)
+ {
+ ip(f.ip);
+ }
+ grpe();
+ return *this;
+ }
+
+ record& alloc_item(
+ InternalID classIid, AllocInfo allocInfo, UINT_PTR ip = 0)
+ {
+ grps(':');
+ hex(classIid).num(allocInfo.allocCount).num(allocInfo.memSize);
+ if (ip != 0)
+ {
+ this->ip(ip);
+ }
+ grpe();
+ return *this;
+ }
+
+ record& grps()
+ {
+ m_sep = -1;
+ m_grp_state = grp_state::FIRST_IN_GROUP;
+ return *this;
+ }
+
+ record& grps(char sep)
+ {
+ m_sep = sep;
+ m_grp_state = grp_state::FIRST_IN_GROUP;
+ return *this;
+ }
+
+ record& grpe()
+ {
+ m_sep = -1;
+ m_grp_state = grp_state::NOT_IN_GROUP;
+ return *this;
+ }
+
+ record& sep()
+ {
+ switch (m_grp_state)
+ {
+ case grp_state::NOT_IN_GROUP:
+ *m_stream << ' ';
+ break;
+ case grp_state::FIRST_IN_GROUP:
+ m_grp_state = grp_state::IN_GROUP;
+ *m_stream << ' ';
+ break;
+ case grp_state::IN_GROUP:
+ if (m_sep != -1)
+ {
+ *m_stream << static_cast<char>(m_sep);
+ }
+ break;
+ }
+ return *this;
+ }
+
+ private:
+ std::unique_lock<std::mutex> m_lock;
+ std::unique_ptr<std::ostream, deleter> m_stream;
+
+ enum class grp_state {
+ NOT_IN_GROUP,
+ FIRST_IN_GROUP,
+ IN_GROUP
+ };
+ grp_state m_grp_state = grp_state::NOT_IN_GROUP;
+ int m_sep = -1;
+ };
+
+public:
+ explicit tracefmt(std::ostream& stream)
+ : m_stream(&stream)
+ {}
+
+ tracefmt() : tracefmt(std::cout) {}
+
+ tracefmt(const tracefmt&) = delete;
+
+ tracefmt &operator=(const tracefmt&) = delete;
+
+ record log(const char *str)
+ {
+ return record(str, m_stream, m_mutex);
+ }
+
+private:
+ std::ostream *m_stream;
+ std::mutex m_mutex;
+};
+
+}
+
+#endif // _TRACE_FMT_H_
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <system_error>
+#include <iostream>
+#include <fstream>
+
+#include "tracefmt.h"
+#include "tracelog.h"
+
+class TraceLog final : public ITraceLog
+{
+public:
+ TraceLog(StdOutStream_t)
+ : m_stream(std::cout)
+ , m_stream_owner(false)
+ , m_tracefmt(m_stream)
+ {}
+
+ TraceLog(StdErrStream_t)
+ : m_stream(std::cerr)
+ , m_stream_owner(false)
+ , m_tracefmt(m_stream)
+ {}
+
+ TraceLog(FileStream_t, const std::string &filename)
+ : m_stream(*new std::ofstream())
+ , m_stream_owner(true)
+ , m_tracefmt(m_stream)
+ {
+ try
+ {
+ m_stream.exceptions(m_stream.exceptions() | std::ios::failbit);
+ static_cast<std::ofstream&>(m_stream).open(filename);
+ m_stream.exceptions(std::ios::goodbit);
+ }
+ catch (...)
+ {
+ delete &m_stream;
+ if (errno)
+ {
+ throw std::system_error(
+ errno, std::system_category(),
+ "TraceLog::TraceLog(): Can't create trace file"
+ );
+ }
+ else
+ {
+ throw;
+ }
+ }
+ }
+
+ virtual ~TraceLog()
+ {
+ if (m_stream_owner)
+ {
+ delete &m_stream;
+ }
+ }
+
+ //
+ // Profiler records
+ //
+
+ virtual void DumpStartTime(
+ const SYSTEMTIME &systime) override
+ {
+ m_tracefmt.log("prf stm").systime(systime);
+ }
+
+ virtual void DumpProfilerConfig(
+ const ProfilerConfig &config) override
+ {
+ m_tracefmt.log("prf cfg").str("CollectionMethod")
+ .config(config.CollectionMethod);
+ m_tracefmt.log("prf cfg").str("SamplingTimeoutMs")
+ .config(config.SamplingTimeoutMs);
+ m_tracefmt.log("prf cfg").str("HighGranularityEnabled")
+ .config(config.HighGranularityEnabled);
+ m_tracefmt.log("prf cfg").str("TracingSuspendedOnStart")
+ .config(config.TracingSuspendedOnStart);
+ m_tracefmt.log("prf cfg").str("LineTraceEnabled")
+ .config(config.LineTraceEnabled);
+ m_tracefmt.log("prf cfg").str("CpuTraceProcessEnabled")
+ .config(config.CpuTraceProcessEnabled);
+ m_tracefmt.log("prf cfg").str("CpuTraceThreadEnabled")
+ .config(config.CpuTraceThreadEnabled);
+ m_tracefmt.log("prf cfg").str("CpuTraceTimeoutMs")
+ .config(config.CpuTraceTimeoutMs);
+ m_tracefmt.log("prf cfg").str("ExecutionTraceEnabled")
+ .config(config.ExecutionTraceEnabled);
+ m_tracefmt.log("prf cfg").str("MemoryTraceEnabled")
+ .config(config.MemoryTraceEnabled);
+ m_tracefmt.log("prf cfg").str("StackTrackingEnabled")
+ .config(config.StackTrackingEnabled);
+ m_tracefmt.log("prf cfg").str("GcAllocTableTraceEnabled")
+ .config(config.GcAllocTableTraceEnabled);
+ }
+
+ virtual void DumpProfilerTracingPause(
+ DWORD ticks) override
+ {
+ m_tracefmt.log("prf tps").ms(ticks);
+ }
+
+ virtual void DumpProfilerTracingResume(
+ DWORD ticks) override
+ {
+ m_tracefmt.log("prf trs").ms(ticks);
+ }
+
+ //
+ // Process records
+ //
+
+ virtual void DumpProcessTimes(
+ DWORD timestamp,
+ DWORD64 usage) override
+ {
+ m_tracefmt.log("prc cpu").ms(timestamp).us(usage);
+ }
+
+ //
+ // Thread records
+ //
+
+ virtual void DumpThreadCreated(
+ ThreadID threadId,
+ InternalID threadIid) override
+ {
+ m_tracefmt.log("thr crt").id(threadId).id(threadIid);
+ }
+
+ virtual void DumpThreadAssignedToOSThread(
+ InternalID managedThreadIid,
+ DWORD osThreadId) override
+ {
+ m_tracefmt.log("thr aos").id(managedThreadIid).pid(osThreadId);
+ }
+
+ virtual void DumpThreadDestroyed(
+ InternalID threadIid) override
+ {
+ m_tracefmt.log("thr dst").id(threadIid);
+ }
+
+ virtual void DumpThreadTimes(
+ InternalID threadIid,
+ DWORD timestamp,
+ DWORD64 usage) override
+ {
+ m_tracefmt.log("thr cpu").id(threadIid).ms(timestamp).us(usage);
+ }
+
+ //
+ // Execution Engine records
+ //
+
+ virtual void DumpModuleLoadFinished(
+ ModuleID moduleId,
+ LPCBYTE baseLoadAddress,
+ LPCWCH moduleName,
+ AssemblyID assemblyId,
+ HRESULT hrStatus) override
+ {
+ if (moduleName == nullptr)
+ moduleName = W("UNKNOWN");
+
+ m_tracefmt.log("mod ldf")
+ .id(moduleId).ptr(baseLoadAddress).id(assemblyId).hr(hrStatus)
+ .qtn(moduleName);
+ }
+
+ virtual void DumpModuleAttachedToAssembly(
+ ModuleID moduleId,
+ AssemblyID assemblyId) override
+ {
+ m_tracefmt.log("mod ata").id(moduleId).id(assemblyId);
+ }
+
+ virtual void DumpAssemblyLoadFinished(
+ AssemblyID assemblyId,
+ LPCWCH assemblyName,
+ AppDomainID appDomainId,
+ ModuleID moduleId,
+ HRESULT hrStatus) override
+ {
+ if (assemblyName == nullptr)
+ assemblyName = W("UNKNOWN");
+
+ m_tracefmt.log("asm ldf")
+ .id(assemblyId).id(appDomainId).id(moduleId).hr(hrStatus)
+ .qtn(assemblyName);
+ }
+
+ virtual void DumpAppDomainCreationFinished(
+ AppDomainID appDomainId,
+ LPCWCH appDomainName,
+ ProcessID processId,
+ HRESULT hrStatus) override
+ {
+ if (appDomainName == nullptr)
+ appDomainName = W("UNKNOWN");
+
+ m_tracefmt.log("apd crf")
+ .id(appDomainId).id(processId).hr(hrStatus).qtn(appDomainName);
+ }
+
+ //
+ // Class records
+ //
+
+ virtual void DumpClassLoadFinished(
+ const ClassInfo &info,
+ HRESULT hrStatus) override
+ {
+ m_tracefmt.log("cls ldf")
+ .id(info.id).id(info.internalId).id(info.moduleId)
+ .token(info.classToken).hr(hrStatus);
+ }
+
+ virtual void DumpClassName(
+ const ClassInfo &info) override
+ {
+ m_tracefmt.log("cls nam").id(info.internalId).qtn(info.fullName);
+ }
+
+ //
+ // Function records
+ //
+
+ virtual void DumpFunctionInfo(
+ const FunctionInfo &info) override
+ {
+ auto log = m_tracefmt.log("fun inf");
+ log.id(info.internalId).id(info.id).id(info.classId).id(info.moduleId)
+ .token(info.funcToken);
+ for (const auto& ci : info.codeInfo)
+ {
+ log.code_info(ci);
+ }
+ for (const auto& m : info.ILToNativeMapping)
+ {
+ log.il_map(m);
+ }
+ }
+
+ virtual void DumpFunctionName(
+ const FunctionInfo &info) override
+ {
+ m_tracefmt.log("fun nam").id(info.internalId)
+ .qtn(info.fullName).qtn(info.returnType).qtn(info.signature);
+ }
+
+ //
+ // JIT records
+ //
+
+ virtual void DumpJITCompilationStarted(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId) override
+ {
+ m_tracefmt.log("jit cms").id(threadIid).ms(timestamp)
+ .id(functionId);
+ }
+
+ virtual void DumpJITCompilationFinished(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId,
+ HRESULT hrStatus) override
+ {
+ m_tracefmt.log("jit cmf").id(threadIid).ms(timestamp)
+ .id(functionId).hr(hrStatus);
+ }
+
+ virtual void DumpJITCachedFunctionSearchStarted(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId) override
+ {
+ m_tracefmt.log("jit css").id(threadIid).ms(timestamp)
+ .id(functionId);
+ }
+
+ virtual void DumpJITCachedFunctionSearchFinished(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId) override
+ {
+ m_tracefmt.log("jit csf").id(threadIid).ms(timestamp)
+ .id(functionId);
+ }
+
+ //
+ // GC records
+ //
+
+ virtual void DumpGarbageCollectionStarted(
+ InternalID threadIid,
+ DWORD timestamp,
+ int cGenerations,
+ BOOL generationCollected[],
+ COR_PRF_GC_REASON reason) override
+ {
+ auto log = m_tracefmt.log("gch gcs");
+ log.id(threadIid).ms(timestamp).str(reason);
+ log.grps();
+ for (int i = 0; i < cGenerations; ++i)
+ {
+ log.str(generationCollected[i] ? 't' : 'f');
+ }
+ log.grpe();
+ }
+
+ virtual void DumpGarbageCollectionFinished(
+ InternalID threadIid,
+ DWORD timestamp) override
+ {
+ m_tracefmt.log("gch gcf").id(threadIid).ms(timestamp);
+ }
+
+ virtual void DumpGcHeapAllocTable(
+ DWORD timestamp,
+ const AllocTable &allocInfoByTypes) override
+ {
+ auto log = m_tracefmt.log("gch alt");
+ log.ms(timestamp);
+ for (const auto &classIidAllocInfo : allocInfoByTypes)
+ {
+ log.alt_item(classIidAllocInfo.first, classIidAllocInfo.second);
+ }
+ }
+
+ //
+ // Sample records
+ //
+
+ virtual void DumpSample(
+ InternalID threadIid,
+ const EventSummary &summary) override
+ {
+ if (summary.HasStackSample())
+ {
+ auto log = m_tracefmt.log("sam str");
+ log.id(threadIid).ms(summary.ticks).num(summary.count);
+ log.grps(':');
+ log.num(summary.matchPrefixSize).num(summary.stackSize);
+ if (summary.ipIsChanged)
+ {
+ log.ip(summary.ip);
+ }
+ log.grpe();
+ for (const auto &frame : summary.newFrames)
+ {
+ log.frame(frame);
+ }
+ }
+
+ if (summary.HasAllocSample())
+ {
+ auto log = m_tracefmt.log("sam mem");
+ log.id(threadIid).ms(summary.ticks);
+ for (const auto &classIidIpAllocInfo : summary.allocIpTable)
+ {
+ for (const auto &IpAllocInfo : classIidIpAllocInfo.second)
+ {
+ log.alloc_item(classIidIpAllocInfo.first,
+ IpAllocInfo.second, IpAllocInfo.first);
+ }
+ }
+ }
+ }
+
+private:
+ std::ostream& m_stream;
+ bool m_stream_owner;
+ tracefmt m_tracefmt;
+};
+
+// static
+ITraceLog *ITraceLog::Create(StdOutStream_t StdOutStream)
+{
+ return new TraceLog(StdOutStream);
+}
+
+// static
+ITraceLog *ITraceLog::Create(StdErrStream_t StdErrStream)
+{
+ return new TraceLog(StdErrStream);
+}
+
+// static
+ITraceLog *ITraceLog::Create(
+ FileStream_t FileStream, const std::string &filename)
+{
+ return new TraceLog(FileStream, filename);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _TRACE_LOG_H_
+#define _TRACE_LOG_H_
+
+#include <windows.h>
+
+#include <cor.h>
+#include <corhdr.h>
+#include <corprof.h>
+
+#include "profilerconfig.h"
+#include "baseinfo.h"
+#include "functioninfo.h"
+#include "classinfo.h"
+#include "eventchannel.h"
+
+class ITraceLog
+{
+protected:
+ class StdOutStream_t {};
+
+ class StdErrStream_t {};
+
+ class FileStream_t {};
+
+public:
+ static StdOutStream_t StdOutStream;
+
+ static StdErrStream_t StdErrStream;
+
+ static FileStream_t FileStream;
+
+ ITraceLog() = default;
+
+ ITraceLog(const ITraceLog&) = delete;
+
+ ITraceLog &operator=(const ITraceLog&) = delete;
+
+ virtual ~ITraceLog() = default;
+
+ static ITraceLog *Create(StdOutStream_t);
+
+ static ITraceLog *Create(StdErrStream_t);
+
+ static ITraceLog *Create(FileStream_t, const std::string &filename);
+
+ //
+ // Profiler records
+ //
+
+ virtual void DumpStartTime(
+ const SYSTEMTIME &systime) = 0;
+
+ virtual void DumpProfilerConfig(
+ const ProfilerConfig &config) = 0;
+
+ virtual void DumpProfilerTracingPause(
+ DWORD timestamp) = 0;
+
+ virtual void DumpProfilerTracingResume(
+ DWORD timestamp) = 0;
+
+ //
+ // Process records
+ //
+
+ virtual void DumpProcessTimes(
+ DWORD timestamp,
+ DWORD64 usage) = 0;
+
+ //
+ // Thread records
+ //
+
+ virtual void DumpThreadCreated(
+ ThreadID threadId,
+ InternalID threadIid) = 0;
+
+ virtual void DumpThreadAssignedToOSThread(
+ InternalID managedThreadIid,
+ DWORD osThreadId) = 0;
+
+ virtual void DumpThreadDestroyed(
+ InternalID threadIid) = 0;
+
+ virtual void DumpThreadTimes(
+ InternalID threadIid,
+ DWORD timestamp,
+ DWORD64 usage) = 0;
+
+ //
+ // Execution Engine records
+ //
+
+ virtual void DumpModuleLoadFinished(
+ ModuleID moduleId,
+ LPCBYTE baseLoadAddress,
+ LPCWCH moduleName,
+ AssemblyID assemblyId,
+ HRESULT hrStatus) = 0;
+
+ virtual void DumpModuleAttachedToAssembly(
+ ModuleID moduleId,
+ AssemblyID assemblyId) = 0;
+
+ virtual void DumpAssemblyLoadFinished(
+ AssemblyID assemblyId,
+ LPCWCH assemblyName,
+ AppDomainID appDomainId,
+ ModuleID moduleId,
+ HRESULT hrStatus) = 0;
+
+ virtual void DumpAppDomainCreationFinished(
+ AppDomainID appDomainId,
+ LPCWCH appDomainName,
+ ProcessID processId,
+ HRESULT hrStatus) = 0;
+
+ //
+ // Class records
+ //
+
+ virtual void DumpClassLoadFinished(
+ const ClassInfo &info,
+ HRESULT hrStatus) = 0;
+
+ virtual void DumpClassName(
+ const ClassInfo &info) = 0;
+
+ //
+ // Function records
+ //
+
+ virtual void DumpFunctionInfo(
+ const FunctionInfo &info) = 0;
+
+ virtual void DumpFunctionName(
+ const FunctionInfo &info) = 0;
+
+ //
+ // JIT records
+ //
+
+ virtual void DumpJITCompilationStarted(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId) = 0;
+
+ virtual void DumpJITCompilationFinished(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId,
+ HRESULT hrStatus) = 0;
+
+ virtual void DumpJITCachedFunctionSearchStarted(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId) = 0;
+
+ virtual void DumpJITCachedFunctionSearchFinished(
+ InternalID threadIid,
+ DWORD timestamp,
+ FunctionID functionId) = 0;
+
+ //
+ // GC records
+ //
+
+ virtual void DumpGarbageCollectionStarted(
+ InternalID threadIid,
+ DWORD timestamp,
+ int cGenerations,
+ BOOL generationCollected[],
+ COR_PRF_GC_REASON reason) = 0;
+
+ virtual void DumpGarbageCollectionFinished(
+ InternalID threadIid,
+ DWORD timestamp) = 0;
+
+ virtual void DumpGcHeapAllocTable(
+ DWORD timestamp,
+ const AllocTable &allocInfoByTypes) = 0;
+
+ //
+ // Sample records
+ //
+
+ virtual void DumpSample(
+ InternalID threadIid,
+ const EventSummary &summary) = 0;
+};
+
+#endif // _TRACE_LOG_H_