mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 09:34:49 +09:00
Add user_events support for the native runtime events (#102523)
This commit is contained in:
parent
796a79fc4c
commit
7934e64492
128 changed files with 30478 additions and 26 deletions
|
@ -115,6 +115,33 @@ Altered source versions must be plainly marked as such, and must not be misrepre
|
|||
|
||||
This notice may not be removed or altered from any source distribution.
|
||||
|
||||
License notice for LinuxTracepoints
|
||||
-----------------------------------
|
||||
|
||||
https://github.com/microsoft/LinuxTracepoints/blob/main/LICENSE
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
|
||||
License notice for Mono
|
||||
-------------------------------
|
||||
|
||||
|
|
20
docs/design/features/user-events.md
Normal file
20
docs/design/features/user-events.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# user_events support in the runtime
|
||||
|
||||
Historically only kernelspace code was allowed to emit events in the Linux kernel, meaning that programs like Perf could only collect system events. Over the years various libraries such as LTTng have been created to allow userspace applications to write to the same trace as the kernel code. The runtime has supported LTTng since very early on, but LTTng has some limitations that are problematic. LTTng requires that all providers and events are known at compile time rather than runtime, and has also recently broken their ABI in a way that is difficult to recover from.
|
||||
|
||||
Starting with kernel version 6.4 the user_events feature is available. user_events allows userspace applications to write events to the same traces as kernel events but does not have the limitations of LTTng. It allows dynamic event creation at runtime and has a stable ABI. For this reason we are adding support for user_events to the runtime in .net 9.
|
||||
|
||||
# Limitations
|
||||
|
||||
Currently the support for user_events is experimental and does not support managed EventSources, it only supports native runtime events such as JIT, GC, class loads, etc.
|
||||
|
||||
# How to enable
|
||||
|
||||
The support for user_events is off by default and can be enabled in one of two ways.
|
||||
|
||||
1. Setting the `DOTNET_EnableUserEvents` environment variable to the value `1`.
|
||||
2. Setting the `System.Diagnostics.Tracing.UserEvents` configuration value to `true` in either your project file or in your `runtimeconfig.json` file.
|
||||
|
||||
# Format
|
||||
|
||||
The events are written with the EventHeader format specified at https://github.com/microsoft/LinuxTracepoints/blob/main/libeventheader-tracepoint/include/eventheader/eventheader.h
|
|
@ -174,6 +174,14 @@ if(FEATURE_EVENT_TRACE)
|
|||
endif(CLR_CMAKE_HOST_UNIX)
|
||||
endif(FEATURE_EVENT_TRACE)
|
||||
|
||||
if(FEATURE_PERFTRACING)
|
||||
if(CLR_CMAKE_TARGET_LINUX)
|
||||
list(APPEND CORECLR_LIBRARIES
|
||||
usereventsprovider
|
||||
)
|
||||
endif(CLR_CMAKE_TARGET_LINUX)
|
||||
endif(FEATURE_PERFTRACING)
|
||||
|
||||
if(FEATURE_MERGE_JIT_AND_ENGINE)
|
||||
set(CLRJIT_STATIC clrjit_static)
|
||||
endif(FEATURE_MERGE_JIT_AND_ENGINE)
|
||||
|
|
|
@ -690,6 +690,11 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeProcNumbers, W("EventPipeProcNumbers"
|
|||
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeOutputStreaming, W("EventPipeOutputStreaming"), 1, "Enable/disable streaming for trace file set in DOTNET_EventPipeOutputPath. Non-zero values enable streaming.")
|
||||
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeEnableStackwalk, W("EventPipeEnableStackwalk"), 1, "Set to 0 to disable collecting stacks for EventPipe events.")
|
||||
|
||||
//
|
||||
// UserEvents
|
||||
//
|
||||
RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableUserEvents, W("EnableUserEvents"), 0, "Enable/disable writing events to user_events. Non-zero values enable tracing.")
|
||||
|
||||
#ifdef FEATURE_AUTO_TRACE
|
||||
RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_AutoTrace_N_Tracers, W("AutoTrace_N_Tracers"), 0, "", CLRConfig::LookupOptions::ParseIntegerAsBase10)
|
||||
RETAIL_CONFIG_STRING_INFO(INTERNAL_AutoTrace_Command, W("AutoTrace_Command"), "")
|
||||
|
|
|
@ -121,12 +121,15 @@ enum EtwGCSettingFlags
|
|||
|
||||
#define ETW_TRACING_INITIALIZED(RegHandle) (TRUE)
|
||||
#define ETW_EVENT_ENABLED(Context, EventDescriptor) (EventPipeHelper::IsEnabled(Context, EventDescriptor.Level, EventDescriptor.Keyword) || \
|
||||
(XplatEventLogger::IsKeywordEnabled(Context, EventDescriptor.Level, EventDescriptor.Keyword)))
|
||||
(XplatEventLogger::IsKeywordEnabled(Context, EventDescriptor.Level, EventDescriptor.Keyword)) || \
|
||||
(UserEventsHelper::IsEnabled(Context, EventDescriptor.Level, EventDescriptor.Keyword)))
|
||||
#define ETW_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::IsEnabled(Context, Level, Keyword) || \
|
||||
(XplatEventLogger::IsKeywordEnabled(Context, Level, Keyword)))
|
||||
(XplatEventLogger::IsKeywordEnabled(Context, Level, Keyword)) || \
|
||||
(UserEventsHelper::IsEnabled(Context, Level, Keyword)))
|
||||
#define ETW_TRACING_ENABLED(Context, EventDescriptor) (EventEnabled##EventDescriptor())
|
||||
#define ETW_TRACING_CATEGORY_ENABLED(Context, Level, Keyword) (EventPipeHelper::IsEnabled(Context, Level, Keyword) || \
|
||||
(XplatEventLogger::IsKeywordEnabled(Context, Level, Keyword)))
|
||||
(XplatEventLogger::IsKeywordEnabled(Context, Level, Keyword)) || \
|
||||
(UserEventsHelper::IsEnabled(Context, Level, Keyword)))
|
||||
#define ETW_PROVIDER_ENABLED(ProviderSymbol) (TRUE)
|
||||
#else //defined(FEATURE_PERFTRACING)
|
||||
#define ETW_INLINE
|
||||
|
@ -651,6 +654,13 @@ public:
|
|||
static bool Enabled();
|
||||
static bool IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONGLONG Keyword);
|
||||
};
|
||||
|
||||
class UserEventsHelper
|
||||
{
|
||||
public:
|
||||
static bool Enabled();
|
||||
static bool IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONGLONG Keyword);
|
||||
};
|
||||
#endif // defined(FEATURE_PERFTRACING)
|
||||
|
||||
#endif // FEATURE_EVENT_TRACE
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
#
|
||||
## Licensed to the .NET Foundation under one or more agreements.
|
||||
## The .NET Foundation licenses this file to you under the MIT license.
|
||||
#
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
from genEventing import *
|
||||
from genLttngProvider import *
|
||||
|
@ -1189,16 +1195,6 @@ def generateEventPipeImplFiles(
|
|||
etwmanifest, eventpipe_directory, extern, target_cpp, runtimeFlavor, inclusionList, exclusionList, dryRun):
|
||||
tree = DOM.parse(etwmanifest)
|
||||
|
||||
# Find the src directory starting with the assumption that
|
||||
# A) It is named 'src'
|
||||
# B) This script lives in it
|
||||
src_dirname = os.path.dirname(__file__)
|
||||
while os.path.basename(src_dirname) != "src":
|
||||
src_dirname = os.path.dirname(src_dirname)
|
||||
|
||||
if os.path.basename(src_dirname) == "":
|
||||
raise IOError("Could not find the Core CLR 'src' directory")
|
||||
|
||||
for providerNode in tree.getElementsByTagName('provider'):
|
||||
providerName = providerNode.getAttribute('name')
|
||||
if not includeProvider(providerName, runtimeFlavor):
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import xml.dom.minidom as DOM
|
||||
from utilities import open_for_update, parseInclusionList
|
||||
|
||||
|
@ -80,6 +81,38 @@ coreCLREventPipeDataTypeMapping={
|
|||
"BYTE" : "BYTE",
|
||||
}
|
||||
|
||||
coreCLRUserEventDataTypeMapping={
|
||||
"win:UInt8" : "TraceLoggingUInt8",
|
||||
"win:UInt16" : "TraceLoggingUInt16",
|
||||
"win:Int32" : "TraceLoggingInt32",
|
||||
"win:UInt32" : "TraceLoggingUInt32",
|
||||
"win:HexInt32" : "TraceLoggingHexInt32",
|
||||
"win:UInt64" : "TraceLoggingUInt64",
|
||||
"win:Int64" : "TraceLoggingInt64",
|
||||
"win:HexInt64" : "TraceLoggingHexInt64",
|
||||
"win:Pointer" : "TraceLoggingPointer",
|
||||
"win:Boolean" : "TraceLoggingBoolean",
|
||||
"win:UnicodeString" : "TraceLoggingString16",
|
||||
"win:GUID" : "TraceLoggingGuid",
|
||||
"win:Binary" : "TraceLoggingBinary",
|
||||
"win:Double" : "TraceLoggingFloat64",
|
||||
"win:AnsiString" : "TraceLoggingString",
|
||||
}
|
||||
|
||||
coreCLRUserEventLogLevelMapping={
|
||||
"win:LogAlways" : "0",
|
||||
"win:Critical" : "1",
|
||||
"win:Error" : "2",
|
||||
"win:Warning" : "3",
|
||||
"win:Informational" : "4",
|
||||
"win:Verbose" : "5",
|
||||
}
|
||||
|
||||
coreCLRUserEventArrayTypeMapping={
|
||||
"win:UInt32" : "TraceLoggingUInt32Array",
|
||||
"win:Binary" : "TraceLoggingUInt8Array",
|
||||
"win:UInt64" : "TraceLoggingUInt64Array",
|
||||
}
|
||||
monoPalDataTypeMapping={
|
||||
#constructed types
|
||||
"win:null" :" ",
|
||||
|
@ -143,6 +176,29 @@ aotEventPipeDataTypeMapping={
|
|||
"WCHAR" : "WCHAR",
|
||||
"BYTE" : "BYTE",
|
||||
}
|
||||
def getUserEventDataTypeMapping(runtimeFlavor):
|
||||
if runtimeFlavor.coreclr:
|
||||
return coreCLRUserEventDataTypeMapping
|
||||
# elif runtimeFlavor.mono:
|
||||
# return monoUserEventDataTypeMapping
|
||||
# elif runtimeFlavor.nativeaot:
|
||||
# return aotUserEventDataTypeMapping
|
||||
|
||||
def getUserEventLogLevelMapping(runtimeFlavor):
|
||||
if runtimeFlavor.coreclr:
|
||||
return coreCLRUserEventLogLevelMapping
|
||||
# elif runtimeFlavor.mono:
|
||||
# return monoUserEventLogLevelMapping
|
||||
# elif runtimeFlavor.nativeaot:
|
||||
# return aotUserEventLogLevelMapping
|
||||
|
||||
def getArrayDataTypeMapping(runtimeFlavor):
|
||||
if runtimeFlavor.coreclr:
|
||||
return coreCLRUserEventArrayTypeMapping
|
||||
# elif runtimeFlavor.mono:
|
||||
# return monoUserEventArrayTypeMapping
|
||||
# elif runtimeFlavor.nativeaot:
|
||||
# return aotUserEventArrayTypeMapping
|
||||
|
||||
def getEventPipeDataTypeMapping(runtimeFlavor):
|
||||
if runtimeFlavor.coreclr:
|
||||
|
@ -160,6 +216,7 @@ def getPalDataTypeMapping(runtimeFlavor):
|
|||
elif runtimeFlavor.nativeaot:
|
||||
return aotPalDataTypeMapping
|
||||
|
||||
|
||||
def includeProvider(providerName, runtimeFlavor):
|
||||
if (runtimeFlavor.coreclr or runtimeFlavor.nativeaot) and providerName == "Microsoft-DotNETRuntimeMonoProfiler":
|
||||
return False
|
||||
|
@ -410,7 +467,7 @@ def parseTemplateNodes(templateNodes):
|
|||
|
||||
return allTemplates
|
||||
|
||||
def generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, write_xplatheader, providerName, inclusionList, generatedFileType):
|
||||
def generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, write_xplatheader, providerName, inclusionList, generatedFileType, user_events):
|
||||
clrallEvents = []
|
||||
for eventNode in eventNodes:
|
||||
eventName = eventNode.getAttribute('symbol')
|
||||
|
@ -439,6 +496,8 @@ def generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, wr
|
|||
|
||||
if runtimeFlavor.coreclr or write_xplatheader or runtimeFlavor.nativeaot:
|
||||
if os.name == 'posix':
|
||||
if user_events and runtimeFlavor.coreclr:
|
||||
clrallEvents.append(" || UserEventsEventEnabled" + eventName + "()")
|
||||
# native AOT does not support non-windows eventing other than via event pipe
|
||||
if not runtimeFlavor.nativeaot:
|
||||
clrallEvents.append(" || (XplatEventLogger" +
|
||||
|
@ -533,6 +592,13 @@ def generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, wr
|
|||
|
||||
fnbody.append("ActivityId,RelatedActivityId);\n")
|
||||
|
||||
if user_events and runtimeFlavor.coreclr:
|
||||
fnbody.append(lindent)
|
||||
fnbody.append("status &= UserEventsWriteEvent" + eventName + "(" + ''.join(line))
|
||||
if len(line) > 0:
|
||||
fnbody.append(",")
|
||||
fnbody.append("ActivityId,RelatedActivityId);\n")
|
||||
|
||||
if runtimeFlavor.coreclr or write_xplatheader:
|
||||
fnbody.append(lindent)
|
||||
fnbody.append("status &= FireEtXplat" + eventName + "(" + ''.join(line) + ");\n")
|
||||
|
@ -667,6 +733,63 @@ def generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern, target_cpp
|
|||
|
||||
return ''.join(clrallEvents)
|
||||
|
||||
def generateClrUserEventsWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list):
|
||||
clrallEvents = []
|
||||
for eventNode in eventNodes:
|
||||
eventName = eventNode.getAttribute('symbol')
|
||||
if not includeEvent(inclusion_list, providerName, eventName):
|
||||
continue
|
||||
|
||||
templateName = eventNode.getAttribute('template')
|
||||
|
||||
#generate UserEventsEventEnabled and UserEventsWriteEvent functions
|
||||
eventenabled = []
|
||||
writeevent = []
|
||||
fnptypeline = []
|
||||
|
||||
if extern:eventenabled.append('extern "C" ')
|
||||
eventenabled.append("%s UserEventsEventEnabled" % (getEventPipeDataTypeMapping(runtimeFlavor)["BOOL"]))
|
||||
eventenabled.append(eventName)
|
||||
eventenabled.append("(void);\n")
|
||||
|
||||
if extern: writeevent.append('extern "C" ')
|
||||
writeevent.append("%s UserEventsWriteEvent" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]))
|
||||
writeevent.append(eventName)
|
||||
writeevent.append("(\n")
|
||||
|
||||
if templateName:
|
||||
template = allTemplates[templateName]
|
||||
fnSig = template.signature
|
||||
|
||||
for params in fnSig.paramlist:
|
||||
fnparam = fnSig.getParam(params)
|
||||
wintypeName = fnparam.winType
|
||||
typewName = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
|
||||
winCount = fnparam.count
|
||||
countw = getPalDataTypeMapping(runtimeFlavor)[winCount]
|
||||
|
||||
if params in template.structs:
|
||||
fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params))
|
||||
|
||||
fnptypeline.append(lindent)
|
||||
fnptypeline.append(typewName)
|
||||
fnptypeline.append(countw)
|
||||
fnptypeline.append(" ")
|
||||
fnptypeline.append(fnparam.name)
|
||||
fnptypeline.append(",\n")
|
||||
|
||||
fnptypeline.append(lindent)
|
||||
fnptypeline.append("%s ActivityId%s\n" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr," if target_cpp else ","))
|
||||
fnptypeline.append(lindent)
|
||||
fnptypeline.append("%s RelatedActivityId%s" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"], " = nullptr" if target_cpp else ""))
|
||||
|
||||
writeevent.extend(fnptypeline)
|
||||
writeevent.append("\n);\n")
|
||||
clrallEvents.extend(eventenabled)
|
||||
clrallEvents.extend(writeevent)
|
||||
|
||||
return ''.join(clrallEvents)
|
||||
|
||||
#generates the dummy header file which is used by the VM as entry point to the logging Functions
|
||||
def generateclrEtwDummy(eventNodes,allTemplates):
|
||||
clretmEvents = []
|
||||
|
@ -749,7 +872,7 @@ def getKeywordsMaskCombined(keywords, keywordsToMask):
|
|||
|
||||
return mask
|
||||
|
||||
def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, tree, clrallevents, inclusion_list, generatedFileType):
|
||||
def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, clrallevents, inclusion_list, generatedFileType, user_events):
|
||||
is_windows = os.name == 'nt'
|
||||
with open_for_update(clrallevents) as Clrallevents:
|
||||
Clrallevents.write(stdprolog)
|
||||
|
@ -759,6 +882,8 @@ def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_
|
|||
if runtimeFlavor.coreclr or write_xplatheader:
|
||||
Clrallevents.write('#include "clrxplatevents.h"\n')
|
||||
Clrallevents.write('#include "clreventpipewriteevents.h"\n')
|
||||
if user_events and runtimeFlavor.coreclr:
|
||||
Clrallevents.write('#include "clrusereventswriteevents.h"\n')
|
||||
elif generatedFileType == "header":
|
||||
Clrallevents.write('#ifndef CLR_ETW_ALL_MAIN_H\n')
|
||||
Clrallevents.write('#define CLR_ETW_ALL_MAIN_H\n\n')
|
||||
|
@ -767,6 +892,8 @@ def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_
|
|||
Clrallevents.write('#include <PalRedhawk.h>\n')
|
||||
Clrallevents.write('#include "clretwallmain.h"\n')
|
||||
Clrallevents.write('#include "clreventpipewriteevents.h"\n')
|
||||
if user_events and runtimeFlavor.coreclr:
|
||||
Clrallevents.write('#include "clrusereventswriteevents.h"\n')
|
||||
Clrallevents.write('#ifdef FEATURE_ETW\n')
|
||||
Clrallevents.write('#include "ClrEtwAll.h"\n')
|
||||
Clrallevents.write('#endif\n')
|
||||
|
@ -787,6 +914,9 @@ def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_
|
|||
else:
|
||||
Clrallevents.write("\n")
|
||||
|
||||
if not is_windows and runtimeFlavor.coreclr:
|
||||
Clrallevents.write(user_events_trace_context_typedef)
|
||||
|
||||
if not is_windows and not write_xplatheader and not runtimeFlavor.nativeaot:
|
||||
Clrallevents.write(eventpipe_trace_context_typedef) # define EVENTPIPE_TRACE_CONTEXT
|
||||
Clrallevents.write("\n")
|
||||
|
@ -799,7 +929,7 @@ def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_
|
|||
eventNodes = providerNode.getElementsByTagName('event')
|
||||
|
||||
#vm header:
|
||||
Clrallevents.write(generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, write_xplatheader, providerName, inclusion_list, generatedFileType))
|
||||
Clrallevents.write(generateClrallEvents(eventNodes, allTemplates, target_cpp, runtimeFlavor, write_xplatheader, providerName, inclusion_list, generatedFileType, user_events))
|
||||
|
||||
providerName = providerNode.getAttribute('name')
|
||||
providerSymbol = providerNode.getAttribute('symbol')
|
||||
|
@ -814,7 +944,7 @@ def updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_
|
|||
if generatedFileType == "header":
|
||||
Clrallevents.write("#endif // __CLR_ETW_ALL_MAIN_H__\n")
|
||||
|
||||
def generatePlatformIndependentFiles(sClrEtwAllMan, incDir, etmDummyFile, extern, write_xplatheader, target_cpp, runtimeFlavor, inclusion_list):
|
||||
def generatePlatformIndependentFiles(sClrEtwAllMan, incDir, etmDummyFile, extern, write_xplatheader, target_cpp, runtimeFlavor, inclusion_list, user_events):
|
||||
|
||||
generateEtmDummyHeader(sClrEtwAllMan,etmDummyFile)
|
||||
tree = DOM.parse(sClrEtwAllMan)
|
||||
|
@ -838,6 +968,16 @@ typedef struct _EVENTPIPE_TRACE_CONTEXT
|
|||
#endif // EVENTPIPE_TRACE_CONTEXT_DEF
|
||||
""" % (getEventPipeDataTypeMapping(runtimeFlavor)["WCHAR"], getEventPipeDataTypeMapping(runtimeFlavor)["UCHAR"], getEventPipeDataTypeMapping(runtimeFlavor)["ULONGLONG"])
|
||||
|
||||
user_events_trace_context_typedef = """
|
||||
#if !defined(USER_EVENTS_TRACE_CONTEXT_DEF)
|
||||
#define USER_EVENTS_TRACE_CONTEXT_DEF
|
||||
typedef struct _USER_EVENTS_TRACE_CONTEXT
|
||||
{
|
||||
UCHAR id;
|
||||
} USER_EVENTS_TRACE_CONTEXT, *PUSER_EVENTS_TRACE_CONTEXT;
|
||||
#endif // USER_EVENTS_TRACE_CONTEXT_DEF
|
||||
"""
|
||||
|
||||
lttng_trace_context_typedef = """
|
||||
#if !defined(LTTNG_TRACE_CONTEXT_DEF)
|
||||
#define LTTNG_TRACE_CONTEXT_DEF
|
||||
|
@ -869,6 +1009,7 @@ typedef struct _DOTNET_TRACE_CONTEXT
|
|||
{
|
||||
EVENTPIPE_TRACE_CONTEXT EventPipeProvider;
|
||||
PLTTNG_TRACE_CONTEXT LttngProvider;
|
||||
USER_EVENTS_TRACE_CONTEXT UserEventsProvider;
|
||||
} DOTNET_TRACE_CONTEXT, *PDOTNET_TRACE_CONTEXT;
|
||||
#endif // DOTNET_TRACE_CONTEXT_DEF
|
||||
"""
|
||||
|
@ -878,11 +1019,11 @@ typedef struct _DOTNET_TRACE_CONTEXT
|
|||
# Write the main source(s) for FireETW* functions
|
||||
# nativeaot requires header and source file to be separated as well as a noop implementation
|
||||
if runtimeFlavor.nativeaot:
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, tree, os.path.join(incDir, "clretwallmain.cpp"), inclusion_list, "source-impl")
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, tree, os.path.join(incDir, "clretwallmain.h"), inclusion_list, "header")
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, tree, os.path.join(incDir, "disabledclretwallmain.cpp"), inclusion_list, "source-impl-noop")
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "clretwallmain.cpp"), inclusion_list, "source-impl", user_events)
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "clretwallmain.h"), inclusion_list, "header", user_events)
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "disabledclretwallmain.cpp"), inclusion_list, "source-impl-noop", user_events)
|
||||
else:
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, tree, os.path.join(incDir, "clretwallmain.h"), inclusion_list, "header-impl")
|
||||
updateclreventsfile(write_xplatheader, target_cpp, runtimeFlavor, eventpipe_trace_context_typedef, dotnet_trace_context_typedef_windows, user_events_trace_context_typedef, tree, os.path.join(incDir, "clretwallmain.h"), inclusion_list, "header-impl", user_events)
|
||||
|
||||
if write_xplatheader:
|
||||
clrproviders = os.path.join(incDir, "clrproviders.h")
|
||||
|
@ -897,6 +1038,7 @@ typedef struct _EVENT_DESCRIPTOR
|
|||
if not is_windows and not runtimeFlavor.nativeaot:
|
||||
Clrproviders.write(eventpipe_trace_context_typedef) # define EVENTPIPE_TRACE_CONTEXT
|
||||
Clrproviders.write(lttng_trace_context_typedef) # define LTTNG_TRACE_CONTEXT
|
||||
Clrproviders.write(user_events_trace_context_typedef)
|
||||
Clrproviders.write(dotnet_trace_context_typedef_unix + "\n")
|
||||
|
||||
allProviders = []
|
||||
|
@ -955,6 +1097,20 @@ typedef struct _EVENT_DESCRIPTOR
|
|||
#eventpipe: create clreventpipewriteevents.h
|
||||
Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list) + "\n")
|
||||
|
||||
if user_events and runtimeFlavor.coreclr:
|
||||
clrusereventswriteeventsPath = os.path.join(incDir, "clrusereventswriteevents.h")
|
||||
with open_for_update(clrusereventswriteeventsPath) as clrusereventswriteevents:
|
||||
clrusereventswriteevents.write(stdprolog + "\n")
|
||||
|
||||
for providerNode in tree.getElementsByTagName('provider'):
|
||||
providerName = providerNode.getAttribute('name')
|
||||
templateNodes = providerNode.getElementsByTagName('template')
|
||||
allTemplates = parseTemplateNodes(templateNodes)
|
||||
eventNodes = providerNode.getElementsByTagName('event')
|
||||
|
||||
#user_events: create clrusereventswriteevents.h
|
||||
clrusereventswriteevents.write(generateClrUserEventsWriteEvents(eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, providerName, inclusion_list) + "\n")
|
||||
|
||||
# Write secondary headers for FireEtXplat* and EventPipe* functions
|
||||
if write_xplatheader:
|
||||
clrxplatevents = os.path.join(incDir, "clrxplatevents.h")
|
||||
|
@ -992,6 +1148,8 @@ def main(argv):
|
|||
help='if specified, will not generated extern function stub headers' )
|
||||
required.add_argument('--noxplatheader', action='store_true',
|
||||
help='if specified, will not write a generated cross-platform header' )
|
||||
required.add_argument('--userevents', action='store_true',
|
||||
help='if specified, will emit support for user_events' )
|
||||
args, unknown = parser.parse_known_args(argv)
|
||||
if unknown:
|
||||
print('Unknown argument(s): ', ', '.join(unknown))
|
||||
|
@ -1004,6 +1162,7 @@ def main(argv):
|
|||
runtimeFlavor = RuntimeFlavor(args.runtimeflavor)
|
||||
extern = not args.nonextern
|
||||
write_xplatheader = not args.noxplatheader
|
||||
user_events = args.userevents
|
||||
|
||||
target_cpp = True
|
||||
if runtimeFlavor.mono:
|
||||
|
@ -1013,7 +1172,7 @@ def main(argv):
|
|||
|
||||
inclusion_list = parseInclusionList(inclusion_filename)
|
||||
|
||||
generatePlatformIndependentFiles(sClrEtwAllMan, incdir, etmDummyFile, extern, write_xplatheader, target_cpp, runtimeFlavor, inclusion_list)
|
||||
generatePlatformIndependentFiles(sClrEtwAllMan, incdir, etmDummyFile, extern, write_xplatheader, target_cpp, runtimeFlavor, inclusion_list, user_events)
|
||||
|
||||
if __name__ == '__main__':
|
||||
return_code = main(sys.argv[1:])
|
||||
|
|
501
src/coreclr/scripts/genUserEvents.py
Normal file
501
src/coreclr/scripts/genUserEvents.py
Normal file
|
@ -0,0 +1,501 @@
|
|||
#
|
||||
## Licensed to the .NET Foundation under one or more agreements.
|
||||
## The .NET Foundation licenses this file to you under the MIT license.
|
||||
#
|
||||
# This file generates support for the .net runtime to emit events via the
|
||||
# EventHeader format specified at https://github.com/microsoft/LinuxTracepoints/blob/main/libeventheader-tracepoint/include/eventheader/eventheader.h
|
||||
#
|
||||
# It uses the LinuxTracepoints library included in this repo at src/native/External/LinuxTracepoints.
|
||||
#
|
||||
# The support is accomplished with the following:
|
||||
#
|
||||
# In clretwall.h all methods have user_events specific code added like the following.
|
||||
# inline BOOL EventEnabledGCStart(void) {return EventPipeEventEnabledGCStart() || UserEventsEventEnabledGCStart() || (XplatEventLogger::IsEventLoggingEnabled() && EventXplatEnabledGCStart());}
|
||||
#
|
||||
# inline ULONG FireEtwGCStart(
|
||||
# const unsigned int Count,
|
||||
# const unsigned int Reason,
|
||||
# LPCGUID ActivityId = nullptr,
|
||||
# LPCGUID RelatedActivityId = nullptr
|
||||
# )
|
||||
# {
|
||||
# ULONG status = EventPipeWriteEventGCStart(Count,Reason,ActivityId,RelatedActivityId);
|
||||
# status &= UserEventsWriteEventGCStart(Count,Reason,ActivityId,RelatedActivityId);
|
||||
# status &= FireEtXplatGCStart(Count,Reason);
|
||||
# return status;
|
||||
# }
|
||||
#
|
||||
# The clretwall.h file is generate in the genEventing.py script.
|
||||
#
|
||||
# This script outputs one file for each provider, with each event on the provider having a method for
|
||||
# checking if the event is enabled and a method for firing the event.
|
||||
# BOOL UserEventsEventEnabledGCStart(void)
|
||||
# {
|
||||
# return IsUserEventsEnabled() && TraceLoggingProviderEnabled(DotNETRuntime, 4, 1);
|
||||
# }
|
||||
#
|
||||
# extern "C" ULONG UserEventsWriteEventGCStart(
|
||||
# const unsigned int Count,
|
||||
# const unsigned int Reason,
|
||||
# LPCGUID ActivityId,
|
||||
# LPCGUID RelatedActivityId)
|
||||
# {
|
||||
# if (!UserEventsEventEnabledGCStart())
|
||||
# return ERROR_SUCCESS;
|
||||
# TraceLoggingWriteActivity(DotNETRuntime, "GCStart", ActivityId, RelatedActivityId, TraceLoggingLevel(4), TraceLoggingKeyword(1),
|
||||
# TraceLoggingUInt32(Count),
|
||||
# TraceLoggingUInt32(Reason)
|
||||
# );
|
||||
# return ERROR_SUCCESS;
|
||||
# }
|
||||
#
|
||||
# We also generate a function to check if a given keyword/level is enabled for each provider:
|
||||
#
|
||||
# bool DotNETRuntimeEnabledByKeyword(uint8_t level, uint64_t keyword)
|
||||
# {
|
||||
# if (!IsUserEventsEnabled())
|
||||
# {
|
||||
# return false;
|
||||
# }
|
||||
#
|
||||
# switch (level)
|
||||
# {
|
||||
# case (0):
|
||||
# if (keyword == 0)
|
||||
# {
|
||||
# if (TraceLoggingProviderEnabled(DotNETRuntimeStress, 0, 0)) return true;
|
||||
# }
|
||||
# // Continue for every eligible keyword
|
||||
# break;
|
||||
# case (1):
|
||||
# if (keyword == 0)
|
||||
# {
|
||||
# if (TraceLoggingProviderEnabled(DotNETRuntimeStress, 1, 0)) return true;
|
||||
# }
|
||||
# // Continue for every eligible keyword
|
||||
# break;
|
||||
# case (2):
|
||||
# if (keyword == 0)
|
||||
# {
|
||||
# if (TraceLoggingProviderEnabled(DotNETRuntimeStress, 2, 0)) return true;
|
||||
# }
|
||||
# // Continue for every eligible keyword
|
||||
# break;
|
||||
# case (3):
|
||||
# if (keyword == 0)
|
||||
# {
|
||||
# if (TraceLoggingProviderEnabled(DotNETRuntimeStress, 3, 0)) return true;
|
||||
# }
|
||||
# // Continue for every eligible keyword
|
||||
# break;
|
||||
# case (4):
|
||||
# if (keyword == 0)
|
||||
# {
|
||||
# if (TraceLoggingProviderEnabled(DotNETRuntimeStress, 4, 0)) return true;
|
||||
# }
|
||||
# // Continue for every eligible keyword
|
||||
# break;
|
||||
# case (5):
|
||||
# if (keyword == 0)
|
||||
# {
|
||||
# if (TraceLoggingProviderEnabled(DotNETRuntimeStress, 5, 0)) return true;
|
||||
# }
|
||||
# // Continue for every eligible keyword
|
||||
# break;
|
||||
#
|
||||
# }
|
||||
# return false;
|
||||
# }
|
||||
|
||||
from __future__ import print_function
|
||||
from genEventing import *
|
||||
import os
|
||||
import xml.dom.minidom as DOM
|
||||
from utilities import open_for_update, parseExclusionList, parseInclusionList
|
||||
|
||||
stdprolog_cpp = """// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
/******************************************************************
|
||||
|
||||
DO NOT MODIFY. AUTOGENERATED FILE.
|
||||
This file is generated using the logic from <root>/src/scripts/genUserEvent.py
|
||||
|
||||
******************************************************************/
|
||||
|
||||
"""
|
||||
|
||||
stdprolog_cmake = """#
|
||||
#
|
||||
#******************************************************************
|
||||
|
||||
#DO NOT MODIFY. AUTOGENERATED FILE.
|
||||
#This file is generated using the logic from <root>/src/scripts/genUserEvent.py
|
||||
|
||||
#******************************************************************
|
||||
|
||||
"""
|
||||
|
||||
userevent_dirname = "userevents"
|
||||
|
||||
def generateMethodSignatureEnabled(eventName, runtimeFlavor, providerName, eventLevel, eventKeywords):
|
||||
return "%s UserEventsEventEnabled%s(void)" % (getEventPipeDataTypeMapping(runtimeFlavor)["BOOL"], eventName,)#mayhbe add in genEventing.py
|
||||
|
||||
def generateMethodSignatureWrite(eventName, template, extern, runtimeFlavor):
|
||||
sig_pieces = []
|
||||
|
||||
if extern: sig_pieces.append('extern "C" ')
|
||||
sig_pieces.append("%s UserEventsWriteEvent" % (getEventPipeDataTypeMapping(runtimeFlavor)["ULONG"]))
|
||||
sig_pieces.append(eventName)
|
||||
sig_pieces.append("(")
|
||||
|
||||
if template:
|
||||
sig_pieces.append("\n")
|
||||
fnSig = template.signature
|
||||
for paramName in fnSig.paramlist:
|
||||
fnparam = fnSig.getParam(paramName)
|
||||
wintypeName = fnparam.winType
|
||||
typewName = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
|
||||
winCount = fnparam.count
|
||||
countw = getPalDataTypeMapping(runtimeFlavor)[winCount]
|
||||
|
||||
if paramName in template.structs:
|
||||
sig_pieces.append(
|
||||
"%sint %s_ElementSize,\n" %
|
||||
(lindent, paramName))
|
||||
|
||||
sig_pieces.append(lindent)
|
||||
sig_pieces.append(typewName)
|
||||
if countw != " ":
|
||||
sig_pieces.append(countw)
|
||||
|
||||
sig_pieces.append(" ")
|
||||
sig_pieces.append(fnparam.name)
|
||||
sig_pieces.append(",\n")
|
||||
|
||||
sig_pieces.append(lindent)
|
||||
sig_pieces.append("%s ActivityId,\n" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"]))
|
||||
sig_pieces.append(lindent)
|
||||
sig_pieces.append("%s RelatedActivityId" % (getEventPipeDataTypeMapping(runtimeFlavor)["LPCGUID"]))
|
||||
sig_pieces.append(")")
|
||||
return ''.join(sig_pieces)
|
||||
def formatGuid(providerGuid):
|
||||
providerGuid = providerGuid[1:-1]
|
||||
guidParts = providerGuid.split('-')
|
||||
lastPart = guidParts[-1]
|
||||
guidParts = guidParts[:-1]
|
||||
nextLastPart = guidParts[-1]
|
||||
guidParts = guidParts[:-1]
|
||||
nextLastPartSplit = [nextLastPart[i:i+2] for i in range(0, len(nextLastPart), 2)]
|
||||
lastPartSplit = [lastPart[i:i+2] for i in range(0, len(lastPart), 2)]
|
||||
guidParts.extend(nextLastPartSplit)
|
||||
guidParts.extend(lastPartSplit)
|
||||
guidParts[0] = "0x" + guidParts[0]
|
||||
return ", 0x".join(guidParts)
|
||||
|
||||
def generateClrUserEventWriteEventsImpl(providerNode, providerPrettyName, providerName, eventNodes, allTemplates, extern, target_cpp, runtimeFlavor, thisProviderKeywords, inclusionList, exclusionList):
|
||||
WriteEventImpl = []
|
||||
# User Event Provider Declaration
|
||||
providerGuid = formatGuid(providerNode.getAttribute('guid'))
|
||||
WriteEventImpl.append("TRACELOGGING_DEFINE_PROVIDER(%s, \"%s\", (%s));\n\n" % (providerPrettyName, providerName, providerGuid))
|
||||
WriteEventImpl.append("""void Init%s()
|
||||
{
|
||||
int err = TraceLoggingRegister(%s);
|
||||
_ASSERTE(err == 0);
|
||||
}\n\n""" % (providerPrettyName, providerPrettyName))
|
||||
WriteEventImpl.append("""bool %sEnabledByKeyword(uint8_t level, uint64_t keyword)
|
||||
{
|
||||
if (!IsUserEventsEnabled())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (level)
|
||||
{\n""" % (providerPrettyName))
|
||||
|
||||
for level in range(6):
|
||||
# first case, 0 keyword
|
||||
WriteEventImpl.append(" case (%s):\n" % (level))
|
||||
WriteEventImpl.append(" if (keyword == 0)\n")
|
||||
WriteEventImpl.append(" {\n")
|
||||
WriteEventImpl.append(" if (TraceLoggingProviderEnabled(%s, %s, 0)) return true;\n" % (providerPrettyName, level))
|
||||
WriteEventImpl.append(" }\n")
|
||||
|
||||
# rest of keywords, only generate ones we know about via keywordMap in order to not define
|
||||
# bogus events. (TraceLoggingProviderEnable registers the event to check if it is set or not)
|
||||
for keyword in thisProviderKeywords:
|
||||
WriteEventImpl.append(" if (keyword == 0x%x)\n" % (keyword))
|
||||
WriteEventImpl.append(" {\n")
|
||||
WriteEventImpl.append(" if (TraceLoggingProviderEnabled(%s, %s, 0x%x)) return true;\n" % (providerPrettyName, level, keyword))
|
||||
WriteEventImpl.append(" }\n")
|
||||
|
||||
WriteEventImpl.append(" break;\n")
|
||||
|
||||
WriteEventImpl.append("""
|
||||
}
|
||||
return false;
|
||||
}\n\n""")
|
||||
#&& TraceLoggingProviderEnabled(%s, level, keyword);
|
||||
|
||||
for eventNode in eventNodes:
|
||||
eventName = eventNode.getAttribute('symbol')
|
||||
templateName = eventNode.getAttribute('template')
|
||||
eventLevel = eventNode.getAttribute('level')
|
||||
eventKeywords = eventNode.getAttribute('keywords')
|
||||
eventKeywordsMask = generateEventKeywords(eventKeywords)
|
||||
|
||||
|
||||
if not includeEvent(inclusionList, providerName, eventName):
|
||||
continue
|
||||
|
||||
eventIsEnabledFunc = "TraceLoggingProviderEnabled"
|
||||
|
||||
# generate UserEventEnabled function
|
||||
eventEnabledImpl = generateMethodSignatureEnabled(eventName, runtimeFlavor, providerName, eventLevel, eventKeywords) + """
|
||||
{
|
||||
return IsUserEventsEnabled() && %s(%s, %s, %s);
|
||||
}
|
||||
|
||||
""" % (eventIsEnabledFunc, providerPrettyName, getUserEventLogLevelMapping(runtimeFlavor)[eventLevel], eventKeywordsMask)
|
||||
WriteEventImpl.append(eventEnabledImpl)
|
||||
|
||||
# generate UserEventWriteEvent function
|
||||
fnptype = []
|
||||
|
||||
if templateName:
|
||||
template = allTemplates[templateName]
|
||||
else:
|
||||
template = None
|
||||
|
||||
fnptype.append(generateMethodSignatureWrite(eventName, template, extern, runtimeFlavor))
|
||||
fnptype.append("\n{\n")
|
||||
checking = """ if (!UserEventsEventEnabled%s())
|
||||
return ERROR_SUCCESS;
|
||||
""" % (eventName)
|
||||
|
||||
fnptype.append(checking)
|
||||
|
||||
WriteEventImpl.extend(fnptype)
|
||||
|
||||
if template:
|
||||
body = generateWriteEventBody(template, providerPrettyName, eventName, runtimeFlavor, eventLevel, eventKeywordsMask)
|
||||
WriteEventImpl.append(body)
|
||||
WriteEventImpl.append("}\n\n")
|
||||
else:
|
||||
if runtimeFlavor.coreclr:
|
||||
WriteEventImpl.append(
|
||||
" TraceLoggingWriteActivity(%s, \"%s\"" %(providerPrettyName, eventName) +
|
||||
", ActivityId, RelatedActivityId);\n")
|
||||
WriteEventImpl.append(" return ERROR_SUCCESS;\n")
|
||||
WriteEventImpl.append("}\n\n")
|
||||
elif (runtimeFlavor.mono or runtimeFlavor.nativeaot):
|
||||
WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n")
|
||||
return ''.join(WriteEventImpl)
|
||||
|
||||
def generateWriteEventBody(template, providerPrettyName, eventName, runtimeFlavor, eventLevel, eventKeywordsMask):
|
||||
#each of the if/else in this function is a different type of template, or a template containing specific args
|
||||
fnSig = template.signature
|
||||
pack_list = []
|
||||
#need the providerNode to get the first arg for TraceLoggingWrite
|
||||
pack_list.append(" TraceLoggingWriteActivity(%s, \"%s\", ActivityId, RelatedActivityId, TraceLoggingLevel(%s), TraceLoggingKeyword(%s)" % (providerPrettyName, eventName, getUserEventLogLevelMapping(runtimeFlavor)[eventLevel], eventKeywordsMask))
|
||||
|
||||
for paramName in fnSig.paramlist:
|
||||
parameter = fnSig.getParam(paramName)
|
||||
if paramName in template.structs:
|
||||
size = "(int)%s_ElementSize * (int)%s" % (
|
||||
paramName, parameter.prop)
|
||||
pack_list.append(" TraceLoggingBinary(%s, %s)" % (parameter, size))
|
||||
elif paramName in template.arrays:
|
||||
size = "sizeof(%s) * (int)%s" % (
|
||||
getArrayDataTypeMapping(runtimeFlavor)[parameter.winType],
|
||||
parameter.prop)
|
||||
elif parameter.winType == "win:GUID":
|
||||
pack_list.append(" %s((uint8_t *)%s)" % (getUserEventDataTypeMapping(runtimeFlavor)[parameter.winType], parameter.name))
|
||||
else:
|
||||
pack_list.append(" %s(%s)" % (getUserEventDataTypeMapping(runtimeFlavor)[parameter.winType], parameter.name))
|
||||
code = ",\n".join(pack_list) + "\n );\n return ERROR_SUCCESS;\n" #+ "\n\n"
|
||||
return code
|
||||
|
||||
|
||||
|
||||
keywordMap = {}
|
||||
|
||||
def generateEventKeywords(eventKeywords):
|
||||
mask = 0
|
||||
# split keywords if there are multiple
|
||||
allKeywords = eventKeywords.split()
|
||||
|
||||
for singleKeyword in allKeywords:
|
||||
mask = mask | keywordMap[singleKeyword]
|
||||
|
||||
return mask
|
||||
|
||||
def getCoreCLRUserEventImplFilePrefix():
|
||||
return """#include "common.h"
|
||||
#include <stdint.h>
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
#include <user_events.h>
|
||||
"""
|
||||
|
||||
def getCoreCLRUserEventImplFileSuffix():
|
||||
return ""
|
||||
|
||||
def getMonoUserEventImplFilePrefix():
|
||||
return ""
|
||||
|
||||
def getMonoUserEventImplFileSuffix():
|
||||
return ""
|
||||
|
||||
def getAotUserEventImplFilePrefix():
|
||||
return ""
|
||||
|
||||
def getAotUserEventImplFileSuffix():
|
||||
return ""
|
||||
|
||||
def generateUserEventImplFiles(
|
||||
etwmanifest, userevent_directory, extern, target_cpp, runtimeFlavor, inclusionList, exclusionList, dryRun):
|
||||
tree = DOM.parse(etwmanifest)
|
||||
|
||||
for providerNode in tree.getElementsByTagName('provider'):
|
||||
providerName = providerNode.getAttribute('name')
|
||||
if not includeProvider(providerName, runtimeFlavor):
|
||||
continue
|
||||
|
||||
providerPrettyName = providerName.replace("Windows-", '')
|
||||
providerPrettyName = providerPrettyName.replace("Microsoft-", '')
|
||||
|
||||
providerName_File = providerPrettyName.replace('-', '')
|
||||
if target_cpp:
|
||||
providerName_File = providerName_File + ".cpp"
|
||||
else:
|
||||
providerName_File = providerName_File + ".c"
|
||||
|
||||
providerName_File = providerName_File.lower()
|
||||
|
||||
usereventfile = os.path.join(userevent_directory, providerName_File)
|
||||
|
||||
providerPrettyName = providerPrettyName.replace('-', '_')
|
||||
|
||||
thisProviderKeywords = []
|
||||
for keywordNode in providerNode.getElementsByTagName('keyword'):
|
||||
mask = int(keywordNode.getAttribute('mask'), 0)
|
||||
thisProviderKeywords.append(mask)
|
||||
|
||||
if dryRun:
|
||||
print(usereventfile)
|
||||
else:
|
||||
with open_for_update(usereventfile) as usereventImpl:
|
||||
usereventImpl.write(stdprolog_cpp)
|
||||
header = ""
|
||||
if runtimeFlavor.coreclr:
|
||||
header = getCoreCLRUserEventImplFilePrefix()
|
||||
elif runtimeFlavor.mono:
|
||||
header = getMonoUserEventImplFilePrefix()
|
||||
elif runtimeFlavor.nativeaot:
|
||||
header = getAotUserEventImplFilePrefix()
|
||||
|
||||
usereventImpl.write(header + "\n")
|
||||
|
||||
templateNodes = providerNode.getElementsByTagName('template')
|
||||
allTemplates = parseTemplateNodes(templateNodes)
|
||||
eventNodes = providerNode.getElementsByTagName('event')
|
||||
usereventImpl.write(
|
||||
generateClrUserEventWriteEventsImpl(
|
||||
providerNode,
|
||||
providerPrettyName,
|
||||
providerName,
|
||||
eventNodes,
|
||||
allTemplates,
|
||||
extern,
|
||||
target_cpp,
|
||||
runtimeFlavor,
|
||||
thisProviderKeywords,
|
||||
inclusionList,
|
||||
exclusionList) + "\n")
|
||||
|
||||
if runtimeFlavor.coreclr:
|
||||
usereventImpl.write(getCoreCLRUserEventImplFileSuffix())
|
||||
elif runtimeFlavor.mono:
|
||||
usereventImpl.write(getMonoUserEventImplFileSuffix())
|
||||
elif runtimeFlavor.nativeaot and providerName=="Microsoft-Windows-DotNETRuntime":
|
||||
usereventImpl.write(getAotUserEventImplFileSuffix())
|
||||
|
||||
def generateUserEventFiles(
|
||||
etwmanifest, intermediate, extern, target_cpp, runtimeFlavor, inclusionList, exclusionList, dryRun):
|
||||
if runtimeFlavor.nativeaot or runtimeFlavor.mono:
|
||||
raise Exception("genUserEvents.py only supports coreclr currently.")
|
||||
|
||||
userevent_directory = os.path.join(intermediate, userevent_dirname)
|
||||
tree = DOM.parse(etwmanifest)
|
||||
|
||||
if not os.path.exists(userevent_directory):
|
||||
os.makedirs(userevent_directory)
|
||||
|
||||
# generate all keywords
|
||||
for keywordNode in tree.getElementsByTagName('keyword'):
|
||||
keywordName = keywordNode.getAttribute('name')
|
||||
keywordMask = keywordNode.getAttribute('mask')
|
||||
keywordMap[keywordName] = int(keywordMask, 0)
|
||||
|
||||
# generate file for each provider
|
||||
generateUserEventImplFiles(
|
||||
etwmanifest,
|
||||
userevent_directory,
|
||||
extern,
|
||||
target_cpp,
|
||||
runtimeFlavor,
|
||||
inclusionList,
|
||||
exclusionList,
|
||||
dryRun
|
||||
)
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
def main(argv):
|
||||
|
||||
# parse the command line
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generates the Code required to instrument userevent logging mechanism")
|
||||
|
||||
required = parser.add_argument_group('required arguments')
|
||||
required.add_argument('--man', type=str, required=True,
|
||||
help='full path to manifest containing the description of events')
|
||||
required.add_argument('--exc', type=str, required=True,
|
||||
help='full path to exclusion list')
|
||||
required.add_argument('--inc', type=str,default="",
|
||||
help='full path to inclusion list')
|
||||
required.add_argument('--intermediate', type=str, required=True,
|
||||
help='full path to eventprovider intermediate directory')
|
||||
required.add_argument('--runtimeflavor', type=str,default="CoreCLR",
|
||||
help='runtime flavor')
|
||||
required.add_argument('--nonextern', action='store_true',
|
||||
help='if specified, will generate files to be compiled into the CLR rather than extern' )
|
||||
required.add_argument('--dry-run', action='store_true',
|
||||
help='if specified, will output the names of the generated files instead of generating the files' )
|
||||
args, unknown = parser.parse_known_args(argv)
|
||||
if unknown:
|
||||
print('Unknown argument(s): ', ', '.join(unknown))
|
||||
return 1
|
||||
|
||||
sClrEtwAllMan = args.man
|
||||
exclusion_filename = args.exc
|
||||
inclusion_filename = args.inc
|
||||
intermediate = args.intermediate
|
||||
runtimeFlavor = RuntimeFlavor(args.runtimeflavor)
|
||||
extern = not args.nonextern
|
||||
dryRun = args.dry_run
|
||||
|
||||
target_cpp = True
|
||||
if runtimeFlavor.mono:
|
||||
extern = False
|
||||
target_cpp = False
|
||||
|
||||
inclusion_list = parseInclusionList(inclusion_filename)
|
||||
exclusion_list = parseExclusionList(exclusion_filename)
|
||||
|
||||
generateUserEventFiles(sClrEtwAllMan, intermediate, extern, target_cpp, runtimeFlavor, inclusion_list, exclusion_list, dryRun)
|
||||
|
||||
if __name__ == '__main__':
|
||||
return_code = main(sys.argv[1:])
|
||||
sys.exit(return_code)
|
|
@ -37,6 +37,8 @@ endif(FEATURE_JIT_PITCHING)
|
|||
if(FEATURE_PERFTRACING)
|
||||
set(CORECLR_EVENTPIPE_SHIM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/eventing/eventpipe)
|
||||
include_directories(${CORECLR_EVENTPIPE_SHIM_DIR})
|
||||
set(CORECLR_USEREVENTS_SHIM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/eventing/userevents)
|
||||
include_directories(${CORECLR_USEREVENTS_SHIM_DIR})
|
||||
endif(FEATURE_PERFTRACING)
|
||||
|
||||
set(VM_SOURCES_DAC_AND_WKS_COMMON
|
||||
|
|
|
@ -197,6 +197,10 @@
|
|||
#include "diagnosticserveradapter.h"
|
||||
#include "eventpipeadapter.h"
|
||||
|
||||
#if defined(FEATURE_PERFTRACING) && defined(TARGET_LINUX)
|
||||
#include "user_events.h"
|
||||
#endif // defined(FEATURE_PERFTRACING) && defined(TARGET_LINUX)
|
||||
|
||||
#ifndef TARGET_UNIX
|
||||
// Included for referencing __security_cookie
|
||||
#include "process.h"
|
||||
|
@ -661,6 +665,9 @@ void EEStartupHelper()
|
|||
#ifdef FEATURE_PERFTRACING
|
||||
// Initialize the event pipe.
|
||||
EventPipeAdapter::Initialize();
|
||||
#if defined(TARGET_LINUX)
|
||||
InitUserEvents();
|
||||
#endif // TARGET_LINUX
|
||||
#endif // FEATURE_PERFTRACING
|
||||
|
||||
#ifdef TARGET_UNIX
|
||||
|
|
|
@ -8,6 +8,10 @@ else()
|
|||
set(NEED_XPLAT_HEADER ON)
|
||||
endif()
|
||||
|
||||
if (CLR_CMAKE_TARGET_LINUX)
|
||||
set(USEREVENTS_ARG "--userevents")
|
||||
endif(CLR_CMAKE_TARGET_LINUX)
|
||||
|
||||
include(FindPython)
|
||||
|
||||
set (EventingHeaders
|
||||
|
@ -26,7 +30,7 @@ set(GENEVENTING_SCRIPT ${CLR_DIR}/scripts/genEventing.py)
|
|||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/eventing_headers.timestamp
|
||||
COMMAND ${Python_EXECUTABLE} ${GENEVENTING_SCRIPT} --man ${EVENT_MANIFEST} --incdir ${GENERATED_INCLUDE_DIR} --dummy ${GENERATED_INCLUDE_DIR}/etmdummy.h ${NONEXTERN_ARG} ${NOXPLATHEADER_ARG}
|
||||
COMMAND ${Python_EXECUTABLE} ${GENEVENTING_SCRIPT} --man ${EVENT_MANIFEST} --incdir ${GENERATED_INCLUDE_DIR} --dummy ${GENERATED_INCLUDE_DIR}/etmdummy.h ${NONEXTERN_ARG} ${NOXPLATHEADER_ARG} ${USEREVENTS_ARG}
|
||||
COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/eventing_headers.timestamp
|
||||
DEPENDS ${EVENT_MANIFEST} ${GENEVENTING_SCRIPT}
|
||||
VERBATIM
|
||||
|
@ -39,6 +43,10 @@ add_dependencies(eventing_headers eventprovider)
|
|||
|
||||
add_subdirectory(eventpipe)
|
||||
|
||||
if(CLR_CMAKE_TARGET_LINUX)
|
||||
add_subdirectory(userevents)
|
||||
endif(CLR_CMAKE_TARGET_LINUX)
|
||||
|
||||
if(CLR_CMAKE_HOST_WIN32)
|
||||
add_subdirectory(EtwProvider)
|
||||
endif()
|
||||
|
|
55
src/coreclr/vm/eventing/userevents/CMakeLists.txt
Normal file
55
src/coreclr/vm/eventing/userevents/CMakeLists.txt
Normal file
|
@ -0,0 +1,55 @@
|
|||
include(FindPython)
|
||||
set (GENERATE_SCRIPT ${CLR_DIR}/scripts/genUserEvents.py)
|
||||
|
||||
set(GENERATE_COMMAND ${Python_EXECUTABLE} ${GENERATE_SCRIPT} --man ${EVENT_MANIFEST} --exc ${EVENT_EXCLUSIONS} --intermediate ${CMAKE_CURRENT_BINARY_DIR} ${NONEXTERN_ARG})
|
||||
|
||||
execute_process(
|
||||
COMMAND ${GENERATE_COMMAND} --dry-run
|
||||
RESULT_VARIABLE GEN_USEREVENTS_RESULT
|
||||
OUTPUT_VARIABLE USEREVENTS_PROVIDER_OUTPUT
|
||||
ERROR_VARIABLE GEN_USEREVENTS_ERRORS
|
||||
)
|
||||
|
||||
if (NOT GEN_USEREVENTS_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to generate user_events provider: ${GEN_USEREVENTS_ERRORS}")
|
||||
endif()
|
||||
|
||||
include(${CLR_SRC_NATIVE_DIR}/external/LinuxTracepoints.cmake)
|
||||
|
||||
include_directories(${COREPAL_SOURCE_DIR}/inc/rt)
|
||||
|
||||
set (USEREVENTS_HELPER_SOURCES
|
||||
user_events.cpp)
|
||||
|
||||
# TODO: keep in sync with providers in ClrEtwAll.man
|
||||
set (USEREVENTS_PROVIDER_SOURCES
|
||||
userevents/dotnetruntime.cpp
|
||||
userevents/dotnetruntimeprivate.cpp
|
||||
userevents/dotnetruntimerundown.cpp
|
||||
userevents/dotnetruntimestress.cpp)
|
||||
|
||||
set (CORECLR_USEREVENTS_SHIM_SOURCE_PATH "${CORECLR_USEREVENTS_SHIM_DIR}")
|
||||
|
||||
addprefix(USEREVENTS_PROVIDER_SOURCES ${CMAKE_CURRENT_BINARY_DIR} "${USEREVENTS_PROVIDER_SOURCES}")
|
||||
|
||||
add_custom_command(OUTPUT ${USEREVENTS_PROVIDER_SOURCES}
|
||||
COMMAND ${GENERATE_COMMAND}
|
||||
DEPENDS ${EVENT_MANIFEST} ${GENERATE_SCRIPT})
|
||||
|
||||
set_source_files_properties(
|
||||
${USEREVENTS_PROVIDER_SOURCES}
|
||||
PROPERTIES GENERATED TRUE)
|
||||
|
||||
add_custom_target(
|
||||
generated_userevents_headers
|
||||
DEPENDS ${USEREVENTS_HEADERS})
|
||||
|
||||
add_library_clr(usereventsprovider
|
||||
OBJECT
|
||||
${USEREVENTS_HELPER_SOURCES}
|
||||
${USEREVENTS_PROVIDER_SOURCES}
|
||||
${LinuxTracepoints_sources}
|
||||
)
|
||||
|
||||
set_target_properties(usereventsprovider PROPERTIES LINKER_LANGUAGE CXX)
|
||||
add_dependencies(usereventsprovider eventing_headers)
|
80
src/coreclr/vm/eventing/userevents/user_events.cpp
Normal file
80
src/coreclr/vm/eventing/userevents/user_events.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include <common.h>
|
||||
#include <configuration.h>
|
||||
#include "user_events.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
bool s_userEventsEnabled = false;
|
||||
}
|
||||
|
||||
void InitDotNETRuntime();
|
||||
bool DotNETRuntimeEnabledByKeyword(uint8_t level, uint64_t keyword);
|
||||
|
||||
void InitDotNETRuntimePrivate();
|
||||
bool DotNETRuntimePrivateEnabledByKeyword(uint8_t level, uint64_t keyword);
|
||||
|
||||
void InitDotNETRuntimeRundown();
|
||||
bool DotNETRuntimeRundownEnabledByKeyword(uint8_t level, uint64_t keyword);
|
||||
|
||||
void InitDotNETRuntimeStress();
|
||||
bool DotNETRuntimeStressEnabledByKeyword(uint8_t level, uint64_t keyword);
|
||||
|
||||
void InitUserEvents()
|
||||
{
|
||||
bool isEnabled = Configuration::GetKnobBooleanValue(W("System.Diagnostics.Tracing.UserEvents"), false);
|
||||
if (!isEnabled)
|
||||
{
|
||||
isEnabled = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableUserEvents) != 0;
|
||||
}
|
||||
|
||||
s_userEventsEnabled = isEnabled;
|
||||
|
||||
if (s_userEventsEnabled)
|
||||
{
|
||||
InitDotNETRuntime();
|
||||
MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context.UserEventsProvider.id = 0;
|
||||
InitDotNETRuntimePrivate();
|
||||
MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context.UserEventsProvider.id = 1;
|
||||
InitDotNETRuntimeRundown();
|
||||
MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.UserEventsProvider.id = 2;
|
||||
InitDotNETRuntimeStress();
|
||||
MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_DOTNET_Context.UserEventsProvider.id = 3;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsUserEventsEnabled()
|
||||
{
|
||||
return s_userEventsEnabled;
|
||||
}
|
||||
|
||||
bool IsUserEventsEnabledByKeyword(UCHAR providerId, uint8_t level, uint64_t keyword)
|
||||
{
|
||||
switch (providerId)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
return DotNETRuntimeEnabledByKeyword(level, keyword);
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
return DotNETRuntimePrivateEnabledByKeyword(level, keyword);
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
return DotNETRuntimeRundownEnabledByKeyword(level, keyword);
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
return DotNETRuntimeStressEnabledByKeyword(level, keyword);
|
||||
}
|
||||
default:
|
||||
{
|
||||
_ASSERTE(!"Unknown provider id");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
12
src/coreclr/vm/eventing/userevents/user_events.h
Normal file
12
src/coreclr/vm/eventing/userevents/user_events.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef __USEREVENTS_H__
|
||||
#define __USEREVENTS_H__
|
||||
|
||||
|
||||
void InitUserEvents();
|
||||
bool IsUserEventsEnabled();
|
||||
bool IsUserEventsEnabledByKeyword(UCHAR providerId, uint8_t level, uint64_t keyword);
|
||||
|
||||
#endif // __USEREVENTS_H__
|
|
@ -5804,6 +5804,30 @@ bool EventPipeHelper::IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONG
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef TARGET_LINUX
|
||||
#include "user_events.h"
|
||||
bool UserEventsHelper::Enabled()
|
||||
{
|
||||
return IsUserEventsEnabled();
|
||||
}
|
||||
|
||||
bool UserEventsHelper::IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONGLONG Keyword)
|
||||
{
|
||||
return IsUserEventsEnabledByKeyword(Context.UserEventsProvider.id, Level, Keyword);
|
||||
}
|
||||
#else // TARGET_LINUX
|
||||
bool UserEventsHelper::Enabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UserEventsHelper::IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONGLONG Keyword)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif // TARGET_LINUX
|
||||
|
||||
#endif // FEATURE_PERFTRACING
|
||||
|
||||
#if defined(HOST_UNIX) && defined(FEATURE_PERFTRACING)
|
||||
|
|
2
src/native/external/LinuxTracepoints-version.txt
vendored
Normal file
2
src/native/external/LinuxTracepoints-version.txt
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
1.3.3
|
||||
https://github.com/microsoft/LinuxTracepoints/tree/a817b91dfb08b2929ec6d48a211644e3394bf1c7
|
11
src/native/external/LinuxTracepoints.cmake
vendored
Normal file
11
src/native/external/LinuxTracepoints.cmake
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# IMPORTANT: do not use add_compile_options(), add_definitions() or similar functions here since it will leak to the including projects
|
||||
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/LinuxTracepoints/libtracepoint/include)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/LinuxTracepoints/libeventheader-tracepoint/include)
|
||||
|
||||
set(LinuxTracepoints_sources_base
|
||||
libtracepoint/src/tracepoint.c
|
||||
libeventheader-tracepoint/src/eventheader-tracepoint.c)
|
||||
|
||||
|
||||
addprefix(LinuxTracepoints_sources "${CMAKE_CURRENT_LIST_DIR}/LinuxTracepoints" "${LinuxTracepoints_sources_base}")
|
12
src/native/external/LinuxTracepoints/.gitattributes
vendored
Normal file
12
src/native/external/LinuxTracepoints/.gitattributes
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
* text=auto
|
||||
*.c text
|
||||
*.cpp text
|
||||
*.h text
|
||||
*.cs text
|
||||
*.md text
|
||||
*.txt text
|
||||
*.json text
|
||||
*.yml text
|
||||
*.config text
|
||||
*.cmake.in text
|
||||
*.sln text eol=crlf
|
10
src/native/external/LinuxTracepoints/.gitignore
vendored
Normal file
10
src/native/external/LinuxTracepoints/.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
*.suo
|
||||
*.user
|
||||
/bin*/
|
||||
.vs/
|
||||
obj/
|
||||
/out/
|
||||
.vscode
|
||||
/rust/target/
|
||||
/rust/Cargo.lock
|
||||
/build/
|
94
src/native/external/LinuxTracepoints/CHANGELOG.md
vendored
Normal file
94
src/native/external/LinuxTracepoints/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
# LinuxTracepoints Change Log
|
||||
|
||||
## v1.3.4 (TBD)
|
||||
|
||||
- libtracepoint-control: New `tracepoint-collect` tool that records tracepoint
|
||||
events into a perf.data file.
|
||||
- libtracepoint-control: TracepointSession SavePerfDataFile adds a
|
||||
`PERF_RECORD_FINISHED_INIT` record to the generated perf.data file.
|
||||
- libeventheader: tool `eventheader-register` deleted. Instead, use
|
||||
`tracepoint-register` from libtracepoint.
|
||||
|
||||
## v1.3.3 (2024-04-15)
|
||||
|
||||
- BUG FIX: EADDRINUSE returned during TraceLoggingRegister on newer kernels.
|
||||
The "name already in use" detection splits on whitespace, while all other
|
||||
processing splits on semicolon. Fix by adding space after each semicolon
|
||||
in `EVENTHEADER_COMMAND_TYPES`.
|
||||
- libtracepoint-decode: In pipe mode, load event names at FinishedInit instead
|
||||
of HeaderLastFeature since not all traces emit HeaderLastFeature.
|
||||
- libtracepoint-decode: Recognize files from LP32 systems as 32-bit.
|
||||
- libtracepoint: new tool `tracepoint-register` for pre-registering
|
||||
tracepoints.
|
||||
- libeventheader: existing tool `eventheader-register` is deprecated in
|
||||
favor of `tracepoint-register`.
|
||||
- libeventheader-decode-dotnet: Moved to separate repository
|
||||
[LinuxTracepoints-Net](https://github.com/microsoft/LinuxTracepoints-Net).
|
||||
|
||||
## v1.3.2 (2024-02-27)
|
||||
|
||||
- Bug fix: Open `user_events_data` for `O_WRONLY` instead of `O_RDWR`.
|
||||
|
||||
## v1.3.1 (2024-01-11)
|
||||
|
||||
- `TracepointSession` supports per-CPU buffer sizes (including 0) to allow
|
||||
memory usage optimization when trace producers are known to be bound to
|
||||
specific CPUs.
|
||||
- `TracepointSession` uses `PERF_ATTR_SIZE_VER3` for the size of
|
||||
`perf_event_attr` to minimize the chance of incompatibilities.
|
||||
|
||||
## v1.3.0 (2023-11-27)
|
||||
|
||||
- **Breaking changes** to `PerfDataFile`:
|
||||
- `dataFile.AttrCount()` method replaced by `EventDescCount()` method.
|
||||
- `dataFile.Attr(index)` method replaced by `EventDesc(index)` method.
|
||||
The returned `PerfEventDesc` object contains an `attr` pointer.
|
||||
- `dataFile.EventDescById(id)` method replaced by `FindEventDescById(id)`.
|
||||
- **Breaking changes** to `PerfSampleEventInfo`:
|
||||
- `eventInfo.session` field renamed to `session_info`.
|
||||
- `eventInfo.attr` field replaced by `Attr()` method.
|
||||
- `eventInfo.name` field replaced by `Name()` method.
|
||||
- `eventInfo.sample_type` field replaced by `SampleType()` method.
|
||||
- `eventInfo.raw_meta` field replaced by `Metadata()` method.
|
||||
- **Breaking changes** to `TracepointSession`:
|
||||
- `session.EnableTracePoint(...)` method renamed to `EnableTracepoint(...)`.
|
||||
- `session.DisableTracePoint(...)` method renamed to `DisableTracepoint(...)`.
|
||||
- `EventFormatter` formats timestamps as date-time if clock information is
|
||||
available in the event metadata. If clock information is not present, it
|
||||
continues to format timestamps as seconds.
|
||||
- `TracepointSession` provides `SavePerfDataFile(filename)` method to save
|
||||
the current contents of the session buffers into a `perf.data` file.
|
||||
- `TracepointSession` now includes ID in default sample type.
|
||||
- `TracepointSession` records clock information from the session.
|
||||
- `TracepointSession` provides access to information about the tracepoints
|
||||
that have been added to the session (metadata, status, statistics).
|
||||
- `PerfDataFile` decodes clock information from perf.data files if present.
|
||||
- `PerfDataFile` provides access to more metadata via `PerfEventDesc` struct.
|
||||
- `PerfDataFile` provides `EventDataSize` for determining the size of an event.
|
||||
- New `PerfDataFileWriter` class for generating `perf.data` files.
|
||||
- Changed procedure for locating the `user_events_data` file.
|
||||
- Old: parse `/proc/mounts` to determine the `tracefs` or `debugfs` mount
|
||||
point, then use that as the root for the `user_events_data` path.
|
||||
- New: try `/sys/kernel/tracing/user_events_data`; if that doesn't exist,
|
||||
parse `/proc/mounts` to find the `tracefs` or `debugfs` mount point.
|
||||
- Rationale: Probe an absolute path so that containers don't have to
|
||||
create a fake `/proc/mounts` and for efficiency in the common case.
|
||||
|
||||
## v1.2.1 (2023-07-24)
|
||||
|
||||
- Prefer `user_events_data` from `tracefs` over `user_events_data` from
|
||||
`debugfs`.
|
||||
|
||||
## v1.2 (2023-06-27)
|
||||
|
||||
- Added "Preregister" methods to the `TracepointCache` class so that a
|
||||
controller can pre-register events that it wants to collect.
|
||||
- If no consumers have enabled a tracepoint, the kernel now returns `EBADF`.
|
||||
The provider APIs have been updated to be consistent with the new behavior.
|
||||
|
||||
## v1.1 (2023-06-20)
|
||||
|
||||
- Add namespaces to the C++ APIs.
|
||||
- Move non-eventheader logic from eventheader-decode to new tracepoint-decode
|
||||
library.
|
||||
- Add new libtracepoint-control library.
|
17
src/native/external/LinuxTracepoints/CMakeLists.txt
vendored
Normal file
17
src/native/external/LinuxTracepoints/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
include(version.cmake)
|
||||
project(LinuxTracepoints
|
||||
VERSION ${LINUXTRACEPOINTS_VERSION})
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
|
||||
add_subdirectory(libtracepoint)
|
||||
add_subdirectory(libtracepoint-decode-cpp)
|
||||
add_subdirectory(libeventheader-tracepoint)
|
||||
add_subdirectory(libeventheader-decode-cpp)
|
||||
|
||||
if(NOT WIN32)
|
||||
add_subdirectory(libtracepoint-control-cpp)
|
||||
endif()
|
117
src/native/external/LinuxTracepoints/CMakePresets.json
vendored
Normal file
117
src/native/external/LinuxTracepoints/CMakePresets.json
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
{
|
||||
"version": 3,
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "Release",
|
||||
"description": "Compile project with release build settings",
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/build/out/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/build/install/${presetName}"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Linux"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||
"hostOS": ["Linux"]
|
||||
},
|
||||
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
|
||||
"copySources": true,
|
||||
"rsyncCommandArgs": ["-t", "--delete", "--delete-excluded"],
|
||||
"copySourcesOptions": {
|
||||
"method": "rsync"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Debug",
|
||||
"description": "Compile project with debug build settings",
|
||||
"inherits": "Release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ReleaseClang",
|
||||
"displayName": "Release clang",
|
||||
"inherits": "Release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "DebugClang",
|
||||
"inherits": "Debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "DebugGCC",
|
||||
"inherits": "Debug",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "g++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ReleaseGCC",
|
||||
"inherits": "Release",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "g++"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"displayName": "Debug VS",
|
||||
"description": "Compile project with VS",
|
||||
"generator": "Visual Studio 17 2022",
|
||||
"architecture": "x64",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
|
||||
},
|
||||
"condition": {
|
||||
"type": "equals",
|
||||
"lhs": "${hostSystemName}",
|
||||
"rhs": "Windows"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||
"hostOS": ["Windows"]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "Release",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "Release"
|
||||
},
|
||||
{
|
||||
"name": "Debug",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "Windows",
|
||||
"description": "",
|
||||
"displayName": "",
|
||||
"configurePreset": "Windows",
|
||||
"configuration": "Debug",
|
||||
"targets": ["ALL_BUILD"]
|
||||
}
|
||||
]
|
||||
}
|
9
src/native/external/LinuxTracepoints/CODE_OF_CONDUCT.md
vendored
Normal file
9
src/native/external/LinuxTracepoints/CODE_OF_CONDUCT.md
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# Microsoft Open Source Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
Resources:
|
||||
|
||||
- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
|
||||
- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
|
||||
- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
|
21
src/native/external/LinuxTracepoints/LICENSE
vendored
Normal file
21
src/native/external/LinuxTracepoints/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
182
src/native/external/LinuxTracepoints/README.md
vendored
Normal file
182
src/native/external/LinuxTracepoints/README.md
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
# Libraries for Linux Tracepoints and user_events
|
||||
|
||||
This repository contains C/C++ libraries for collecting and decoding
|
||||
[Linux Tracepoint](https://www.kernel.org/doc/html/latest/trace/tracepoints.html)
|
||||
events and for generating Tracepoint events from user mode using the
|
||||
[user_events](https://docs.kernel.org/trace/user_events.html) facility.
|
||||
|
||||
Related repositories:
|
||||
|
||||
- [LinuxTracepoints-Net](https://github.com/microsoft/LinuxTracepoints-Net) -
|
||||
.NET libraries and tools for decoding perf.data files, including `eventheader`
|
||||
events.
|
||||
- [LinuxTracepoints-Rust](https://github.com/microsoft/LinuxTracepoints-Rust) -
|
||||
Rust libraries for generating Tracepoint events from user mode using the
|
||||
[user_events](https://docs.kernel.org/trace/user_events.html) facility
|
||||
|
||||
## Overview
|
||||
|
||||
- [libtracepoint](libtracepoint) -
|
||||
low-level C/C++ tracing interface. Designed to support replacement at
|
||||
link-time if a different implementation is needed (e.g. for testing).
|
||||
|
||||
- [tracepoint-provider.h](libtracepoint/include/tracepoint/tracepoint-provider.h) -
|
||||
a developer-friendly C/C++ API for writing tracepoint events to any
|
||||
implementation of the `tracepoint.h` interface.
|
||||
- [tracepoint.h](libtracepoint/include/tracepoint/tracepoint-provider.h) -
|
||||
low-level interface for writing tracepoint events.
|
||||
- [libtracepoint.a](libtracepoint/src/tracepoint.c) -
|
||||
default implementation that writes directly to the Linux `user_events` facility.
|
||||
|
||||
- [libtracepoint-control-cpp](libtracepoint-control-cpp) -
|
||||
C++ library for controlling a tracepoint event collection session.
|
||||
|
||||
- `TracingSession.h` implements an event collection session that can
|
||||
collect tracepoint events and enumerate the events that the session has
|
||||
collected. Supports real-time and circular-buffer modes.
|
||||
- `TracingPath.h` has functions for finding the `/sys/kernel/tracing`
|
||||
mount point and reading `format` files.
|
||||
- `TracepointSpec.h` parses tracepoint event specifications for configuring
|
||||
a tracepoint collection session.
|
||||
- `TracingCache.h` implements a cache for tracking parsed `format` files
|
||||
based on system+name or by `common_type` id.
|
||||
|
||||
- [libtracepoint-decode-cpp](libtracepoint-decode-cpp) -
|
||||
C++ library for decoding tracepoints. Works on both Linux and Windows.
|
||||
|
||||
- `PerfDataFile.h` defines the `PerfDataFile` class that decodes
|
||||
`perf.data` files.
|
||||
- `PerfEventInfo.h` defines the `PerfSampleEventInfo` and
|
||||
`PerfNonSampleEventInfo` structures for raw event information.
|
||||
- `PerfEventMetadata.h` defines classes for parsing ftrace event metadata
|
||||
information.
|
||||
|
||||
- [libeventheader-tracepoint](libeventheader-tracepoint) -
|
||||
`eventheader` envelope that supports extended attributes including severity
|
||||
level and optional field information (field types and field names).
|
||||
|
||||
- [TraceLoggingProvider.h](libeventheader-tracepoint/include/eventheader/TraceLoggingProvider.h) -
|
||||
a developer-friendly C/C++ API for writing `eventheader`-encapsulated
|
||||
events to any implementation of the tracepoint interface.
|
||||
- [EventHeaderDynamic.h](libeventheader-tracepoint/include/eventheader/EventHeaderDynamic.h) -
|
||||
C++ API for writing runtime-defined `eventheader`-encapsulated events,
|
||||
intended for use as an implementation layer for a higher-level API like
|
||||
OpenTelemetry.
|
||||
|
||||
- [libeventheader-decode-cpp](libeventheader-decode-cpp) -
|
||||
C++ library for decoding events that use the `eventheader` envelope.
|
||||
- `EventEnumerator` class parses an event into fields.
|
||||
- `EventFormatter` class converts event data into a string.
|
||||
- `decode-perf` tool that decodes `perf.data` files to JSON.
|
||||
|
||||
## General Usage
|
||||
|
||||
- Configure a Linux system with the `user_events` feature enabled.
|
||||
|
||||
- Supported on Linux kernel 6.4 and later.
|
||||
- Kernel must be built with `user_events` support (`CONFIG_USER_EVENTS=y`).
|
||||
- Must have either `tracefs` or `debugfs` mounted. For example, you might add
|
||||
the following line to your `/etc/fstab` file:
|
||||
`tracefs /sys/kernel/tracing tracefs defaults 0 0`
|
||||
- The user that will generate events must have `x` access to the `tracing`
|
||||
directory and `w` access to the `tracing/user_events_data` file. One
|
||||
possible implementation is to create a `tracers` group, then:
|
||||
- `chgrp tracers /sys/kernel/tracing`
|
||||
- `chgrp tracers /sys/kernel/tracing/user_events_data`
|
||||
- `chmod g+x /sys/kernel/tracing`
|
||||
- `chmod g+w /sys/kernel/tracing/user_events_data`
|
||||
|
||||
- Use one of the event generation APIs to write a program that generates events.
|
||||
|
||||
- C/C++ programs can use
|
||||
[tracepoint-provider.h](libtracepoint/include/tracepoint/tracepoint-provider.h)
|
||||
to generate regular Linux Tracepoint events that are defined at compile-time.
|
||||
(Link with `libtracepoint`.)
|
||||
- C/C++ programs can use
|
||||
[TraceLoggingProvider.h](libeventheader-tracepoint/include/eventheader/TraceLoggingProvider.h)
|
||||
to generate eventheader-enabled Tracepoint events that are defined at
|
||||
compile-time. (Link with `libtracepoint` and `libeventheader-tracepoint`.)
|
||||
- C++ middle-layer APIs (e.g. an OpenTelemetry exporter) can use
|
||||
[EventHeaderDynamic.h](libeventheader-tracepoint/include/eventheader/EventHeaderDynamic.h)
|
||||
to generate eventheader-enabled Tracepoint events that are runtime-dynamic.
|
||||
(Link with `libtracepoint` and `libeventheader-tracepoint`.)
|
||||
- Rust programs can use
|
||||
[LinuxTracepoints-Rust](https://github.com/microsoft/LinuxTracepoints-Rust)
|
||||
to generate eventheader-enabled Tracepoint events.
|
||||
|
||||
- To collect events in a C++ program, use
|
||||
[libtracepoint-control-cpp](libtracepoint-control-cpp). Note that your
|
||||
program must run as a privileged user (`CAP_PERFMON` capability plus read access to
|
||||
`/sys/kernel/tracing/events`) because access to the event collection system is
|
||||
restricted by default.
|
||||
|
||||
- To collect events without writing C++ code, use the included
|
||||
[tracepoint-collect](libtracepoint-control-cpp/tools/tracepoint-collect.cpp) tool
|
||||
or the Linux [`perf`](https://www.man7.org/linux/man-pages/man1/perf.1.html) tool
|
||||
to collect events to a `perf.data` file, e.g.
|
||||
`tracepoint-collect -o File.perf user_events:MyEvent1 user_events:MyEvent2` or
|
||||
`perf record -o File.perf -k monotonic -e user_events:MyEvent1,user_events:MyEvent2`.
|
||||
Note that you must run the tool as a privileged user to collect events (`CAP_PERFMON`
|
||||
capability plus read access to `/sys/kernel/tracing/events`).
|
||||
|
||||
- The `perf` tool binary is typically available as part of the `linux-perf`
|
||||
package (e.g. can be installed by `apt install linux-perf`). However, this
|
||||
package installs a `perf_VERSION` binary rather than a `perf` binary, so
|
||||
you will need to add an appropriate VERSION suffix to your `perf` commands
|
||||
or use a wrapper script.
|
||||
- To capture tracepoints using `perf`, you'll also need to install
|
||||
`libtraceevent`, e.g. `apt install libtraceevent1`.
|
||||
- The `linux-base` package installs a `perf` wrapper script that redirects to
|
||||
the version of `perf` that matches your current kernel (if present) so that
|
||||
you can run the appropriate version of `perf` without the VERSION suffix.
|
||||
This frequently doesn't work because the latest `perf` binary from `apt`
|
||||
doesn't always match the running kernel, so you may want to make your own
|
||||
wrapper script instead.
|
||||
- Note that for purposes of collecting events, it is usually not important
|
||||
for the version of the `perf` tool to match the kernel version, so it's
|
||||
ok to use e.g. `perf_5.10` even if you are running a newer kernel.
|
||||
|
||||
- Note that tracepoints must be registered before you can start collecting
|
||||
them. The `tracepoint-collect` tool has facilities to pre-register a user_events
|
||||
tracepoint. The `perf` command will report an error if the tracepoint is not yet
|
||||
registered.
|
||||
|
||||
- You can usually register tracepoints by starting the program that generates
|
||||
them. Most programs will register all of their tracepoints when they start
|
||||
running. (They will usually unregister when they stop running.)
|
||||
- You can also use the
|
||||
[`tracepoint-register`](libtracepoint/tools/tracepoint-register.cpp)
|
||||
tool to pre-register an event so you can start collecting it before
|
||||
starting the program that generates it.
|
||||
- If writing your own event collection tool, you might do something similar
|
||||
in your tool to pre-register the events that you need to collect. For
|
||||
example, you might use the `PreregisterTracepoint` or
|
||||
`PreregisterEventHeaderTracepoint` methods of the `TracepointCache` class
|
||||
in [`libtracepoint=control`](libtracepoint-control-cpp).
|
||||
|
||||
- Use the [`decode-perf`](libeventheader-decode-cpp/tools/decode-perf.cpp)
|
||||
tool to decode the `perf.data` file to JSON text, or write your own decoding
|
||||
tool using [libtracepoint-decode-cpp](libtracepoint-decode-cpp) and
|
||||
`libeventheader-decode-cpp`.
|
||||
|
||||
## Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit [https://cla.opensource.microsoft.com](https://cla.opensource.microsoft.com).
|
||||
|
||||
When you submit a pull request, a CLA bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Trademarks
|
||||
|
||||
This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
|
||||
trademarks or logos is subject to and must follow
|
||||
[Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/legal/intellectualproperty/trademarks/usage/general).
|
||||
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
|
||||
Any use of third-party trademarks or logos are subject to those third-party's policies.
|
41
src/native/external/LinuxTracepoints/SECURITY.md
vendored
Normal file
41
src/native/external/LinuxTracepoints/SECURITY.md
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
<!-- BEGIN MICROSOFT SECURITY.MD V0.0.8 BLOCK -->
|
||||
|
||||
## Security
|
||||
|
||||
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
|
||||
|
||||
If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||
|
||||
Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
|
||||
|
||||
If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
|
||||
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
|
||||
|
||||
Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
|
||||
|
||||
* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
|
||||
* Full paths of source file(s) related to the manifestation of the issue
|
||||
* The location of the affected source code (tag/branch/commit or direct URL)
|
||||
* Any special configuration required to reproduce the issue
|
||||
* Step-by-step instructions to reproduce the issue
|
||||
* Proof-of-concept or exploit code (if possible)
|
||||
* Impact of the issue, including how an attacker might exploit the issue
|
||||
|
||||
This information will help us triage your report more quickly.
|
||||
|
||||
If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
|
||||
|
||||
## Preferred Languages
|
||||
|
||||
We prefer all communications to be in English.
|
||||
|
||||
## Policy
|
||||
|
||||
Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
|
||||
|
||||
<!-- END MICROSOFT SECURITY.MD BLOCK -->
|
11
src/native/external/LinuxTracepoints/SUPPORT.md
vendored
Normal file
11
src/native/external/LinuxTracepoints/SUPPORT.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Support
|
||||
|
||||
## How to file issues and get help
|
||||
|
||||
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
|
||||
issues before filing new issues to avoid duplicates. For new issues, file your bug or
|
||||
feature request as a new Issue.
|
||||
|
||||
## Microsoft Support Policy
|
||||
|
||||
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
|
BIN
src/native/external/LinuxTracepoints/TestOutput/EventHeaderInterceptorLE64.dat
vendored
Normal file
BIN
src/native/external/LinuxTracepoints/TestOutput/EventHeaderInterceptorLE64.dat
vendored
Normal file
Binary file not shown.
262
src/native/external/LinuxTracepoints/TestOutput/EventHeaderInterceptorLE64.dat.linux.json
vendored
Normal file
262
src/native/external/LinuxTracepoints/TestOutput/EventHeaderInterceptorLE64.dat.linux.json
vendored
Normal file
|
@ -0,0 +1,262 @@
|
|||
|
||||
"EventHeaderInterceptorLE64.dat": [
|
||||
{ "n": "Long_Provider_Name_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0123456789:LongProviderEvent", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:EventCG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:EventCppG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:CScalars1", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:CScalars2", "meta": { "level": 1, "keyword": "0xF123456789ABCDEF", "opcode": 2 } },
|
||||
{ "n": "TestProviderC:CScalars3", "Struct20;tag=0xBEEF": { "hi;tag=0x12": "hi", "ch10;tag=0x10": [ "H", "o", "w" ] }, "meta": { "id": 1000, "version": 11, "level": 4, "keyword": "0x85", "opcode": 3, "tag": "0x1234" } },
|
||||
{ "n": "TestProviderC:Transfer00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Transfer10", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderC:Transfer11", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708", "relatedActivity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderC:i8", "i8": 100, "(-128)": -128, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u8", "u8": 200, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:i16", "i16": 30000, "(-32767-1)": -32768, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u16", "u16": 60000, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:i32", "i32": 2000000000, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u32", "u32": 4000000000, "(4294967295U)": 4294967295, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:i64", "i64": 9000000000000000000, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u64", "u64": 18000000000000000000, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:iptr", "iptr": 1234, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:uptr", "uptr": 4321, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:iL", "iL": 2000000000, "(-0x7fffffffffffffffL - 1L)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:uL", "uL": 4000000000, "(0x7fffffffffffffffL * 2UL + 1UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi8", "i8": "0x64", "(-128)": "0x80", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu8", "u8": "0xC8", "(255)": "0xFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi16", "i16": "0x7530", "(-32767-1)": "0x8000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu16", "u16": "0xEA60", "(65535)": "0xFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi32", "i32": "0x77359400", "(-2147483647-1)": "0x80000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu32", "u32": "0xEE6B2800", "(4294967295U)": "0xFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi64", "i64": "0x7CE66C50E2840000", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu64", "u64": "0xF9CCD8A1C5080000", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hiptr", "iptr": "0x4D2", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:huptr", "uptr": "0x10E1", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hiL", "iL": "0x77359400", "(-0x7fffffffffffffffL - 1L)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:huL", "uL": "0xEE6B2800", "(0x7fffffffffffffffL * 2UL + 1UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:f32", "f32": 3.1400001, "1/3": 0.333333343, "NaN": "-nan", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:f64", "f64": 6.2800000000000002, "1/3": 0.33333333333333331, "NaN": "-nan", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:b8", "b0": false, "b1": true, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:b32", "b0": false, "b1": true, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ch", "ch": "A", "FE": "Ăľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u16ch", "u16ch": "A", "FFFE": "ďżľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u32ch", "u32ch": "A", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "FFFEFDFC": "ţ<>żżŻ·Ľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:wch", "wch": "B", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "0x7fffffff": "ýżżżżż", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ptr", "pSamplePtr": "0xFFFFFFFFFFFFCFC7", "UINTPTR_MAX": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:pid", "i32": 2000000000, "(2147483647)": 2147483647, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:port", "port80": 80, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:errno", "(-2147483647-1)": "ERRNO(-2147483648)", "1": "EPERM(1)", "131": "ENOTRECOVERABLE(131)", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:t32", "i32": "2033-05-18T03:33:20", "(-2147483647-1)": "1901-12-13T20:45:52", "(2147483647)": "2038-01-19T03:14:07", "0": "1970-01-01T00:00:00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:t64", "i64": "TIME(9000000000000000000)", "(-9223372036854775807L-1)": "TIME(-9223372036854775808)", "(9223372036854775807L)": "TIME(9223372036854775807)", "0": "1970-01-01T00:00:00", "-11644473600": "1601-01-01T00:00:00", "-11644473601": "1600-12-31T23:59:59", "910692730085": "30828-09-14T02:48:05", "910692730086": "30828-09-14T02:48:06", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:guid", "guid": "01020304-0506-0708-0102-030405060708", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz8", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:wsz", "NULL": "", "wch10": "Goodbye!!", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz16", "NULL": "", "u16ch10": "HowAreU16", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz32", "NULL": "", "u32ch10": "HowAreU32", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz8", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:cwsz", "NULL": "", "wch10": "Goodb", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz16", "NULL": "", "u16ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz32", "NULL": "", "u32ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:bin", "NULL": "", "ch10": "48 6f 77 41 72", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ipV4", "ipv4": "127.0.0.1", "(4294967295U)": "255.255.255.255", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ipV6", "ipv6": "102:304:506:708:90a:b0c:d0e:f10", "fefe..fe00": "fefe:fefe:fefe:fefe:fefe:fefe:fefe:fe00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai8", "a1": [ 100 ], "s": [ 100 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au8", "a1": [ 200 ], "s": [ 200 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai16", "a1": [ 30000 ], "s": [ 30000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au16", "a1": [ 60000 ], "s": [ 60000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai32", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au32", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai64", "a1": [ 9000000000000000000 ], "s": [ 9000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au64", "a1": [ 18000000000000000000 ], "s": [ 18000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aiptr", "a1": [ 1234 ], "s": [ 1234 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:auptr", "a1": [ 4321 ], "s": [ 4321 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aiL", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:auL", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai8", "a1": [ "0x64" ], "s": [ "0x64" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau8", "a1": [ "0xC8" ], "s": [ "0xC8" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai16", "a1": [ "0x7530" ], "s": [ "0x7530" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau16", "a1": [ "0xEA60" ], "s": [ "0xEA60" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai32", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau32", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai64", "a1": [ "0x7CE66C50E2840000" ], "s": [ "0x7CE66C50E2840000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau64", "a1": [ "0xF9CCD8A1C5080000" ], "s": [ "0xF9CCD8A1C5080000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:haiptr", "a1": [ "0x4D2" ], "s": [ "0x4D2" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hauptr", "a1": [ "0x10E1" ], "s": [ "0x10E1" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:haiL", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hauL", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:af32", "a1": [ 3.1400001 ], "s": [ 3.1400001 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:af64", "a1": [ 6.2800000000000002 ], "s": [ 6.2800000000000002 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ab8", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ab32", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ach", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ach16", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ach32", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:awch", "a4": [ "G", "o", "o", "d" ], "s5": [ "G", "o", "o", "d", "b" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aptr", "a1": [ "0xFFFFFFFFFFFFCFC7" ], "s": [ "0xFFFFFFFFFFFFCFC7" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:apid", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aport", "a1": [ 24810 ], "s": [ 24810 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aerrno", "a1": [ "ERRNO(2000000000)" ], "s": [ "ERRNO(2000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aft", "a1": [ "2033-05-18T03:33:20" ], "s": [ "2033-05-18T03:33:20" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:auft", "a1": [ "TIME(9000000000000000000)" ], "s": [ "TIME(9000000000000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ag", "s0": [ ], "s1": [ "01020304-0506-0708-0102-030405060708" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ahexbytes", "s0": [ ], "s1": [ "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Default", "V8": 200, "V16": 60000, "V32": 4000000000, "V64": 18000000000000000000, "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:HexBytes", "V8": "01", "V16": "01 02", "V32": "01 02 03 04", "V64": "01 02 03 04 05 06 07 08", "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "68 6a 6b 6c", "NChar16": "68 00 6a 00 6b 00 6c 00", "NChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "LChar8": "68 6a 6b 6c", "LChar16": "68 00 6a 00 6b 00 6c 00", "LChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Bool16", "false16": false, "true16": true, "u16": 60000, "i16": 30000, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtf", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtfBom-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringXml-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringJson-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtfBom-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringXml-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringJson-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtfBom-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringXml-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringJson-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Packed", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ { "Struct2": { "K": "A", "NChar16": "68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "B", "NChar16": "ff fe 68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "C", "NChar16": "fe ff 00 68 00 6a 00 6b 00 6c" } } ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Packed0", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:PackedComplexArray", "five": 5, "MyStrings3": [ "ABC", "", "XYZ" ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:EventCG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:EventCppG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:CScalars1", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:CScalars2", "meta": { "level": 1, "keyword": "0xF123456789ABCDEF", "opcode": 2 } },
|
||||
{ "n": "TestProviderCpp:CScalars3", "Struct20;tag=0xBEEF": { "hi;tag=0x12": "hi", "ch10;tag=0x10": [ "H", "o", "w" ] }, "meta": { "id": 1000, "version": 11, "level": 4, "keyword": "0x85", "opcode": 3, "tag": "0x1234" } },
|
||||
{ "n": "TestProviderCpp:Transfer00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Transfer10", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderCpp:Transfer11", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708", "relatedActivity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderCpp:i8", "i8": 100, "(-128)": -128, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u8", "u8": 200, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:i16", "i16": 30000, "(-32767-1)": -32768, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u16", "u16": 60000, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:i32", "i32": 2000000000, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u32", "u32": 4000000000, "(4294967295U)": 4294967295, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:i64", "i64": 9000000000000000000, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u64", "u64": 18000000000000000000, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:iptr", "iptr": 1234, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:uptr", "uptr": 4321, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:iL", "iL": 2000000000, "(-0x7fffffffffffffffL - 1L)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:uL", "uL": 4000000000, "(0x7fffffffffffffffL * 2UL + 1UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi8", "i8": "0x64", "(-128)": "0x80", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu8", "u8": "0xC8", "(255)": "0xFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi16", "i16": "0x7530", "(-32767-1)": "0x8000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu16", "u16": "0xEA60", "(65535)": "0xFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi32", "i32": "0x77359400", "(-2147483647-1)": "0x80000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu32", "u32": "0xEE6B2800", "(4294967295U)": "0xFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi64", "i64": "0x7CE66C50E2840000", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu64", "u64": "0xF9CCD8A1C5080000", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hiptr", "iptr": "0x4D2", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:huptr", "uptr": "0x10E1", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hiL", "iL": "0x77359400", "(-0x7fffffffffffffffL - 1L)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:huL", "uL": "0xEE6B2800", "(0x7fffffffffffffffL * 2UL + 1UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:f32", "f32": 3.1400001, "1/3": 0.333333343, "NaN": "-nan", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:f64", "f64": 6.2800000000000002, "1/3": 0.33333333333333331, "NaN": "-nan", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:b8", "b0": false, "b1": true, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:b32", "b0": false, "b1": true, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ch", "ch": "A", "FE": "Ăľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u16ch", "u16ch": "A", "FFFE": "ďżľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u32ch", "u32ch": "A", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "FFFEFDFC": "ţ<>żżŻ·Ľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:wch", "wch": "B", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "0x7fffffff": "ýżżżżż", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ptr", "pSamplePtr": "0xFFFFFFFFFFFFCFC7", "UINTPTR_MAX": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:pid", "i32": 2000000000, "(2147483647)": 2147483647, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:port", "port80": 80, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:errno", "(-2147483647-1)": "ERRNO(-2147483648)", "1": "EPERM(1)", "131": "ENOTRECOVERABLE(131)", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:t32", "i32": "2033-05-18T03:33:20", "(-2147483647-1)": "1901-12-13T20:45:52", "(2147483647)": "2038-01-19T03:14:07", "0": "1970-01-01T00:00:00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:t64", "i64": "TIME(9000000000000000000)", "(-9223372036854775807L-1)": "TIME(-9223372036854775808)", "(9223372036854775807L)": "TIME(9223372036854775807)", "0": "1970-01-01T00:00:00", "-11644473600": "1601-01-01T00:00:00", "-11644473601": "1600-12-31T23:59:59", "910692730085": "30828-09-14T02:48:05", "910692730086": "30828-09-14T02:48:06", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:guid", "guid": "01020304-0506-0708-0102-030405060708", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz8", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:wsz", "NULL": "", "wch10": "Goodbye!!", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz16", "NULL": "", "u16ch10": "HowAreU16", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz32", "NULL": "", "u32ch10": "HowAreU32", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz8", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:cwsz", "NULL": "", "wch10": "Goodb", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz16", "NULL": "", "u16ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz32", "NULL": "", "u32ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:bin", "NULL": "", "ch10": "48 6f 77 41 72", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ipV4", "ipv4": "127.0.0.1", "(4294967295U)": "255.255.255.255", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ipV6", "ipv6": "102:304:506:708:90a:b0c:d0e:f10", "fefe..fe00": "fefe:fefe:fefe:fefe:fefe:fefe:fefe:fe00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai8", "a1": [ 100 ], "s": [ 100 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au8", "a1": [ 200 ], "s": [ 200 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai16", "a1": [ 30000 ], "s": [ 30000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au16", "a1": [ 60000 ], "s": [ 60000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai32", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au32", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai64", "a1": [ 9000000000000000000 ], "s": [ 9000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au64", "a1": [ 18000000000000000000 ], "s": [ 18000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aiptr", "a1": [ 1234 ], "s": [ 1234 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:auptr", "a1": [ 4321 ], "s": [ 4321 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aiL", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:auL", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai8", "a1": [ "0x64" ], "s": [ "0x64" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau8", "a1": [ "0xC8" ], "s": [ "0xC8" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai16", "a1": [ "0x7530" ], "s": [ "0x7530" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau16", "a1": [ "0xEA60" ], "s": [ "0xEA60" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai32", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau32", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai64", "a1": [ "0x7CE66C50E2840000" ], "s": [ "0x7CE66C50E2840000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau64", "a1": [ "0xF9CCD8A1C5080000" ], "s": [ "0xF9CCD8A1C5080000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:haiptr", "a1": [ "0x4D2" ], "s": [ "0x4D2" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hauptr", "a1": [ "0x10E1" ], "s": [ "0x10E1" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:haiL", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hauL", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:af32", "a1": [ 3.1400001 ], "s": [ 3.1400001 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:af64", "a1": [ 6.2800000000000002 ], "s": [ 6.2800000000000002 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ab8", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ab32", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ach", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ach16", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ach32", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:awch", "a4": [ "G", "o", "o", "d" ], "s5": [ "G", "o", "o", "d", "b" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aptr", "a1": [ "0xFFFFFFFFFFFFCFC7" ], "s": [ "0xFFFFFFFFFFFFCFC7" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:apid", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aport", "a1": [ 24810 ], "s": [ 24810 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aerrno", "a1": [ "ERRNO(2000000000)" ], "s": [ "ERRNO(2000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aft", "a1": [ "2033-05-18T03:33:20" ], "s": [ "2033-05-18T03:33:20" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:auft", "a1": [ "TIME(9000000000000000000)" ], "s": [ "TIME(9000000000000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ag", "s0": [ ], "s1": [ "01020304-0506-0708-0102-030405060708" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ahexbytes", "s0": [ ], "s1": [ "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Default", "V8": 200, "V16": 60000, "V32": 4000000000, "V64": 18000000000000000000, "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:HexBytes", "V8": "01", "V16": "01 02", "V32": "01 02 03 04", "V64": "01 02 03 04 05 06 07 08", "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "68 6a 6b 6c", "NChar16": "68 00 6a 00 6b 00 6c 00", "NChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "LChar8": "68 6a 6b 6c", "LChar16": "68 00 6a 00 6b 00 6c 00", "LChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Bool16", "false16": false, "true16": true, "u16": 60000, "i16": 30000, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtf", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtfBom-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringXml-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringJson-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtfBom-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringXml-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringJson-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtfBom-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringXml-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringJson-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Packed", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ { "Struct2": { "K": "A", "NChar16": "68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "B", "NChar16": "ff fe 68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "C", "NChar16": "fe ff 00 68 00 6a 00 6b 00 6c" } } ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Packed0", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:PackedComplexArray", "five": 5, "MyStrings3": [ "ABC", "", "XYZ" ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:bool", "false;tag=0x1234": false, "true": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char16", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char32", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:wchar", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:schar", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:uchar", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:sshort", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:ushort", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:sint", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:uint", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:slong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:ulong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:slonglong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:ulonglong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:float", "0": 0, "65": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:double", "0": 0, "65": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:void*", "0": "0x0", "p": "0xFFFFFFFFFFFFCFC7", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cvoid*", "0": "0x0", "p": "0xFFFFFFFFFFFFCFC7", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cchar*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char16_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cchar16_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char32_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cchar32_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:wchar_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cwchar_t*", "0": "", "hello": "hello", "meta": { "level": 5 } } ]
|
262
src/native/external/LinuxTracepoints/TestOutput/EventHeaderInterceptorLE64.dat.windows.json
vendored
Normal file
262
src/native/external/LinuxTracepoints/TestOutput/EventHeaderInterceptorLE64.dat.windows.json
vendored
Normal file
|
@ -0,0 +1,262 @@
|
|||
|
||||
"EventHeaderInterceptorLE64.dat": [
|
||||
{ "n": "Long_Provider_Name_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0123456789:LongProviderEvent", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:EventCG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:EventCppG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:CScalars1", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:CScalars2", "meta": { "level": 1, "keyword": "0xF123456789ABCDEF", "opcode": 2 } },
|
||||
{ "n": "TestProviderC:CScalars3", "Struct20;tag=0xBEEF": { "hi;tag=0x12": "hi", "ch10;tag=0x10": [ "H", "o", "w" ] }, "meta": { "id": 1000, "version": 11, "level": 4, "keyword": "0x85", "opcode": 3, "tag": "0x1234" } },
|
||||
{ "n": "TestProviderC:Transfer00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Transfer10", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderC:Transfer11", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708", "relatedActivity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderC:i8", "i8": 100, "(-128)": -128, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u8", "u8": 200, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:i16", "i16": 30000, "(-32767-1)": -32768, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u16", "u16": 60000, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:i32", "i32": 2000000000, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u32", "u32": 4000000000, "(4294967295U)": 4294967295, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:i64", "i64": 9000000000000000000, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u64", "u64": 18000000000000000000, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:iptr", "iptr": 1234, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:uptr", "uptr": 4321, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:iL", "iL": 2000000000, "(-0x7fffffffffffffffL - 1L)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:uL", "uL": 4000000000, "(0x7fffffffffffffffL * 2UL + 1UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi8", "i8": "0x64", "(-128)": "0x80", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu8", "u8": "0xC8", "(255)": "0xFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi16", "i16": "0x7530", "(-32767-1)": "0x8000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu16", "u16": "0xEA60", "(65535)": "0xFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi32", "i32": "0x77359400", "(-2147483647-1)": "0x80000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu32", "u32": "0xEE6B2800", "(4294967295U)": "0xFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hi64", "i64": "0x7CE66C50E2840000", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hu64", "u64": "0xF9CCD8A1C5080000", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hiptr", "iptr": "0x4D2", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:huptr", "uptr": "0x10E1", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hiL", "iL": "0x77359400", "(-0x7fffffffffffffffL - 1L)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:huL", "uL": "0xEE6B2800", "(0x7fffffffffffffffL * 2UL + 1UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:f32", "f32": 3.1400001, "1/3": 0.333333343, "NaN": "-nan(ind)", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:f64", "f64": 6.2800000000000002, "1/3": 0.33333333333333331, "NaN": "-nan(ind)", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:b8", "b0": false, "b1": true, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:b32", "b0": false, "b1": true, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ch", "ch": "A", "FE": "Ăľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u16ch", "u16ch": "A", "FFFE": "ďżľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:u32ch", "u32ch": "A", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "FFFEFDFC": "ţ<>żżŻ·Ľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:wch", "wch": "B", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "0x7fffffff": "ýżżżżż", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ptr", "pSamplePtr": "0xFFFFFFFFFFFFCFC7", "UINTPTR_MAX": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:pid", "i32": 2000000000, "(2147483647)": 2147483647, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:port", "port80": 80, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:errno", "(-2147483647-1)": "ERRNO(-2147483648)", "1": "EPERM(1)", "131": "ENOTRECOVERABLE(131)", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:t32", "i32": "2033-05-18T03:33:20", "(-2147483647-1)": "1901-12-13T20:45:52", "(2147483647)": "2038-01-19T03:14:07", "0": "1970-01-01T00:00:00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:t64", "i64": "TIME(9000000000000000000)", "(-9223372036854775807L-1)": "TIME(-9223372036854775808)", "(9223372036854775807L)": "TIME(9223372036854775807)", "0": "1970-01-01T00:00:00", "-11644473600": "1601-01-01T00:00:00", "-11644473601": "TIME(-11644473601)", "910692730085": "30828-09-14T02:48:05", "910692730086": "TIME(910692730086)", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:guid", "guid": "01020304-0506-0708-0102-030405060708", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz8", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:wsz", "NULL": "", "wch10": "Goodbye!!", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz16", "NULL": "", "u16ch10": "HowAreU16", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:sz32", "NULL": "", "u32ch10": "HowAreU32", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz8", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:cwsz", "NULL": "", "wch10": "Goodb", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz16", "NULL": "", "u16ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:csz32", "NULL": "", "u32ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:bin", "NULL": "", "ch10": "48 6f 77 41 72", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ipV4", "ipv4": "127.0.0.1", "(4294967295U)": "255.255.255.255", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ipV6", "ipv6": "102:304:506:708:90a:b0c:d0e:f10", "fefe..fe00": "fefe:fefe:fefe:fefe:fefe:fefe:fefe:fe00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai8", "a1": [ 100 ], "s": [ 100 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au8", "a1": [ 200 ], "s": [ 200 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai16", "a1": [ 30000 ], "s": [ 30000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au16", "a1": [ 60000 ], "s": [ 60000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai32", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au32", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ai64", "a1": [ 9000000000000000000 ], "s": [ 9000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:au64", "a1": [ 18000000000000000000 ], "s": [ 18000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aiptr", "a1": [ 1234 ], "s": [ 1234 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:auptr", "a1": [ 4321 ], "s": [ 4321 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aiL", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:auL", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai8", "a1": [ "0x64" ], "s": [ "0x64" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau8", "a1": [ "0xC8" ], "s": [ "0xC8" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai16", "a1": [ "0x7530" ], "s": [ "0x7530" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau16", "a1": [ "0xEA60" ], "s": [ "0xEA60" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai32", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau32", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hai64", "a1": [ "0x7CE66C50E2840000" ], "s": [ "0x7CE66C50E2840000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hau64", "a1": [ "0xF9CCD8A1C5080000" ], "s": [ "0xF9CCD8A1C5080000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:haiptr", "a1": [ "0x4D2" ], "s": [ "0x4D2" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hauptr", "a1": [ "0x10E1" ], "s": [ "0x10E1" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:haiL", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:hauL", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:af32", "a1": [ 3.1400001 ], "s": [ 3.1400001 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:af64", "a1": [ 6.2800000000000002 ], "s": [ 6.2800000000000002 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ab8", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ab32", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ach", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ach16", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ach32", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:awch", "a4": [ "G", "o", "o", "d" ], "s5": [ "G", "o", "o", "d", "b" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aptr", "a1": [ "0xFFFFFFFFFFFFCFC7" ], "s": [ "0xFFFFFFFFFFFFCFC7" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:apid", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aport", "a1": [ 24810 ], "s": [ 24810 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aerrno", "a1": [ "ERRNO(2000000000)" ], "s": [ "ERRNO(2000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:aft", "a1": [ "2033-05-18T03:33:20" ], "s": [ "2033-05-18T03:33:20" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:auft", "a1": [ "TIME(9000000000000000000)" ], "s": [ "TIME(9000000000000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ag", "s0": [ ], "s1": [ "01020304-0506-0708-0102-030405060708" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:ahexbytes", "s0": [ ], "s1": [ "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Default", "V8": 200, "V16": 60000, "V32": 4000000000, "V64": 18000000000000000000, "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:HexBytes", "V8": "01", "V16": "01 02", "V32": "01 02 03 04", "V64": "01 02 03 04 05 06 07 08", "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "68 6a 6b 6c", "NChar16": "68 00 6a 00 6b 00 6c 00", "NChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "LChar8": "68 6a 6b 6c", "LChar16": "68 00 6a 00 6b 00 6c 00", "LChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Bool16", "false16": false, "true16": true, "u16": 60000, "i16": 30000, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtf", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtfBom-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringXml-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringJson-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtfBom-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringXml-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringJson-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringUtfBom-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringXml-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:StringJson-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Packed", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ { "Struct2": { "K": "A", "NChar16": "68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "B", "NChar16": "ff fe 68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "C", "NChar16": "fe ff 00 68 00 6a 00 6b 00 6c" } } ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:Packed0", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:PackedComplexArray", "five": 5, "MyStrings3": [ "ABC", "", "XYZ" ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderC:EventCG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:EventCppG", "enabled": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:CScalars1", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:CScalars2", "meta": { "level": 1, "keyword": "0xF123456789ABCDEF", "opcode": 2 } },
|
||||
{ "n": "TestProviderCpp:CScalars3", "Struct20;tag=0xBEEF": { "hi;tag=0x12": "hi", "ch10;tag=0x10": [ "H", "o", "w" ] }, "meta": { "id": 1000, "version": 11, "level": 4, "keyword": "0x85", "opcode": 3, "tag": "0x1234" } },
|
||||
{ "n": "TestProviderCpp:Transfer00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Transfer10", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderCpp:Transfer11", "meta": { "level": 5, "activity": "01020304-0506-0708-0102-030405060708", "relatedActivity": "01020304-0506-0708-0102-030405060708" } },
|
||||
{ "n": "TestProviderCpp:i8", "i8": 100, "(-128)": -128, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u8", "u8": 200, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:i16", "i16": 30000, "(-32767-1)": -32768, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u16", "u16": 60000, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:i32", "i32": 2000000000, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u32", "u32": 4000000000, "(4294967295U)": 4294967295, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:i64", "i64": 9000000000000000000, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u64", "u64": 18000000000000000000, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:iptr", "iptr": 1234, "(-9223372036854775807L-1)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:uptr", "uptr": 4321, "(18446744073709551615UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:iL", "iL": 2000000000, "(-0x7fffffffffffffffL - 1L)": -9223372036854775808, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:uL", "uL": 4000000000, "(0x7fffffffffffffffL * 2UL + 1UL)": 18446744073709551615, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi8", "i8": "0x64", "(-128)": "0x80", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu8", "u8": "0xC8", "(255)": "0xFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi16", "i16": "0x7530", "(-32767-1)": "0x8000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu16", "u16": "0xEA60", "(65535)": "0xFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi32", "i32": "0x77359400", "(-2147483647-1)": "0x80000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu32", "u32": "0xEE6B2800", "(4294967295U)": "0xFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hi64", "i64": "0x7CE66C50E2840000", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hu64", "u64": "0xF9CCD8A1C5080000", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hiptr", "iptr": "0x4D2", "(-9223372036854775807L-1)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:huptr", "uptr": "0x10E1", "(18446744073709551615UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hiL", "iL": "0x77359400", "(-0x7fffffffffffffffL - 1L)": "0x8000000000000000", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:huL", "uL": "0xEE6B2800", "(0x7fffffffffffffffL * 2UL + 1UL)": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:f32", "f32": 3.1400001, "1/3": 0.333333343, "NaN": "-nan(ind)", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:f64", "f64": 6.2800000000000002, "1/3": 0.33333333333333331, "NaN": "-nan(ind)", "-Inf": "-inf", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:b8", "b0": false, "b1": true, "(255)": 255, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:b32", "b0": false, "b1": true, "(-2147483647-1)": -2147483648, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ch", "ch": "A", "FE": "Ăľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u16ch", "u16ch": "A", "FFFE": "ďżľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:u32ch", "u32ch": "A", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "FFFEFDFC": "ţ<>żżŻ·Ľ", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:wch", "wch": "B", "FFFE": "ďżľ", "10FFFF": "ôŹżż", "0x7fffffff": "ýżżżżż", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ptr", "pSamplePtr": "0xFFFFFFFFFFFFCFC7", "UINTPTR_MAX": "0xFFFFFFFFFFFFFFFF", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:pid", "i32": 2000000000, "(2147483647)": 2147483647, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:port", "port80": 80, "(65535)": 65535, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:errno", "(-2147483647-1)": "ERRNO(-2147483648)", "1": "EPERM(1)", "131": "ENOTRECOVERABLE(131)", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:t32", "i32": "2033-05-18T03:33:20", "(-2147483647-1)": "1901-12-13T20:45:52", "(2147483647)": "2038-01-19T03:14:07", "0": "1970-01-01T00:00:00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:t64", "i64": "TIME(9000000000000000000)", "(-9223372036854775807L-1)": "TIME(-9223372036854775808)", "(9223372036854775807L)": "TIME(9223372036854775807)", "0": "1970-01-01T00:00:00", "-11644473600": "1601-01-01T00:00:00", "-11644473601": "TIME(-11644473601)", "910692730085": "30828-09-14T02:48:05", "910692730086": "TIME(910692730086)", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:guid", "guid": "01020304-0506-0708-0102-030405060708", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz8", "NULL": "", "ch10": "HowAreU8?", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:wsz", "NULL": "", "wch10": "Goodbye!!", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz16", "NULL": "", "u16ch10": "HowAreU16", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:sz32", "NULL": "", "u32ch10": "HowAreU32", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz8", "NULL": "", "ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:cwsz", "NULL": "", "wch10": "Goodb", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz16", "NULL": "", "u16ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:csz32", "NULL": "", "u32ch10": "HowAr", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:bin", "NULL": "", "ch10": "48 6f 77 41 72", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ipV4", "ipv4": "127.0.0.1", "(4294967295U)": "255.255.255.255", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ipV6", "ipv6": "102:304:506:708:90a:b0c:d0e:f10", "fefe..fe00": "fefe:fefe:fefe:fefe:fefe:fefe:fefe:fe00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai8", "a1": [ 100 ], "s": [ 100 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au8", "a1": [ 200 ], "s": [ 200 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai16", "a1": [ 30000 ], "s": [ 30000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au16", "a1": [ 60000 ], "s": [ 60000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai32", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au32", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ai64", "a1": [ 9000000000000000000 ], "s": [ 9000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:au64", "a1": [ 18000000000000000000 ], "s": [ 18000000000000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aiptr", "a1": [ 1234 ], "s": [ 1234 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:auptr", "a1": [ 4321 ], "s": [ 4321 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aiL", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:auL", "a1": [ 4000000000 ], "s": [ 4000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai8", "a1": [ "0x64" ], "s": [ "0x64" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau8", "a1": [ "0xC8" ], "s": [ "0xC8" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai16", "a1": [ "0x7530" ], "s": [ "0x7530" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau16", "a1": [ "0xEA60" ], "s": [ "0xEA60" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai32", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau32", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hai64", "a1": [ "0x7CE66C50E2840000" ], "s": [ "0x7CE66C50E2840000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hau64", "a1": [ "0xF9CCD8A1C5080000" ], "s": [ "0xF9CCD8A1C5080000" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:haiptr", "a1": [ "0x4D2" ], "s": [ "0x4D2" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hauptr", "a1": [ "0x10E1" ], "s": [ "0x10E1" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:haiL", "a1": [ "0x77359400" ], "s": [ "0x77359400" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:hauL", "a1": [ "0xEE6B2800" ], "s": [ "0xEE6B2800" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:af32", "a1": [ 3.1400001 ], "s": [ 3.1400001 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:af64", "a1": [ 6.2800000000000002 ], "s": [ 6.2800000000000002 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ab8", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ab32", "a1": [ true ], "s": [ true ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ach", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ach16", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ach32", "a4": [ "H", "o", "w", "A" ], "s5": [ "H", "o", "w", "A", "r" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:awch", "a4": [ "G", "o", "o", "d" ], "s5": [ "G", "o", "o", "d", "b" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aptr", "a1": [ "0xFFFFFFFFFFFFCFC7" ], "s": [ "0xFFFFFFFFFFFFCFC7" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:apid", "a1": [ 2000000000 ], "s": [ 2000000000 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aport", "a1": [ 24810 ], "s": [ 24810 ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aerrno", "a1": [ "ERRNO(2000000000)" ], "s": [ "ERRNO(2000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:aft", "a1": [ "2033-05-18T03:33:20" ], "s": [ "2033-05-18T03:33:20" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:auft", "a1": [ "TIME(9000000000000000000)" ], "s": [ "TIME(9000000000000000000)" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ag", "s0": [ ], "s1": [ "01020304-0506-0708-0102-030405060708" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:ahexbytes", "s0": [ ], "s1": [ "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08" ], "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Default", "V8": 200, "V16": 60000, "V32": 4000000000, "V64": 18000000000000000000, "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:HexBytes", "V8": "01", "V16": "01 02", "V32": "01 02 03 04", "V64": "01 02 03 04 05 06 07 08", "V128": "01 02 03 04 05 06 07 08 01 02 03 04 05 06 07 08", "NChar8": "68 6a 6b 6c", "NChar16": "68 00 6a 00 6b 00 6c 00", "NChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "LChar8": "68 6a 6b 6c", "LChar16": "68 00 6a 00 6b 00 6c 00", "LChar32": "68 00 00 00 6a 00 00 00 6b 00 00 00 6c 00 00 00", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Bool16", "false16": false, "true16": true, "u16": 60000, "i16": 30000, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtf", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtfBom-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringXml-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringJson-NoBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtfBom-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringXml-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringJson-Bom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringUtfBom-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringXml-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:StringJson-XBom", "NChar8": "hjkl", "NChar16": "hjkl", "NChar32": "hjkl", "LChar8": "hjkl", "LChar16": "hjkl", "LChar32": "hjkl", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Packed", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ { "Struct2": { "K": "A", "NChar16": "68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "B", "NChar16": "ff fe 68 00 6a 00 6b 00 6c 00" } }, { "Struct2": { "K": "C", "NChar16": "fe ff 00 68 00 6a 00 6b 00 6c" } } ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Packed0", "five": 5, "Struct1": { "NChar8": "hjkl" }, "StructArray": [ ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:PackedComplexArray", "five": 5, "MyStrings3": [ "ABC", "", "XYZ" ], "five": 5, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:bool", "false;tag=0x1234": false, "true": true, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char16", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char32", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:wchar", "0": "\u0000", "A": "A", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:schar", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:uchar", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:sshort", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:ushort", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:sint", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:uint", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:slong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:ulong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:slonglong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:ulonglong", "0": 0, "A": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:float", "0": 0, "65": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:double", "0": 0, "65": 65, "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:void*", "0": "0x0", "p": "0xFFFFFFFFFFFFCFC7", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cvoid*", "0": "0x0", "p": "0xFFFFFFFFFFFFCFC7", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cchar*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char16_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cchar16_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:char32_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cchar32_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:wchar_t*", "0": "", "hello": "hello", "meta": { "level": 5 } },
|
||||
{ "n": "TestProviderCpp:Value:cwchar_t*", "0": "", "hello": "hello", "meta": { "level": 5 } } ]
|
45
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/CMakeLists.txt
vendored
Normal file
45
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
include(../version.cmake)
|
||||
project(eventheader-decode-cpp
|
||||
VERSION ${LINUXTRACEPOINTS_VERSION}
|
||||
DESCRIPTION "EventHeader tracepoint decoding for C/C++"
|
||||
HOMEPAGE_URL "https://github.com/microsoft/LinuxTracepoints"
|
||||
LANGUAGES CXX)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(BUILD_SAMPLES ON CACHE BOOL "Build sample code")
|
||||
set(BUILD_TOOLS ON CACHE BOOL "Build tool code")
|
||||
|
||||
if(NOT TARGET tracepoint-decode)
|
||||
find_package(tracepoint-decode ${TRACEPOINT_DECODE_MINVER} REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET eventheader-headers)
|
||||
find_package(eventheader-headers ${EVENTHEADER_HEADERS_MINVER} REQUIRED)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_compile_options(/W4 /WX /permissive-)
|
||||
else()
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wformat
|
||||
-Wformat-security
|
||||
-Werror=format-security
|
||||
-Wstack-protector
|
||||
-Werror=stack-protector)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-D_FORTIFY_SOURCE=2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_subdirectory(samples)
|
||||
endif()
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
endif()
|
11
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/README.md
vendored
Normal file
11
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/README.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# libeventheader-decode-cpp
|
||||
|
||||
C++ library for decoding events that use the eventheader envelope.
|
||||
|
||||
- **[EventEnumerator.h](include/eventheader/EventEnumerator.h):**
|
||||
Splits an eventheader-encoded event into fields.
|
||||
- **[EventFormatter.h](include/eventheader/EventFormatter.h):**
|
||||
Turns events or fields into strings.
|
||||
- **[decode-perf](samples/decode-perf.cpp):**
|
||||
Simple tool that uses `EventFormatter` and `PerfDataFile` to decode a
|
||||
`perf.data` file into JSON text. Works on Linux or Windows.
|
673
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/include/eventheader/EventEnumerator.h
vendored
Normal file
673
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/include/eventheader/EventEnumerator.h
vendored
Normal file
|
@ -0,0 +1,673 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_EventEnumerator_h
|
||||
#define _included_EventEnumerator_h 1
|
||||
|
||||
#include <eventheader/eventheader.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _In_reads_bytes_
|
||||
#define _In_reads_bytes_(cb)
|
||||
#endif
|
||||
#ifndef _Out_
|
||||
#define _Out_
|
||||
#endif
|
||||
#ifndef _Field_z_
|
||||
#define _Field_z_
|
||||
#endif
|
||||
#ifndef _Field_size_bytes_
|
||||
#define _Field_size_bytes_(cb)
|
||||
#endif
|
||||
#ifndef _Field_size_bytes_opt_
|
||||
#define _Field_size_bytes_opt_(cb)
|
||||
#endif
|
||||
|
||||
namespace eventheader_decode
|
||||
{
|
||||
// Forward declarations:
|
||||
class EventEnumerator;
|
||||
enum EventEnumeratorState : uint8_t;
|
||||
enum EventEnumeratorError : uint8_t;
|
||||
struct EventInfo;
|
||||
struct EventItemInfo;
|
||||
struct EventDataPosition;
|
||||
|
||||
/// <summary>
|
||||
/// Helper for decoding EventHeader events.
|
||||
/// </summary>
|
||||
class EventEnumerator
|
||||
{
|
||||
static event_field_encoding const EncodingCountMask = static_cast<event_field_encoding>(
|
||||
event_field_encoding_carray_flag | event_field_encoding_varray_flag);
|
||||
|
||||
static event_field_encoding const ReadFieldError = event_field_encoding_invalid;
|
||||
|
||||
/// <summary>
|
||||
/// Substate allows us to flatten
|
||||
/// "switch (state) { case X: if (condition) ... }" to
|
||||
/// "switch (substate) { case X_condition: ... }"
|
||||
/// which potentially improves performance.
|
||||
/// </summary>
|
||||
enum SubState : uint8_t
|
||||
{
|
||||
SubState_None,
|
||||
SubState_Error,
|
||||
SubState_AfterLastItem,
|
||||
SubState_BeforeFirstItem,
|
||||
SubState_Value_Metadata,
|
||||
SubState_Value_Scalar,
|
||||
SubState_Value_SimpleArrayElement,
|
||||
SubState_Value_ComplexArrayElement,
|
||||
SubState_ArrayBegin,
|
||||
SubState_ArrayEnd,
|
||||
SubState_StructBegin,
|
||||
SubState_StructEnd,
|
||||
};
|
||||
|
||||
struct StackEntry
|
||||
{
|
||||
uint16_t NextOffset; // m_metaBuf[NextOffset] starts next field's name.
|
||||
uint16_t NameOffset; // m_metaBuf[NameOffset] starts current field's name.
|
||||
uint16_t NameSize; // m_metaBuf[NameOffset + NameSize + 1] starts current field's type.
|
||||
uint16_t ArrayIndex;
|
||||
uint16_t ArrayCount;
|
||||
uint8_t RemainingFieldCount; // Number of NextProperty() calls before popping stack.
|
||||
uint8_t ArrayFlags; // Encoding & EncodingCountMask
|
||||
};
|
||||
|
||||
struct FieldType
|
||||
{
|
||||
event_field_encoding Encoding : 8;
|
||||
event_field_format Format : 8;
|
||||
unsigned Tag : 16;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
// Set up by StartEvent:
|
||||
eventheader m_header;
|
||||
uint64_t m_keyword;
|
||||
uint8_t const* m_metaBuf;
|
||||
uint8_t const* m_dataBuf;
|
||||
uint8_t const* m_activityIdBuf;
|
||||
char const* m_tracepointName; // Not nul-terminated.
|
||||
uint8_t m_tracepointNameLength;
|
||||
uint8_t m_providerNameLength; // Index into m_tracepointName
|
||||
uint8_t m_optionsIndex; // Index into m_tracepointName
|
||||
uint16_t m_metaEnd;
|
||||
uint8_t m_activityIdSize;
|
||||
bool m_needByteSwap;
|
||||
uint16_t m_eventNameSize; // Name starts at m_metaBuf
|
||||
uint32_t m_dataEnd;
|
||||
|
||||
// Values change during enumeration:
|
||||
uint32_t m_dataPosRaw;
|
||||
uint32_t m_moveNextRemaining;
|
||||
StackEntry m_stackTop;
|
||||
uint8_t m_stackIndex; // Number of items currently on stack.
|
||||
EventEnumeratorState m_state;
|
||||
SubState m_subState;
|
||||
EventEnumeratorError m_lastError;
|
||||
|
||||
uint8_t m_elementSize; // 0 if item is variable-size or complex.
|
||||
FieldType m_fieldType; // Note: fieldType.Encoding is cooked.
|
||||
uint32_t m_dataPosCooked;
|
||||
uint32_t m_itemSizeRaw;
|
||||
uint32_t m_itemSizeCooked;
|
||||
|
||||
// Limit events to 8 levels of nested structures.
|
||||
StackEntry m_stack[8];
|
||||
|
||||
public:
|
||||
|
||||
static uint32_t const MoveNextLimitDefault = 4096;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of EventEnumerator. Sets State to None.
|
||||
/// </summary>
|
||||
EventEnumerator() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current state.
|
||||
/// </summary>
|
||||
EventEnumeratorState
|
||||
State() const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Gets status for the most recent call to StartEvent, MoveNext, or MoveNextSibling.
|
||||
/// </summary>
|
||||
EventEnumeratorError
|
||||
LastError() const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Sets State to None.
|
||||
/// </summary>
|
||||
void
|
||||
Clear() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Starts decoding the specified EventHeader event: decodes the header and
|
||||
/// positions the enumerator before the first item.
|
||||
/// </para><para>
|
||||
/// On success, changes the state to BeforeFirstItem and returns true.
|
||||
/// On failure, changes the state to None (not Error) and returns false.
|
||||
/// </para><para>
|
||||
/// Note that the enumerator stores the pchTracepointName and pData pointers but
|
||||
/// does not copy the referenced data, so the referenced data must remain valid
|
||||
/// and unchanged while you are processing the data with this enumerator (i.e.
|
||||
/// do not deallocate or overwrite the name or data until you call Clear, make
|
||||
/// another call to StartEvent, or destroy this EventEnumerator instance).
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <param name="pchTracepointName">Set to tep_event->name, e.g. "MyProvider_L4K1".
|
||||
/// Must follow the tracepoint name rules described in eventheader.h.</param>
|
||||
/// <param name="cchTracepointName">Set to strlen(tep_event->name). Must be less
|
||||
/// than EVENTHEADER_NAME_MAX.</param>
|
||||
/// <param name="pData">Set to pointer to the start of the event data (the eventheader_flags
|
||||
/// field of the event header), usually something like
|
||||
/// tep_record->data + tep_event->format.fields[0].offset.</param>
|
||||
/// <param name="cbData">Set to size of the data, usually something like
|
||||
/// tep_record->size - tep_event->format.fields[0].offset.</param>
|
||||
/// <param name="moveNextLimit">Set to the maximum number of MoveNext calls to allow when
|
||||
/// processing this event (to guard against DoS attacks from a maliciously-crafted
|
||||
/// event).</param>
|
||||
/// <returns>Returns false for failure. Check LastError for details.</returns>
|
||||
bool
|
||||
StartEvent(
|
||||
_In_reads_bytes_(cchTracepointName) char const* pchTracepointName, // e.g. "MyProvider_L4K1"
|
||||
size_t cchTracepointName, // e.g. strlen(pchTracepointName)
|
||||
_In_reads_bytes_(cbData) void const* pData, // points at the eventheader_flags field
|
||||
size_t cbData, // size in bytes of the pData buffer
|
||||
uint32_t moveNextLimit = MoveNextLimitDefault) noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Positions the enumerator before the first item.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called when State != None, i.e. at any time after a
|
||||
/// successful call to StartEvent, until a call to Clear.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
void
|
||||
Reset(uint32_t moveNextLimit = MoveNextLimitDefault) noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Moves the enumerator to the next item in the current event, or to the end
|
||||
/// of the event if no more items. Returns true if moved to a valid item,
|
||||
/// false if no more items or decoding error.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called when State >= BeforeFirstItem, i.e. after a
|
||||
/// successful call to StartEvent, until MoveNext returns false.
|
||||
/// </para><para>
|
||||
/// Typically called in a loop until it returns false, e.g.:
|
||||
/// </para><code>
|
||||
/// if (!e.StartEvent(...)) return e.LastError();
|
||||
/// while (e.MoveNext())
|
||||
/// {
|
||||
/// EventItemInfo item = e.GetItemInfo();
|
||||
/// switch (e.State())
|
||||
/// {
|
||||
/// case EventEnumeratorState_Value:
|
||||
/// DoValue(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_StructBegin:
|
||||
/// DoStructBegin(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_StructEnd:
|
||||
/// DoStructEnd(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_ArrayBegin:
|
||||
/// DoArrayBegin(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_ArrayEnd:
|
||||
/// DoArrayEnd(item);
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
/// return e.LastError();
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns true if moved to a valid item.
|
||||
/// Returns false and sets state to AfterLastItem if no more items.
|
||||
/// Returns false and sets state to Error for decoding error.
|
||||
/// Check LastError for details.
|
||||
/// </returns>
|
||||
bool
|
||||
MoveNext() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Moves the enumerator to the next sibling of the current item, or to the end
|
||||
/// of the event if no more items. Returns true if moved to a valid item, false
|
||||
/// if no more items or decoding error.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called when State >= BeforeFirstItem, i.e. after a
|
||||
/// successful call to StartEvent, until MoveNext returns false.
|
||||
/// </para><list type="bullet"><item>
|
||||
/// If the current item is ArrayBegin or StructBegin, this efficiently moves
|
||||
/// enumeration to AFTER the corresponding ArrayEnd or StructEnd.
|
||||
/// </item><item>
|
||||
/// Otherwise, this is the same as MoveNext.
|
||||
/// </item></list><para>
|
||||
/// Typical use for this method is to efficiently skip past an array of fixed-size
|
||||
/// items (i.e. an array where ElementSize is nonzero) when you process all of the
|
||||
/// array items within the ArrayBegin state.
|
||||
/// </para><code>
|
||||
/// if (!e.StartEvent(...)) return e.LastError(); // Error.
|
||||
/// if (!e.MoveNext()) return e.LastError(); // AfterLastItem or Error.
|
||||
/// while (true)
|
||||
/// {
|
||||
/// EventItemInfo item = e.GetItemInfo();
|
||||
/// switch (e.State())
|
||||
/// {
|
||||
/// case EventEnumeratorState_Value:
|
||||
/// DoValue(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_StructBegin:
|
||||
/// DoStructBegin(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_StructEnd:
|
||||
/// DoStructEnd(item);
|
||||
/// break;
|
||||
/// case EventEnumeratorState_ArrayBegin:
|
||||
/// if (e.ElementSize == 0)
|
||||
/// {
|
||||
/// DoComplexArrayBegin(item);
|
||||
/// }
|
||||
/// else
|
||||
/// {
|
||||
/// // Process the entire array directly without using the enumerator.
|
||||
/// DoSimpleArrayBegin(item);
|
||||
/// for (unsigned i = 0; i != item.ArrayCount; i++)
|
||||
/// {
|
||||
/// DoArrayElement(item, i);
|
||||
/// }
|
||||
/// DoSimpleArrayEnd(item);
|
||||
///
|
||||
/// // Skip the entire array at once.
|
||||
/// if (!e.MoveNextSibling()) // Instead of MoveNext().
|
||||
/// {
|
||||
/// return e.LastError(); // AfterLastItem or Error.
|
||||
/// }
|
||||
/// continue; // Skip the MoveNext().
|
||||
/// }
|
||||
/// break;
|
||||
/// case EventEnumeratorState_ArrayEnd:
|
||||
/// DoComplexArrayEnd(item);
|
||||
/// break;
|
||||
/// }
|
||||
///
|
||||
/// if (!e.MoveNext())
|
||||
/// {
|
||||
/// return e.LastError(); // AfterLastItem or Error.
|
||||
/// }
|
||||
/// }
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns true if moved to a valid item.
|
||||
/// Returns false and sets state to AfterLastItem if no more items.
|
||||
/// Returns false and sets state to Error for decoding error.
|
||||
/// Check LastError for details.
|
||||
/// </returns>
|
||||
bool
|
||||
MoveNextSibling() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Advanced scenarios. This method is for extracting type information from an
|
||||
/// event without looking at value information. Moves the enumerator to the next
|
||||
/// field declaration (not the next field value). Returns true if moved to a valid
|
||||
/// item, false if no more items or decoding error.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called after a successful call to StartEvent, until
|
||||
/// MoveNextMetadata returns false.
|
||||
/// </para><para>
|
||||
/// Note that metadata enumeration gives a flat view of arrays and structures.
|
||||
/// There are only Value items, no BeginArray, EndArray, BeginStruct, EndStruct.
|
||||
/// A struct shows up as a value with Encoding = Struct (Format holds field count).
|
||||
/// An array shows up as a value with ArrayFlags != 0, and ArrayCount is either zero
|
||||
/// (indicating a runtime-variable array length) or nonzero (indicating a compile-time
|
||||
/// constant array length). An array of struct is a field with Encoding = Struct and
|
||||
/// ArrayFlags != 0. ValueBytes will always be empty. ArrayIndex and ElementSize
|
||||
/// will always be zero.
|
||||
/// </para><para>
|
||||
/// Note that when enumerating metadata for a structure, the enumeration may end before
|
||||
/// the expected number of fields are seen. This is a supported scenario and is not an
|
||||
/// error in the event. A large field count just means "this structure contains all the
|
||||
/// remaining fields in the event".
|
||||
/// </para><para>
|
||||
/// Typically called in a loop until it returns false.
|
||||
/// </para><code>
|
||||
/// if (!e.StartEvent(...)) return e.LastError();
|
||||
/// while (e.MoveNextMetadata())
|
||||
/// {
|
||||
/// DoFieldDeclaration(e.GetItemInfo());
|
||||
/// }
|
||||
/// return e.LastError();
|
||||
/// </code>
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns true if moved to a valid item.
|
||||
/// Returns false and sets state to AfterLastItem if no more items.
|
||||
/// Returns false and sets state to Error for decoding error.
|
||||
/// Check LastError for details.
|
||||
/// </returns>
|
||||
bool
|
||||
MoveNextMetadata() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Gets information that applies to the current event, e.g. the event name,
|
||||
/// provider name, options, level, keyword, etc.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called when State != None, i.e. at any time after a
|
||||
/// successful call to StartEvent, until a call to Clear.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
EventInfo
|
||||
GetEventInfo() const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Gets information that applies to the current item, e.g. the item's name,
|
||||
/// the item's type (integer, string, float, etc.), data pointer, data size.
|
||||
/// The current item changes each time MoveNext() is called.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called when State > BeforeFirstItem, i.e. after MoveNext
|
||||
/// returns true.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
EventItemInfo
|
||||
GetItemInfo() const noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Gets the remaining event payload, i.e. the event data that has not yet
|
||||
/// been decoded. The data position can change each time MoveNext is called.
|
||||
/// </para><para>
|
||||
/// PRECONDITION: Can be called when State != None, i.e. at any time after a
|
||||
/// successful call to StartEvent, until a call to Clear.
|
||||
/// </para><para>
|
||||
/// This can be useful after enumeration has completed to to determine
|
||||
/// whether the event contains any trailing data (data not described by the
|
||||
/// decoding information). Up to 3 bytes of trailing data is normal (padding
|
||||
/// between events), but 4 or more bytes of trailing data might indicate some
|
||||
/// kind of encoding problem or data corruption.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
EventDataPosition
|
||||
GetRawDataPosition() const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
void
|
||||
ResetImpl(uint32_t moveNextLimit) noexcept;
|
||||
|
||||
bool
|
||||
SkipStructMetadata() noexcept;
|
||||
|
||||
bool
|
||||
NextProperty() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Requires m_metaEnd >= m_stackTop.NameOffset.
|
||||
/// Reads name, encoding, format, tag starting at m_stackTop.NameOffset.
|
||||
/// Updates m_stackTop.NameSize, m_stackTop.NextOffset.
|
||||
/// On failure, returns Encoding = None.
|
||||
/// </summary>
|
||||
FieldType
|
||||
ReadFieldNameAndType() noexcept;
|
||||
|
||||
/// <summary>
|
||||
/// Requires m_metaEnd > typeOffset.
|
||||
/// Reads encoding, format, tag starting at m_stackTop.NameOffset.
|
||||
/// Updates m_stackTop.NextOffset.
|
||||
/// On failure, returns Encoding = None.
|
||||
/// </summary>
|
||||
FieldType
|
||||
ReadFieldType(uint16_t typeOffset) noexcept;
|
||||
|
||||
bool
|
||||
StartArray() noexcept;
|
||||
|
||||
void
|
||||
StartStruct() noexcept;
|
||||
|
||||
bool
|
||||
StartValue() noexcept;
|
||||
|
||||
void
|
||||
StartValueSimple() noexcept;
|
||||
|
||||
template<class CH>
|
||||
void
|
||||
StartValueStringNul() noexcept;
|
||||
|
||||
void
|
||||
StartValueStringLength16(uint8_t charSizeShift) noexcept;
|
||||
|
||||
void
|
||||
SetState(EventEnumeratorState newState, SubState newSubState) noexcept;
|
||||
|
||||
void
|
||||
SetEndState(EventEnumeratorState newState, SubState newSubState) noexcept;
|
||||
|
||||
bool
|
||||
SetNoneState(EventEnumeratorError error) noexcept;
|
||||
|
||||
bool
|
||||
SetErrorState(EventEnumeratorError error) noexcept;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Enumeration states.
|
||||
/// </summary>
|
||||
enum EventEnumeratorState : uint8_t
|
||||
{
|
||||
/// <summary>
|
||||
/// After construction, a call to Clear, or a failed StartEvent.
|
||||
/// </summary>
|
||||
EventEnumeratorState_None,
|
||||
|
||||
/// <summary>
|
||||
/// After an error has been returned by MoveNext.
|
||||
/// </summary>
|
||||
EventEnumeratorState_Error,
|
||||
|
||||
/// <summary>
|
||||
/// Positioned after the last item in the event.
|
||||
/// </summary>
|
||||
EventEnumeratorState_AfterLastItem,
|
||||
|
||||
// MoveNext() is an invalid operation for all states above this line.
|
||||
// MoveNext() is a valid operation for all states below this line.
|
||||
|
||||
/// <summary>
|
||||
/// Positioned before the first item in the event.
|
||||
/// </summary>
|
||||
EventEnumeratorState_BeforeFirstItem,
|
||||
|
||||
// GetItemInfo() is an invalid operation for all states above this line.
|
||||
// GetItemInfo() is a valid operation for all states below this line.
|
||||
|
||||
/// <summary>
|
||||
/// Positioned at an item with data (a field or an array element).
|
||||
/// </summary>
|
||||
EventEnumeratorState_Value,
|
||||
|
||||
/// <summary>
|
||||
/// Positioned before the first item in an array.
|
||||
/// </summary>
|
||||
EventEnumeratorState_ArrayBegin,
|
||||
|
||||
/// <summary>
|
||||
/// Positioned after the last item in an array.
|
||||
/// </summary>
|
||||
EventEnumeratorState_ArrayEnd,
|
||||
|
||||
/// <summary>
|
||||
/// Positioned before the first item in a struct.
|
||||
/// </summary>
|
||||
EventEnumeratorState_StructBegin,
|
||||
|
||||
/// <summary>
|
||||
/// Positioned after the last item in a struct.
|
||||
/// </summary>
|
||||
EventEnumeratorState_StructEnd,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Values for the LastError property.
|
||||
/// </summary>
|
||||
enum EventEnumeratorError : uint8_t
|
||||
{
|
||||
/// <summary>
|
||||
/// No error.
|
||||
/// </summary>
|
||||
EventEnumeratorError_Success = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Event is smaller than 8 bytes or larger than 2GB,
|
||||
/// or TracepointName is longer than 255 characters.
|
||||
/// </summary>
|
||||
EventEnumeratorError_InvalidParameter = EINVAL,
|
||||
|
||||
/// <summary>
|
||||
/// Event does not follow the EventHeader naming/layout rules,
|
||||
/// is big-endian, has unrecognized flags, or unrecognized types.
|
||||
/// </summary>
|
||||
EventEnumeratorError_NotSupported = ENOTSUP,
|
||||
|
||||
/// <summary>
|
||||
/// Resource usage limit (moveNextLimit) reached.
|
||||
/// </summary>
|
||||
EventEnumeratorError_ImplementationLimit = E2BIG,
|
||||
|
||||
/// <summary>
|
||||
/// Event has an out-of-range value.
|
||||
/// </summary>
|
||||
EventEnumeratorError_InvalidData = EBADMSG,
|
||||
|
||||
/// <summary>
|
||||
/// Event has more than 8 levels of nested structs.
|
||||
/// </summary>
|
||||
EventEnumeratorError_StackOverflow = EOVERFLOW,
|
||||
|
||||
/// <summary>
|
||||
/// Method call invalid for current State().
|
||||
/// </summary>
|
||||
EventEnumeratorError_InvalidState = EPERM,
|
||||
};
|
||||
|
||||
struct EventDataPosition
|
||||
{
|
||||
_Field_size_bytes_(Size) void const* Data;
|
||||
uint32_t Size;
|
||||
};
|
||||
|
||||
struct EventInfo
|
||||
{
|
||||
// "EventName" followed by 0 or more event attributes.
|
||||
// Each attribute is ";AttribName=AttribValue".
|
||||
// EventName should not contain ';'.
|
||||
// AttribName should not contain ';' or '='.
|
||||
// AttribValue may contain ";;" which should be unescaped to ";".
|
||||
_Field_z_ char const* Name;
|
||||
|
||||
// TracepointName, e.g. "ProviderName_LnKnnnOptions".
|
||||
// May not be nul-terminated. Length is TracepointNameLength.
|
||||
_Field_size_bytes_(TracepointNameLength) char const* TracepointName;
|
||||
|
||||
// 128-bit big-endian activity id, or NULL if none.
|
||||
_Field_size_bytes_opt_(16) uint8_t const* ActivityId;
|
||||
|
||||
// 128-bit big-endian related activity id, or NULL if none.
|
||||
_Field_size_bytes_opt_(16) uint8_t const* RelatedActivityId;
|
||||
|
||||
// flags, version, id, tag, opcode, level.
|
||||
eventheader Header;
|
||||
|
||||
// Event category bits.
|
||||
uint64_t Keyword;
|
||||
|
||||
// Length of TracepointName.
|
||||
uint8_t TracepointNameLength;
|
||||
|
||||
// Length of the ProviderName part of TracepointName, e.g. if
|
||||
// TracepointName is "ProviderName_LnKnnnOptions", this will be 12
|
||||
// since strlen("ProviderName") = 12.
|
||||
uint8_t ProviderNameLength;
|
||||
|
||||
// Index to the Options part of TracepointName, i.e. the part of the
|
||||
// TracepointName after level and keyword, e.g. if TracepointName is
|
||||
// "ProviderName_LnKnnnOptions", this will be 19.
|
||||
uint8_t OptionsIndex;
|
||||
};
|
||||
|
||||
struct EventItemInfo
|
||||
{
|
||||
// "FieldName" followed by 0 or more field attributes.
|
||||
// Each attribute is ";AttribName=AttribValue".
|
||||
// FieldName should not contain ';'.
|
||||
// AttribName should not contain ';' or '='.
|
||||
// AttribValue may contain ";;" which should be unescaped to ";".
|
||||
_Field_z_ char const* Name;
|
||||
|
||||
// Raw field value bytes.
|
||||
// May need byte-swap (check e.NeedByteSwap() or eventInfo.header.flags).
|
||||
// For strings, does not include length prefix or nul-termination.
|
||||
_Field_size_bytes_(ValueSize) void const* ValueData;
|
||||
|
||||
// Raw field value size (in bytes).
|
||||
// This is nonzero for Value items and for ArrayBegin of array of simple values.
|
||||
// This is zero for everything else, including ArrayBegin of array of complex items.
|
||||
// For strings, does not include length prefix or nul-termination.
|
||||
uint32_t ValueSize;
|
||||
|
||||
// Array element index.
|
||||
// For non-array, this is 0.
|
||||
// For ArrayBegin, this is 0.
|
||||
// For ArrayEnd, this is ArrayCount.
|
||||
uint16_t ArrayIndex;
|
||||
|
||||
// Array element count. For non-array, this is 1.
|
||||
uint16_t ArrayCount;
|
||||
|
||||
// Nonzero for simple items (fixed-size non-struct).
|
||||
// Zero for complex items (variable-size or struct).
|
||||
uint32_t ElementSize : 8;
|
||||
|
||||
// Field's underlying encoding. The encoding indicates how to determine the field's
|
||||
// size and the semantic type to use when Format = Default.
|
||||
event_field_encoding Encoding : 8;
|
||||
|
||||
// Field's semantic type. May be Default, in which case the semantic type should be
|
||||
// determined based on the default format for the field's encoding.
|
||||
// For StructBegin/StructEnd, this contains the struct field count.
|
||||
event_field_format Format : 8;
|
||||
|
||||
// 0 if item is a non-array Value.
|
||||
// event_field_encoding_carray_flag if item is a fixed-length ArrayBegin, ArrayEnd, or array Value.
|
||||
// event_field_encoding_varray_flag if item is a variable-length ArrayBegin, ArrayEnd, or array Value.
|
||||
event_field_encoding ArrayFlags : 8;
|
||||
|
||||
// True if event's byte order != host byte order.
|
||||
bool NeedByteSwap;
|
||||
|
||||
// Field tag, or 0 if none.
|
||||
uint16_t FieldTag;
|
||||
};
|
||||
}
|
||||
// namespace eventheader_decode
|
||||
|
||||
#endif // _included_EventEnumerator_h
|
234
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/include/eventheader/EventFormatter.h
vendored
Normal file
234
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/include/eventheader/EventFormatter.h
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_EventFormatter_h
|
||||
#define _included_EventFormatter_h 1
|
||||
|
||||
#include "EventEnumerator.h"
|
||||
#include <string>
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Forward declarations from libtracepoint-decode
|
||||
struct PerfSampleEventInfo;
|
||||
class PerfFieldMetadata;
|
||||
}
|
||||
|
||||
namespace eventheader_decode
|
||||
{
|
||||
// Forward declarations from this file.
|
||||
enum EventFormatterJsonFlags : unsigned;
|
||||
enum EventFormatterMetaFlags : unsigned;
|
||||
|
||||
/*
|
||||
Helper for converting event fields to strings.
|
||||
*/
|
||||
class EventFormatter
|
||||
{
|
||||
public:
|
||||
|
||||
/*
|
||||
Formats the specified sample as a UTF-8 JSON string and appends the
|
||||
result to dest.
|
||||
|
||||
If the Name flag is not specified, the appended string is a valid JSON object.
|
||||
If the Name flag is specified, the appended string is a valid JSON member,
|
||||
i.e. it is a "FieldName": prefix followed by a valid JSON object.
|
||||
|
||||
If the Space flag is specified, the appended string will begin with a space
|
||||
and will have spaces between elements, e.g. after ',' and ':'.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
*/
|
||||
int
|
||||
AppendSampleAsJson(
|
||||
std::string& dest,
|
||||
tracepoint_decode::PerfSampleEventInfo const& sampleEventInfo,
|
||||
bool fileBigEndian,
|
||||
EventFormatterJsonFlags jsonFlags = static_cast<EventFormatterJsonFlags>(0),
|
||||
EventFormatterMetaFlags metaFlags = static_cast<EventFormatterMetaFlags>(0xffff),
|
||||
uint32_t moveNextLimit = 4096);
|
||||
|
||||
/*
|
||||
Formats the specified sample field as a UTF-8 JSON string and appends the
|
||||
result to dest.
|
||||
|
||||
If the Name flag is not specified, the appended string is a valid JSON value.
|
||||
If the Name flag is specified, the appended string is a valid JSON member,
|
||||
i.e. it is a "FieldName": prefix followed by a valid JSON value.
|
||||
|
||||
If the Space flag is specified, the appended string will begin with a space
|
||||
and will have spaces between elements, e.g. after ',' and ':'.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
*/
|
||||
int
|
||||
AppendSampleFieldAsJson(
|
||||
std::string& dest,
|
||||
_In_reads_bytes_(fieldRawDataSize) void const* fieldRawData,
|
||||
size_t fieldRawDataSize,
|
||||
tracepoint_decode::PerfFieldMetadata const& fieldMetadata,
|
||||
bool fileBigEndian,
|
||||
EventFormatterJsonFlags jsonFlags = static_cast<EventFormatterJsonFlags>(0));
|
||||
|
||||
/*
|
||||
Formats the enumerator's event as a UTF-8 JSON string and appends the
|
||||
result to dest. Moves the enumerator to the end of the event.
|
||||
|
||||
If the Name flag is not specified, the appended string is a valid JSON object.
|
||||
If the Name flag is specified, the appended string is a valid JSON member,
|
||||
i.e. it is a "FieldName": prefix followed by a valid JSON object.
|
||||
|
||||
If the Space flag is specified, the appended string will begin with a space
|
||||
and will have spaces between elements, e.g. after ',' and ':'.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
|
||||
Requires: enumerator.State is BeforeFirstItem.
|
||||
*/
|
||||
int
|
||||
AppendEventAsJsonAndMoveToEnd(
|
||||
std::string& dest,
|
||||
EventEnumerator& enumerator,
|
||||
EventFormatterJsonFlags jsonFlags = static_cast<EventFormatterJsonFlags>(0),
|
||||
EventFormatterMetaFlags metaFlags = static_cast<EventFormatterMetaFlags>(0xffff));
|
||||
|
||||
/*
|
||||
Formats the item at the enumerator's current position (a value, array
|
||||
begin, or structure begin) as UTF-8 JSON string and appends the result to
|
||||
dest. Moves the enumerator to the next item as if by MoveNextSibling.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
|
||||
Requires: enumerator.State is Value, ArrayBegin, or StructBegin.
|
||||
|
||||
Booleans, decimal integers, and finite floating-point data values will be
|
||||
unquoted. Other simple data values (including hexadecimal integers, infinities
|
||||
and NaNs) will be quoted. Complex items (structures and arrays) will be
|
||||
converted to JSON objects and arrays.
|
||||
|
||||
If the Name flag is not specified, the appended string is a valid JSON value.
|
||||
If the Name flag is specified, the appended string is a valid JSON member,
|
||||
i.e. it is a "FieldName": prefix followed by a valid JSON value.
|
||||
|
||||
If the Space flag is specified, the appended string will begin with a space
|
||||
and will have spaces between elements, e.g. after ',' and ':'.
|
||||
*/
|
||||
int
|
||||
AppendItemAsJsonAndMoveNextSibling(
|
||||
std::string& dest,
|
||||
EventEnumerator& enumerator,
|
||||
EventFormatterJsonFlags jsonFlags = static_cast<EventFormatterJsonFlags>(0));
|
||||
|
||||
/*
|
||||
Formats the event field value at the enumerator's current position as a
|
||||
UTF-8 string and appends the result to dest.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
|
||||
Requires: enumerator.State is Value.
|
||||
*/
|
||||
int
|
||||
AppendValue(
|
||||
std::string& dest,
|
||||
EventEnumerator const& enumerator);
|
||||
|
||||
/*
|
||||
Formats the event field value as a UTF-8 string and appends the
|
||||
result to dest.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
|
||||
Requires: valueItem is a Value, not an ArrayBegin, StructEnd, etc.
|
||||
*/
|
||||
int
|
||||
AppendValue(
|
||||
std::string& dest,
|
||||
EventItemInfo const& valueItemInfo);
|
||||
|
||||
/*
|
||||
Formats the specified event field value as a UTF-8 string and appends the
|
||||
result to dest.
|
||||
|
||||
Returns 0 for success, errno for error. May throw bad_alloc.
|
||||
*/
|
||||
int
|
||||
AppendValue(
|
||||
std::string& dest,
|
||||
_In_reads_bytes_(valueSize) void const* valueData,
|
||||
uint32_t valueSize,
|
||||
event_field_encoding encoding,
|
||||
event_field_format format,
|
||||
bool needsByteSwap);
|
||||
|
||||
/*
|
||||
Formats the specified big-endian UUID value as a UTF-8 string and appends
|
||||
the result to dest. UUID is formatted as 36 chars with dashes, e.g.
|
||||
"00000000-0000-0000-0000-000000000000".
|
||||
|
||||
May throw bad_alloc.
|
||||
*/
|
||||
void
|
||||
AppendUuid(
|
||||
std::string& dest,
|
||||
_In_reads_bytes_(16) uint8_t const* uuid);
|
||||
};
|
||||
|
||||
/*
|
||||
Flags for use when formatting an item as a JSON string with
|
||||
AppendItemAsJsonAndMoveNextSibling.
|
||||
*/
|
||||
enum EventFormatterJsonFlags : unsigned
|
||||
{
|
||||
EventFormatterJsonFlags_None = 0,
|
||||
EventFormatterJsonFlags_Name = 0x1, // Include a "Name": prefix for root item.
|
||||
EventFormatterJsonFlags_Space = 0x2, // Include a space between values.
|
||||
EventFormatterJsonFlags_FieldTag = 0x4, // Append ";tag=0xNNNN" to name of fields if tag != 0.
|
||||
};
|
||||
|
||||
/*
|
||||
Flags controlling the metadata to be included in the "meta" suffix of a JSON
|
||||
event string.
|
||||
|
||||
Note that the "n" field is for the convenience of human readers of the JSON file.
|
||||
It contains the provider and event names and appears at the start of the event
|
||||
rather than in the "meta" section even though it is technically metadata.
|
||||
|
||||
Note that the format of the "time" field depends on the clock information that was
|
||||
provided by the session:
|
||||
|
||||
- If clock information is available: "yyyy-mm-ddThh:mm:ss.nnnnnnnnnZ"
|
||||
- Else, timestamp is seconds relative to an unknown epoch: 123.123456789
|
||||
|
||||
For consistent behavior, always include clock information in the trace,
|
||||
e.g. "perf record -k monotonic -e ...".
|
||||
*/
|
||||
enum EventFormatterMetaFlags : unsigned
|
||||
{
|
||||
EventFormatterMetaFlags_None = 0, // disable the "meta" suffix.
|
||||
EventFormatterMetaFlags_n = 0x1, // "n":"provider:event" before the user fields (not in the suffix).
|
||||
EventFormatterMetaFlags_time = 0x2, // timestamp (only for sample events).
|
||||
EventFormatterMetaFlags_cpu = 0x4, // cpu index (only for sample events).
|
||||
EventFormatterMetaFlags_pid = 0x8, // process id (only for sample events).
|
||||
EventFormatterMetaFlags_tid = 0x10, // thread id (only for sample events).
|
||||
EventFormatterMetaFlags_id = 0x20, // eventheader id (decimal integer, omitted if 0).
|
||||
EventFormatterMetaFlags_version = 0x40, // eventheader version (decimal integer, omitted if 0).
|
||||
EventFormatterMetaFlags_level = 0x80, // eventheader level (decimal integer, omitted if 0).
|
||||
EventFormatterMetaFlags_keyword = 0x100, // eventheader keyword (hexadecimal string, omitted if 0).
|
||||
EventFormatterMetaFlags_opcode = 0x200, // eventheader opcode (decimal integer, omitted if 0).
|
||||
EventFormatterMetaFlags_tag = 0x400, // eventheader tag (hexadecimal string, omitted if 0).
|
||||
EventFormatterMetaFlags_activity = 0x800, // eventheader activity ID (UUID string, omitted if 0).
|
||||
EventFormatterMetaFlags_relatedActivity = 0x1000,// eventheader related activity ID (UUID string, omitted if not set).
|
||||
EventFormatterMetaFlags_provider = 0x10000, // provider name or system name (string).
|
||||
EventFormatterMetaFlags_event = 0x20000, // event name or tracepoint name (string).
|
||||
EventFormatterMetaFlags_options = 0x40000, // eventheader provider options (string, omitted if none).
|
||||
EventFormatterMetaFlags_flags = 0x80000, // eventheader flags (hexadecimal string).
|
||||
EventFormatterMetaFlags_common = 0x100000, // Include the common_* fields before the user fields (only for sample events).
|
||||
EventFormatterMetaFlags_Default = 0xffff, // Include n..relatedActivity.
|
||||
EventFormatterMetaFlags_All = ~0u
|
||||
};
|
||||
}
|
||||
// namespace eventheader_decode
|
||||
|
||||
#endif // _included_EventFormatter_h
|
20
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/samples/CMakeLists.txt
vendored
Normal file
20
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/samples/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
add_executable(eventheader-decode-file
|
||||
decode-file.cpp)
|
||||
target_link_libraries(eventheader-decode-file
|
||||
eventheader-decode)
|
||||
|
||||
if(NOT WIN32)
|
||||
|
||||
find_library(TRACEFS_LIBRARIES tracefs)
|
||||
find_library(TRACEEVENT_LIBRARIES traceevent)
|
||||
|
||||
if(TRACEFS_LIBRARIES AND TRACEEVENT_LIBRARIES)
|
||||
|
||||
add_executable(eventheader-decode-live
|
||||
decode-live.cpp)
|
||||
target_link_libraries(eventheader-decode-live
|
||||
eventheader-decode
|
||||
"${TRACEFS_LIBRARIES}" "${TRACEEVENT_LIBRARIES}")
|
||||
|
||||
endif()
|
||||
endif()
|
173
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/samples/decode-file.cpp
vendored
Normal file
173
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/samples/decode-file.cpp
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/EventFormatter.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <share.h>
|
||||
#define fopen(filename, mode) _fsopen(filename, mode, _SH_DENYWR)
|
||||
#define strerror_r(errnum, buf, buflen) (strerror_s(buf, buflen, errnum), buf)
|
||||
#define le32toh(x) x
|
||||
#endif // _WIN32
|
||||
|
||||
using namespace eventheader_decode;
|
||||
|
||||
struct fcloseDelete
|
||||
{
|
||||
void operator()(FILE* file) const noexcept
|
||||
{
|
||||
fclose(file);
|
||||
}
|
||||
};
|
||||
|
||||
static bool
|
||||
ReadFromFile(FILE* file, void* buffer, uint32_t size)
|
||||
{
|
||||
size_t actual = fread(buffer, 1, size, file);
|
||||
if (size == actual)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int err = ferror(file);
|
||||
if (err)
|
||||
{
|
||||
char errBuf[80];
|
||||
printf("\n- fread error %u %s",
|
||||
err,
|
||||
strerror_r(err, errBuf, sizeof(errBuf)));
|
||||
}
|
||||
else if (actual != 0)
|
||||
{
|
||||
printf("\n- fread early eof (asked for %u, got %u)", size, static_cast<unsigned>(actual));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int err;
|
||||
if (argc <= 1)
|
||||
{
|
||||
printf("\nUsage: %s [InterceptorSampleFileName1] ...\n", argv[0]);
|
||||
err = 1;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::vector<char> buffer(4096);
|
||||
std::string eventText;
|
||||
EventEnumerator enumerator;
|
||||
EventFormatter formatter;
|
||||
bool comma = false;
|
||||
|
||||
for (int argi = 1; argi < argc; argi += 1)
|
||||
{
|
||||
char const* const filename = argv[argi];
|
||||
printf("%s\n\"%s\": [",
|
||||
comma ? "," : "",
|
||||
filename);
|
||||
comma = false;
|
||||
|
||||
std::unique_ptr<FILE, fcloseDelete> file(fopen(filename, "rb"));
|
||||
if (!file)
|
||||
{
|
||||
err = errno;
|
||||
char errBuf[80];
|
||||
printf("\n- fopen(%s) error %u %s",
|
||||
filename,
|
||||
err,
|
||||
strerror_r(err, errBuf, sizeof(errBuf)));
|
||||
}
|
||||
else for (;;)
|
||||
{
|
||||
uint32_t recordSize;
|
||||
if (!ReadFromFile(file.get(), &recordSize, sizeof(recordSize)))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
recordSize = le32toh(recordSize);
|
||||
|
||||
if (recordSize <= sizeof(recordSize))
|
||||
{
|
||||
printf("\n- Unexpected recordSize %u", recordSize);
|
||||
break;
|
||||
}
|
||||
|
||||
recordSize -= sizeof(recordSize); // File's recordSize includes itself.
|
||||
|
||||
if (buffer.size() < recordSize)
|
||||
{
|
||||
buffer.reserve(recordSize);
|
||||
buffer.resize(buffer.capacity());
|
||||
}
|
||||
|
||||
if (!ReadFromFile(file.get(), buffer.data(), recordSize))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto const nameSize = static_cast<uint32_t>(strnlen(buffer.data(), recordSize));
|
||||
if (nameSize == recordSize)
|
||||
{
|
||||
printf("\n- TracepointName not nul-terminated.");
|
||||
continue;
|
||||
}
|
||||
|
||||
fputs(comma ? ",\n " : "\n ", stdout);
|
||||
comma = true;
|
||||
|
||||
if (!enumerator.StartEvent(
|
||||
buffer.data(), // tracepoint name
|
||||
nameSize, // tracepoint name length
|
||||
buffer.data() + nameSize + 1, // event data
|
||||
recordSize - nameSize - 1)) // event data length
|
||||
{
|
||||
printf("\n- StartEvent error %d.", enumerator.LastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
eventText.clear();
|
||||
err = formatter.AppendEventAsJsonAndMoveToEnd(
|
||||
eventText, enumerator, static_cast<EventFormatterJsonFlags>(
|
||||
EventFormatterJsonFlags_Space |
|
||||
EventFormatterJsonFlags_FieldTag));
|
||||
if (err != 0)
|
||||
{
|
||||
printf("\n- AppendEvent error.");
|
||||
}
|
||||
else
|
||||
{
|
||||
fputs(eventText.c_str(), stdout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fputs(" ]", stdout);
|
||||
comma = true;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
err = 0;
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
printf("\nException: %s\n", ex.what());
|
||||
err = 1;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
return err;
|
||||
}
|
102
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/samples/decode-live.cpp
vendored
Normal file
102
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/samples/decode-live.cpp
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/EventFormatter.h>
|
||||
|
||||
extern "C" {
|
||||
#include <tracefs/tracefs.h>
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct CallbackContext
|
||||
{
|
||||
std::string Value;
|
||||
EventEnumerator Enumerator;
|
||||
EventFormatter Formatter;
|
||||
};
|
||||
|
||||
static int
|
||||
IterateCallback(tep_event* ev, tep_record* rec, int cpu, void* pContext)
|
||||
{
|
||||
auto& ctx = *static_cast<CallbackContext*>(pContext);
|
||||
if (ev->format.nr_fields < 1 ||
|
||||
0 != strcmp(ev->format.fields[0].name, "eventheader_flags"))
|
||||
{
|
||||
fprintf(stdout, "- No eventheader_flags: \"%s\"\n", ev->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const flagsOffset = ev->format.fields[0].offset;
|
||||
auto const pData = static_cast<uint8_t const*>(rec->data) + flagsOffset;
|
||||
auto const cData = rec->size - flagsOffset;
|
||||
|
||||
if (!ctx.Enumerator.StartEvent(ev->name, pData, cData))
|
||||
{
|
||||
fprintf(stdout, "- StartEvent error %u: \"%s\"\n", ctx.Enumerator.LastError(), ev->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
ctx.Value.clear();
|
||||
int err = ctx.Formatter.AppendEventAsJsonAndMoveToEnd(ctx.Value, ctx.Enumerator);
|
||||
if (err != 0)
|
||||
{
|
||||
fprintf(stdout, "- AppendEvent error %u: \"%s\"\n", err, ev->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout, "%s,\n", ctx.Value.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int err;
|
||||
CallbackContext callbackContext;
|
||||
auto tep = tracefs_local_events(nullptr);
|
||||
if (!tep)
|
||||
{
|
||||
err = errno;
|
||||
char errBuf[80];
|
||||
strerror_r(err, errBuf, sizeof(errBuf));
|
||||
printf("tracefs_local_events: errno=%u %s\n", err, errBuf);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
int parsingFailures;
|
||||
if (tracefs_fill_local_events(nullptr, tep, &parsingFailures))
|
||||
{
|
||||
err = errno;
|
||||
char errBuf[80];
|
||||
strerror_r(err, errBuf, sizeof(errBuf));
|
||||
printf("tracefs_fill_local_events: errno=%u %s\n", err, errBuf);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
printf("tracefs_fill_local_events parsing failures: %u\n", parsingFailures);
|
||||
|
||||
if (tracefs_iterate_raw_events(tep, nullptr, nullptr, 0, &IterateCallback, &callbackContext))
|
||||
{
|
||||
err = errno;
|
||||
char errBuf[80];
|
||||
strerror_r(err, errBuf, sizeof(errBuf));
|
||||
printf("tracefs_iterate_raw_events: errno=%u %s\n", err, errBuf);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
printf("Done.\n");
|
||||
|
||||
Done:
|
||||
|
||||
if (tep)
|
||||
{
|
||||
tep_free(tep);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
37
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/src/CMakeLists.txt
vendored
Normal file
37
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/src/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
# eventheader-decode = libeventheader-decode, DECODE_HEADERS
|
||||
add_library(eventheader-decode
|
||||
EventEnumerator.cpp
|
||||
EventFormatter.cpp)
|
||||
target_include_directories(eventheader-decode
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
target_link_libraries(eventheader-decode
|
||||
PUBLIC eventheader-headers
|
||||
PRIVATE tracepoint-decode)
|
||||
set(DECODE_HEADERS
|
||||
"${PROJECT_SOURCE_DIR}/include/eventheader/EventEnumerator.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/eventheader/EventFormatter.h")
|
||||
set_target_properties(eventheader-decode PROPERTIES
|
||||
PUBLIC_HEADER "${DECODE_HEADERS}")
|
||||
target_compile_features(eventheader-decode
|
||||
PRIVATE cxx_std_17)
|
||||
install(TARGETS eventheader-decode
|
||||
EXPORT eventheader-decodeTargets
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/eventheader)
|
||||
install(EXPORT eventheader-decodeTargets
|
||||
FILE "eventheader-decodeTargets.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-decode")
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/eventheader-decodeConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-decodeConfig.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-decode"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-decodeConfigVersion.cmake"
|
||||
COMPATIBILITY SameMinorVersion)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-decodeConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-decodeConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-decode")
|
1308
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/src/EventEnumerator.cpp
vendored
Normal file
1308
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/src/EventEnumerator.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
2234
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/src/EventFormatter.cpp
vendored
Normal file
2234
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/src/EventFormatter.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,2 @@
|
|||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/eventheader-decodeTargets.cmake")
|
8
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/tools/CMakeLists.txt
vendored
Normal file
8
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/tools/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
add_executable(decode-perf
|
||||
decode-perf.cpp)
|
||||
target_link_libraries(decode-perf
|
||||
eventheader-decode
|
||||
tracepoint-decode)
|
||||
target_compile_features(decode-perf
|
||||
PRIVATE cxx_std_17)
|
||||
install(TARGETS decode-perf)
|
140
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/tools/decode-perf.cpp
vendored
Normal file
140
src/native/external/LinuxTracepoints/libeventheader-decode-cpp/tools/decode-perf.cpp
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/PerfEventInfo.h>
|
||||
#include <tracepoint/PerfDataFile.h>
|
||||
#include <tracepoint/PerfEventAbi.h>
|
||||
#include <eventheader/EventFormatter.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strerror_r(errnum, buf, buflen) (strerror_s(buf, buflen, errnum), buf)
|
||||
#endif // _WIN32
|
||||
|
||||
using namespace eventheader_decode;
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
static bool
|
||||
FlushEvents(std::multimap<uint64_t, std::string>& events, bool comma) noexcept
|
||||
{
|
||||
for (auto const& pair : events)
|
||||
{
|
||||
fputs(comma ? ",\n " : "\n ", stdout);
|
||||
comma = true;
|
||||
fputs(pair.second.c_str(), stdout);
|
||||
}
|
||||
|
||||
events.clear();
|
||||
return comma;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int err;
|
||||
if (argc <= 1)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [perf.data] ... (use - for stdin)\n", argv[0]);
|
||||
err = 1;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::multimap<uint64_t, std::string> events;
|
||||
EventFormatter formatter;
|
||||
PerfDataFile file;
|
||||
bool comma = false;
|
||||
|
||||
for (int argi = 1; argi < argc; argi += 1)
|
||||
{
|
||||
bool const isStdin =
|
||||
0 == strcmp(argv[argi], "") ||
|
||||
0 == strcmp(argv[argi], "-") ||
|
||||
0 == strcmp(argv[argi], "--");
|
||||
char const* const filename = isStdin ? "stdin" : argv[argi];
|
||||
fprintf(stdout, "%s\n\"%s\": [",
|
||||
comma ? "," : "",
|
||||
filename);
|
||||
comma = false;
|
||||
|
||||
// CodeQL [SM01937] This is non shipping sample code that is not intended to be secure. Users should be able
|
||||
// to specify the output file path.
|
||||
err = isStdin ? file.OpenStdin() : file.Open(filename);
|
||||
if (err != 0)
|
||||
{
|
||||
char errBuf[80];
|
||||
fprintf(stderr, "\n- Open(\"%s\") error %d: \"%s\"\n",
|
||||
filename,
|
||||
err,
|
||||
strerror_r(err, errBuf, sizeof(errBuf)));
|
||||
}
|
||||
else for (;;)
|
||||
{
|
||||
perf_event_header const* pHeader;
|
||||
err = file.ReadEvent(&pHeader);
|
||||
if (!pHeader)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "\n- ReadEvent error %d.\n", err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (pHeader->type != PERF_RECORD_SAMPLE)
|
||||
{
|
||||
if (pHeader->type == PERF_RECORD_FINISHED_ROUND)
|
||||
{
|
||||
comma = FlushEvents(events, comma);
|
||||
}
|
||||
|
||||
continue; // Only interested in sample events for now.
|
||||
}
|
||||
|
||||
PerfSampleEventInfo sampleEventInfo;
|
||||
err = file.GetSampleEventInfo(pHeader, &sampleEventInfo);
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "\n- GetSampleEventInfo error %d.\n", err);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Events are returned out-of-order and need to be sorted. Use a map to
|
||||
// put them into timestamp order. Flush the map at the end of each round.
|
||||
auto it = events.emplace(
|
||||
(sampleEventInfo.SampleType() & PERF_SAMPLE_TIME) ? sampleEventInfo.time : 0u,
|
||||
std::string());
|
||||
err = formatter.AppendSampleAsJson(
|
||||
it->second,
|
||||
sampleEventInfo,
|
||||
file.FileBigEndian(),
|
||||
static_cast<EventFormatterJsonFlags>(
|
||||
EventFormatterJsonFlags_Space |
|
||||
EventFormatterJsonFlags_FieldTag));
|
||||
if (err)
|
||||
{
|
||||
fprintf(stderr, "\n- Format error %d.\n", err);
|
||||
}
|
||||
}
|
||||
|
||||
comma = FlushEvents(events, comma);
|
||||
|
||||
fputs(" ]", stdout);
|
||||
comma = true;
|
||||
}
|
||||
|
||||
fprintf(stdout, "\n");
|
||||
err = 0;
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
fprintf(stderr, "\nException: %s\n", ex.what());
|
||||
err = 1;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
return err;
|
||||
}
|
46
src/native/external/LinuxTracepoints/libeventheader-tracepoint/CMakeLists.txt
vendored
Normal file
46
src/native/external/LinuxTracepoints/libeventheader-tracepoint/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,46 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
include(../version.cmake)
|
||||
project(eventheader-tracepoint
|
||||
VERSION ${LINUXTRACEPOINTS_VERSION}
|
||||
DESCRIPTION "EventHeader-encoded Linux tracepoints for C/C++"
|
||||
HOMEPAGE_URL "https://github.com/microsoft/LinuxTracepoints"
|
||||
LANGUAGES C CXX)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(BUILD_SAMPLES ON CACHE BOOL "Build sample code")
|
||||
|
||||
if(WIN32)
|
||||
add_compile_options(/W4 /WX /permissive-)
|
||||
else()
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wformat
|
||||
-Wformat-security
|
||||
-Werror=format-security
|
||||
-Wstack-protector
|
||||
-Werror=stack-protector)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-D_FORTIFY_SOURCE=2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(include)
|
||||
|
||||
if(NOT WIN32)
|
||||
|
||||
if(NOT TARGET tracepoint-headers)
|
||||
find_package(tracepoint-headers ${TRACEPOINT_HEADERS_MINVER} REQUIRED)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET tracepoint)
|
||||
find_package(tracepoint ${TRACEPOINT_MINVER} REQUIRED)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_subdirectory(samples)
|
||||
endif()
|
||||
|
||||
endif()
|
316
src/native/external/LinuxTracepoints/libeventheader-tracepoint/README.md
vendored
Normal file
316
src/native/external/LinuxTracepoints/libeventheader-tracepoint/README.md
vendored
Normal file
|
@ -0,0 +1,316 @@
|
|||
# libeventheader-tracepoint
|
||||
|
||||
- [EventHeader](include/eventheader/eventheader.h)
|
||||
is a convention for packing events.
|
||||
- [libeventheader-tracepoint](src/eventheader-tracepoint.c)
|
||||
is a library that supports writing eventheader-packed events to any
|
||||
implementation of the `tracepoint.h` interface.
|
||||
- [TraceLoggingProvider.h](include/eventheader/TraceLoggingProvider.h)
|
||||
is a high-level C/C++ tracing API with multiple implementations targeting
|
||||
different tracing systems, e.g. Windows ETW or Linux LTTng. The
|
||||
implementation in this project packs data using the `EventHeader` convention
|
||||
and logs events using `libeventheader-tracepoint`.
|
||||
- [EventHeaderDynamic.h](include/eventheader/EventHeaderDynamic.h)
|
||||
is a mid-level C++ tracing API for generating runtime-specified events
|
||||
using the `EventHeader` convention and logging via `libeventheader-tracepoint`.
|
||||
This is intended for use as an implementation layer for a higher-level API
|
||||
like OpenTelemetry. Developers instrumenting their own C/C++ code would
|
||||
normally use `TraceLoggingProvider.h` instead of `EventHeaderDynamic.h`.
|
||||
- [Similar APIs](https://github.com/microsoft/LinuxTracepoints-Rust)
|
||||
are available for Rust.
|
||||
|
||||
## EventHeader
|
||||
|
||||
EventHeader is a tracing convention layered on top of Linux Tracepoints. It
|
||||
extends the Tracepoint system with additional event attributes and a stronger
|
||||
field value type system.
|
||||
|
||||
To reduce the number of unique Tracepoint names tracked by the kernel, we
|
||||
use a small number of Tracepoints to manage a larger number of events. All
|
||||
events with the same attributes (provider name, severity level, category
|
||||
keyword, etc.) will share one Tracepoint.
|
||||
|
||||
- This means we cannot enable/disable events individually. Instead, all events
|
||||
with similar attributes will be enabled/disabled as a group.
|
||||
- This means we cannot rely on the kernel's Tracepoint metadata for event
|
||||
identity or event field names/types. Instead, all events contain a common
|
||||
header that provides event identity, core event attributes, and support for
|
||||
optional event attributes. The kernel's Tracepoint metadata is used only for
|
||||
the Tracepoint's name and to determine whether the event follows the
|
||||
EventHeader conventions.
|
||||
- Since any eventheader-conforming tracepoint with a particular name will be
|
||||
identical from the perspective of the kernel (they all have the same
|
||||
tracepoint fields), it is possible to pre-register tracepoints. For example,
|
||||
if I have the names of eventheader-compliant tracepoints that I need to
|
||||
collect but the tracepoints have not been registered yet (because the
|
||||
programs that generate the tracepoints haven't run yet), I can just register
|
||||
them myself since any registration will be equivalent to the "real"
|
||||
registrations.
|
||||
|
||||
We define a naming scheme to be used for the shared Tracepoints:
|
||||
|
||||
`TracepointName = ProviderName + '_' + 'L' + EventLevel + 'K' + EventKeyword + [Options]`
|
||||
|
||||
We define a common event layout to be used by all EventHeader events. The
|
||||
event has a header, optional header extensions, and then the event data:
|
||||
|
||||
`Event = eventheader + [HeaderExtensions] + Data`
|
||||
|
||||
We define a format to be used for header extensions:
|
||||
|
||||
`HeaderExtension = eventheader_extension + ExtensionData`
|
||||
|
||||
We define a header extension to be used for activity IDs.
|
||||
|
||||
We define a header extension to be used for event metadata (event name, field
|
||||
names, field types).
|
||||
|
||||
For use in the event metadata extension, we define a field type system that
|
||||
supports scalar, string, binary, array, and struct.
|
||||
|
||||
Note that we assume that the Tracepoint name corresponding to the event is
|
||||
available during event decoding. The event decoder obtains the provider name
|
||||
and the keyword for an event by parsing the event's Tracepoint name.
|
||||
|
||||
Details are provided in [eventheader.h](include/eventheader/eventheader.h).
|
||||
|
||||
### Provider Names
|
||||
|
||||
A provider is a component that generates events. Each event from a provider is
|
||||
associated with a Provider Name that uniquely identifies the provider.
|
||||
|
||||
The provider name should be short, yet descriptive enough to minimize the
|
||||
chance of collision and to help developers track down the component generating
|
||||
the events. Hierarchical namespaces may be useful for provider names, e.g.
|
||||
`MyCompany_MyOrg_MyComponent`.
|
||||
|
||||
Restrictions:
|
||||
|
||||
- ProviderName may not contain `' '` or `':'` characters.
|
||||
- `strlen(ProviderName + '_' + Attributes)` must be less than
|
||||
`EVENTHEADER_NAME_MAX` (256) characters.
|
||||
- Some event APIs (e.g. tracefs) might impose additional restrictions on
|
||||
tracepoint names. For best compatibility, use only ASCII identifier
|
||||
characters `[A-Za-z0-9_]` in provider names.
|
||||
|
||||
Event attribute semantics should be consistent within a given provider. While
|
||||
some event attributes have generally-accepted semantics (e.g. level value 3
|
||||
is defined below as "warning"), the precise semantics of the attribute values
|
||||
are defined at the scope of a provider (e.g. different providers will use
|
||||
different criteria for what constitutes a warning). In addition, some
|
||||
attributes (tag, keyword) are completely provider-defined. All events with a
|
||||
particular provider name should use consistent semantics for all attributes
|
||||
(e.g. keyword bit `0x1` should have a consistent meaning for all events from a
|
||||
particular provider but will mean something different for other providers).
|
||||
|
||||
### Tracepoint Names
|
||||
|
||||
A Tracepoint is registered with the kernel for each unique combination of
|
||||
ProviderName + Attributes. This allows a larger number of distinct events to
|
||||
be controlled by a smaller number of kernel Tracepoints while still allowing
|
||||
events to be enabled/disabled at a reasonable granularity.
|
||||
|
||||
The Tracepoint name for an EventHeader event is defined as:
|
||||
|
||||
`ProviderName + '_' + 'L' + eventLevel + 'K' + eventKeyword + [Options]`
|
||||
or `printf("%s_L%xK%lx%s", providerName, eventLevel, eventKeyword, options)`,
|
||||
e.g. `MyProvider_L3K2a` or `OtherProvider_L5K0Gperf`.
|
||||
|
||||
Event level is a `uint8` value 1..255 indicating event severity, formatted as
|
||||
lowercase hexadecimal, e.g. `printf("L%x", eventLevel)`. The defined level values
|
||||
are: `1` = critical error, `2` = error, `3` = warning, `4` = information, `5` = verbose.
|
||||
|
||||
Event keyword is a `uint64` bitmask indicating event category membership,
|
||||
formatted as lowercase hexadecimal, e.g. `printf("K%lx", eventKeyword)`. Each
|
||||
bit in the keyword corresponds to a provider-defined category, e.g. a provider
|
||||
might define `0x2` = networking and `0x4` = I/O so that keyword value of
|
||||
`0x2|0x4` = `0x6` would indicate that an event is in both the networking and
|
||||
I/O categories.
|
||||
|
||||
Options (optional attributes) can be specified after the keyword attribute.
|
||||
Each option consists of an uppercase ASCII letter (option type) followed by 0
|
||||
or more ASCII digits or lowercase ASCII letters (option value). To support
|
||||
consistent event names, the options must be sorted in alphabetical order, e.g.
|
||||
"Aoption" should come before "Boption".
|
||||
|
||||
The currently defined options are:
|
||||
|
||||
- `G` = provider Group name. Defines a group of providers. This can be used by
|
||||
event analysis tools to find all providers that generate a certain kind of
|
||||
information.
|
||||
|
||||
Restrictions:
|
||||
|
||||
- ProviderName may not contain `' '` or `':'` characters.
|
||||
- Tracepoint name must be less than `EVENTHEADER_NAME_MAX` (256)
|
||||
characters in length.
|
||||
- Some event APIs (e.g. tracefs) might impose additional restrictions on
|
||||
tracepoint names. For best compatibility, use only ASCII identifier
|
||||
characters `[A-Za-z0-9_]` in provider names.
|
||||
|
||||
### Header
|
||||
|
||||
Because multiple events may share a single Tracepoint, each event must contain
|
||||
information to distinguish it from other events. To enable this, each event
|
||||
starts with an EventHeader structure which contains information about the
|
||||
event:
|
||||
|
||||
```c
|
||||
typedef struct eventheader {
|
||||
uint8_t flags; // eventheader_flags: pointer64, little_endian, extension.
|
||||
uint8_t version; // If id != 0 then increment version when event layout changes.
|
||||
uint16_t id; // Stable id for this event, or 0 if none.
|
||||
uint16_t tag; // Provider-defined event tag, or 0 if none.
|
||||
uint8_t opcode; // event_opcode: info, start activity, stop activity, etc.
|
||||
uint8_t level; // event_level: critical, error, warning, info, verbose.
|
||||
// Followed by: eventheader_extension block(s), then event payload.
|
||||
} eventheader;
|
||||
```
|
||||
|
||||
- **flags:** Bits indicating pointer size (32 or 64 bits), byte order
|
||||
(big-endian or little), and whether any header extensions are present.
|
||||
- **opcode:** Indicates special event semantics e.g. "normal event",
|
||||
"activity start event", "activity end event".
|
||||
- **tag:** Provider-defined 16-bit value. Can be used for anything.
|
||||
- **id:** 16-bit stable event identifier, or 0 if no identifier is assigned.
|
||||
- **version:** 8-bit event version, incremented for e.g. field type changes.
|
||||
- **level:** 8-bit event severity level, `1` = critical .. `5` = verbose.
|
||||
(level value in event header must match the level in the Tracepoint name.)
|
||||
|
||||
If the extension flag is not set, the header is immediately followed by the
|
||||
event payload.
|
||||
|
||||
If the extension flag is set, the header is immediately followed by one or more
|
||||
header extensions. Each header extension has a 16-bit size, a 15-bit type code,
|
||||
and a 1-bit flag indicating whether another header extension follows the
|
||||
current extension. The final header extension is immediately followed by the
|
||||
event payload.
|
||||
|
||||
### Extension
|
||||
|
||||
Each event may have any number of header extensions that contain information
|
||||
associated with the event.
|
||||
|
||||
```c
|
||||
typedef struct eventheader_extension {
|
||||
uint16_t size;
|
||||
uint16_t kind; // eventheader_extension_kind
|
||||
// Followed by size bytes of data. No padding/alignment.
|
||||
} eventheader_extension;
|
||||
```
|
||||
|
||||
The following header extensions are defined:
|
||||
|
||||
- **Activity ID:** Contains a 128-bit ID that can be used to correlate events. May
|
||||
also contain the 128-bit ID of the parent activity (typically used only for
|
||||
the first event of an activity).
|
||||
- **Metadata:** Contains the event's metadata: event name, event attributes, field
|
||||
names, field attributes, and field types. Both simple (e.g. Int32, HexInt16,
|
||||
Float64, Char32, Uuid) and complex (e.g. NulTerminatedString8,
|
||||
CountedString16, Binary, Struct, Array) types are supported.
|
||||
|
||||
### Metadata
|
||||
|
||||
Each event may have a header extension that defines event metadata, i.e.
|
||||
event name, event attributes, field names, field attributes, and field types.
|
||||
|
||||
Event definition format:
|
||||
|
||||
```c
|
||||
char event_name[]; // Nul-terminated utf-8 string: "eventName{;attribName=attribValue}"
|
||||
followed by 0 or more field definition blocks, tightly-packed (no padding).
|
||||
```
|
||||
|
||||
Field definition block:
|
||||
|
||||
```c
|
||||
char field_name[]; // Nul-terminated utf-8 string: "fieldName{;attribName=attribValue}"
|
||||
uint8_t encoding; // encoding is 0..31, with 3 flag bits.
|
||||
uint8_t format; // Present if 0 != (encoding & 128). format is 0..127, with 1 flag bit.
|
||||
uint16_t tag; // Present if 0 != (format & 128). Contains provider-defined value.
|
||||
uint16_t array_length; // Present if 0 != (encoding & 32). Contains element count of constant-length array.
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `event_name` and `field_name` may not contain any `';'` characters.
|
||||
- `event_name` and `field_name` may be followed by attribute strings.
|
||||
- attribute string is: `';' + attribName + '=' + attribValue`.
|
||||
- `attribName` may not contain any `';'` or `'='` characters.
|
||||
- Semicolons in attribValue must be escaped by doubling, e.g.
|
||||
`"my;value"` is escaped as `"my;;value"`.
|
||||
- `array_length` may not be `0`, i.e. constant-length arrays may not be empty.
|
||||
|
||||
Each field's type has an arity, an encoding, and a format.
|
||||
|
||||
- **Arity** indicates how many values are in a field.
|
||||
- A scalar field contains one value.
|
||||
- A const (fixed-length) array contains one or more values. The number of
|
||||
values is specified in the event metadata and does not vary from one event
|
||||
to another.
|
||||
- A variable (dynamic-length) array contains zero or more values. The number
|
||||
of values is specified in the event data and may vary from one event to
|
||||
another.
|
||||
- **Encoding** indicates how to determine the field size. Supported encodings:
|
||||
- Fixed-size 8-bit, 16-bit, 32-bit, 64-bit, and 128-bit values.
|
||||
- 0-terminated blobs containing 8-bit, 16-bit, or 32-bit elements (used for
|
||||
NUL-terminated strings).
|
||||
- Counted blobs containing 8-bit, 16-bit, or 32-bit elements (used for both
|
||||
strings and for binary data).
|
||||
- Structures (fields that logically contain other fields).
|
||||
- **Format** indicates how to interpret the bytes of the field data.
|
||||
- Integer: signed decimal, unsigned decimal, hexadecimal, `errno`, `pid`,
|
||||
`time_t`, Boolean, IP port.
|
||||
- String: Latin-1, UTF, UTF-BOM, XML, JSON.
|
||||
- Other: Float, IPv4 address, IPv6 address, UUID, Binary.
|
||||
|
||||
## TraceLoggingProvider.h
|
||||
|
||||
[TraceLoggingProvider.h](include/eventheader/TraceLoggingProvider.h)
|
||||
is a high-level C/C++ tracing interface with multiple implementations
|
||||
targeting different tracing systems. The implementation in this library packs
|
||||
data using the `EventHeader` convention and logs to any implementation of the
|
||||
`tracepoint.h` interface.
|
||||
|
||||
Other implementations of this header support tracing for
|
||||
[Windows ETW](https://learn.microsoft.com/windows/win32/tracelogging/trace-logging-portal)
|
||||
and [Linux LTTng](https://github.com/microsoft/tracelogging/tree/main/LTTng).
|
||||
|
||||
Basic usage:
|
||||
|
||||
```C
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
MyProvider,
|
||||
"MyProviderName", // utf-8 event source name
|
||||
// {b7aa4d18-240c-5f41-5852-817dbf477472} - UUID event source identifier
|
||||
(0xb7aa4d18, 0x240c, 0x5f41, 0x58, 0x52, 0x81, 0x7d, 0xbf, 0x47, 0x74, 0x72));
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Register the provider during component initialization.
|
||||
TraceLoggingRegister(MyProvider);
|
||||
|
||||
for (int i = 0; i < argc; i += 1)
|
||||
{
|
||||
// Log some events.
|
||||
// Note that the value expressions are only evaluated if the event is enabled.
|
||||
TraceLoggingWrite(
|
||||
MyProvider, // The event will use the "MyProviderName" event source.
|
||||
"argv", // Human-readable event name.
|
||||
TraceLoggingLevel(EventLevel_Warning), // Event severity = Warning
|
||||
TraceLoggingInt32(i, "arg_index"), // int32 field arg_index with value = i
|
||||
TraceLoggingString(argv[i], "arg_string") // char* field arg_string with value = argv[i]
|
||||
);
|
||||
}
|
||||
|
||||
// Unregister the provider during component cleanup.
|
||||
TraceLoggingUnregister(MyProvider);
|
||||
}
|
||||
```
|
||||
|
||||
Additional TraceLogging examples:
|
||||
|
||||
- [samples/sample.cpp](samples/sample.cpp)
|
||||
- [samples/interceptor-sample.cpp](samples/interceptor-sample.cpp)
|
47
src/native/external/LinuxTracepoints/libeventheader-tracepoint/include/CMakeLists.txt
vendored
Normal file
47
src/native/external/LinuxTracepoints/libeventheader-tracepoint/include/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
include(../../version.cmake)
|
||||
project(eventheader-tracepoint-headers
|
||||
VERSION ${LINUXTRACEPOINTS_VERSION}
|
||||
DESCRIPTION "EventHeader-encoded Linux tracepoints for C/C++ (headers)"
|
||||
HOMEPAGE_URL "https://github.com/microsoft/LinuxTracepoints"
|
||||
LANGUAGES C CXX)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
list(APPEND EVENTHEADER_HEADERS
|
||||
"${PROJECT_SOURCE_DIR}/eventheader/eventheader.h")
|
||||
|
||||
if(NOT WIN32)
|
||||
list(APPEND EVENTHEADER_HEADERS
|
||||
"${PROJECT_SOURCE_DIR}/eventheader/eventheader-tracepoint.h"
|
||||
"${PROJECT_SOURCE_DIR}/eventheader/EventHeaderDynamic.h"
|
||||
"${PROJECT_SOURCE_DIR}/eventheader/TraceLoggingProvider.h")
|
||||
endif()
|
||||
|
||||
# eventheader-headers = EVENTHEADER_HEADERS
|
||||
add_library(eventheader-headers INTERFACE)
|
||||
target_include_directories(eventheader-headers
|
||||
INTERFACE
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
set_target_properties(eventheader-headers PROPERTIES
|
||||
PUBLIC_HEADER "${EVENTHEADER_HEADERS}")
|
||||
install(TARGETS eventheader-headers
|
||||
EXPORT eventheader-headersTargets
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/eventheader)
|
||||
install(EXPORT eventheader-headersTargets
|
||||
FILE "eventheader-headersTargets.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-headers")
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/eventheader-headersConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-headersConfig.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-headers"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-headersConfigVersion.cmake"
|
||||
COMPATIBILITY SameMinorVersion)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-headersConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-headersConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-headers")
|
|
@ -0,0 +1,2 @@
|
|||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/eventheader-headersTargets.cmake")
|
1582
src/native/external/LinuxTracepoints/libeventheader-tracepoint/include/eventheader/EventHeaderDynamic.h
vendored
Normal file
1582
src/native/external/LinuxTracepoints/libeventheader-tracepoint/include/eventheader/EventHeaderDynamic.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,192 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_eventheader_tracepoint_h
|
||||
#define _included_eventheader_tracepoint_h 1
|
||||
|
||||
#include <tracepoint/tracepoint-state.h>
|
||||
#include <sys/uio.h> // struct iovec
|
||||
#include <eventheader/eventheader.h>
|
||||
|
||||
/*
|
||||
Read-only event info, typically a const static/global for each event.
|
||||
Caller must provide one for each event, initialized to metadata for the
|
||||
event and with a pointer to the state for the event.
|
||||
*/
|
||||
typedef struct eventheader_tracepoint {
|
||||
tracepoint_state* state;
|
||||
eventheader_extension const* metadata;
|
||||
eventheader header;
|
||||
uint64_t keyword;
|
||||
} eventheader_tracepoint;
|
||||
|
||||
/*
|
||||
Read-only provider info, typically a const static/global for each provider.
|
||||
Caller must provide one for each provider, initialized to metadata for the
|
||||
provider and with a pointer to the state for the provider.
|
||||
*/
|
||||
typedef struct eventheader_provider {
|
||||
tracepoint_provider_state* state;
|
||||
|
||||
/*
|
||||
Nul-terminated provider options string. May be "" or NULL if none.
|
||||
|
||||
The options string contains 0 or more options, ordered by option type
|
||||
(e.g. option "Gvalue" would come before option "Hvalue").
|
||||
|
||||
Each option is an uppercase ASCII letter (option type) followed by 0 or
|
||||
more ASCII digits or **lowercase** ASCII letters (option value), e.g.
|
||||
"Gmygroupname".
|
||||
|
||||
Recognized option types:
|
||||
- 'G' = provider group name, e.g. "Gmygroupname".
|
||||
|
||||
Total strlen(name + "_" + level + keyword + options) must be less than
|
||||
EVENTHEADER_NAME_MAX (256).
|
||||
*/
|
||||
char const* options;
|
||||
|
||||
/*
|
||||
Nul-terminated provider name string.
|
||||
|
||||
Provider Name may not contain ' ' or ':' characters.
|
||||
|
||||
Some decoding tools (e.g. tracefs) might impose additional restrictions on
|
||||
provider name. For best compatibility, use only ASCII identifier characters
|
||||
[A-Za-z0-9_] in provider names.
|
||||
|
||||
Total strlen(name + "_" + level + keyword + options) must be less than
|
||||
EVENTHEADER_NAME_MAX (256).
|
||||
*/
|
||||
char const* name;
|
||||
|
||||
} eventheader_provider;
|
||||
|
||||
enum {
|
||||
// 1. For use by tracepoint_write
|
||||
// 2. header + activity_id
|
||||
EVENTHEADER_PREFIX_DATAVEC_COUNT_NO_METADATA = 2,
|
||||
|
||||
// 1. For use by tracepoint_write
|
||||
// 2. header + activity_id
|
||||
// 3. header extension block (metadata)
|
||||
EVENTHEADER_PREFIX_DATAVEC_COUNT = 3
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
/*
|
||||
Closes the specified provider. Calling Close on an already-closed provider
|
||||
is a safe no-op.
|
||||
*/
|
||||
void
|
||||
eventheader_close_provider(
|
||||
eventheader_provider const* pProvider);
|
||||
|
||||
/*
|
||||
Opens the specified provider.
|
||||
|
||||
- Returns 0 for success, errno otherwise. Result is primarily for
|
||||
debugging/diagnostics and is usually ignored for production code.
|
||||
|
||||
PRECONDITION:
|
||||
|
||||
- It is an error to call Open(pProvider) while Open or Close for that
|
||||
pProvider is running on another thread.
|
||||
- It is an error to call Open(pProvider) on a pProvider that is already
|
||||
open.
|
||||
*/
|
||||
int
|
||||
eventheader_open_provider(
|
||||
eventheader_provider const* pProvider);
|
||||
|
||||
/*
|
||||
Opens the specified provider and connects the specified events.
|
||||
|
||||
- Returns 0 for success, errno otherwise. Result is primarily for
|
||||
debugging/diagnostics and is usually ignored for production code.
|
||||
- This function is intended for use when the caller is using
|
||||
__attribute__(section) to generate the event list. It sorts and
|
||||
de-duplicates the list (moving NULLs to the end), then initializes events
|
||||
starting at pEventsStart and stopping at pEventsStop or NULL, whichever
|
||||
comes first.
|
||||
|
||||
PRECONDITION:
|
||||
|
||||
- It is an error to call Open(pProvider) while Open or Close for that
|
||||
pProvider is running on another thread.
|
||||
- It is an error to call Open(pProvider) on a pProvider that is already
|
||||
open.
|
||||
*/
|
||||
int
|
||||
eventheader_open_provider_with_events(
|
||||
eventheader_provider const* pProvider,
|
||||
eventheader_tracepoint const** pEventsStart,
|
||||
eventheader_tracepoint const** pEventsStop);
|
||||
|
||||
/*
|
||||
Opens the specified event and associates it with the specified provider.
|
||||
Returns 0 for success, errno for failure. In case of failure, the event
|
||||
state is unchanged.
|
||||
|
||||
Call eventheader_connect(pEvent, NULL) to disconnect an event.
|
||||
*/
|
||||
int
|
||||
eventheader_connect(
|
||||
eventheader_tracepoint const* pEvent,
|
||||
eventheader_provider const* pProvider);
|
||||
|
||||
/*
|
||||
Writes an event. Safe no-op if event is disabled.
|
||||
|
||||
- Returns 0 for success, EBADF if event is disabled, errno for error.
|
||||
Result is primarily for debugging/diagnostics and is usually ignored
|
||||
for production code.
|
||||
- If pActivityId is not NULL, event will have an activity_id extension.
|
||||
- If pEvent->metadata is not NULL, event will have a extension with the
|
||||
data from pEvent->metadata.
|
||||
|
||||
PRECONDITION:
|
||||
|
||||
- The ActivityId parameters must either be NULL or must point at 16-byte
|
||||
IDs.
|
||||
- If pActivityId is NULL then pRelatedActivityId must be NULL.
|
||||
- If pEvent->metadata is not NULL then the first
|
||||
EVENTHEADER_PREFIX_DATAVEC_COUNT iovecs will be used for event headers,
|
||||
so dataCount must be >= EVENTHEADER_PREFIX_DATAVEC_COUNT. Event payload
|
||||
(if any) should start at dataVecs[EVENTHEADER_PREFIX_DATAVEC_COUNT].
|
||||
- If pEvent->metadata is NULL then the first
|
||||
EVENTHEADER_PREFIX_DATAVEC_COUNT_NO_METADATA iovecs will be used for
|
||||
event headers, so dataCount must be >=
|
||||
EVENTHEADER_PREFIX_DATAVEC_COUNT_NO_METADATA. Event payload (if any)
|
||||
should start at dataVecs[EVENTHEADER_PREFIX_DATAVEC_COUNT_NO_METADATA].
|
||||
|
||||
Implementation details:
|
||||
|
||||
- Always: dataVecs[0] will be populated with the event's write_index.
|
||||
- Always: dataVecs[1] will be populated with headers.
|
||||
- Always: eventheader.
|
||||
- If pActivityId != NULL: eventheader_extension + activity ids.
|
||||
- If pEvent->metadata != NULL: dataVecs[2] will be populated with the
|
||||
header extension block from pEvent->metadata.
|
||||
- Remaining dataVecs (if any) are populated by caller (event payload).
|
||||
- If you have header extensions in the payload:
|
||||
- If pEvent->metadata == NULL: set pEvent->header.flags's extension bit.
|
||||
- If pEvent->metadata != NULL: set pEvent->metadata.kind's chain bit.
|
||||
*/
|
||||
int
|
||||
eventheader_write(
|
||||
eventheader_tracepoint const* pEvent,
|
||||
void const* pActivityId,
|
||||
void const* pRelatedActivityId,
|
||||
uint32_t dataCount,
|
||||
struct iovec* dataVecs);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // _included_eventheader_tracepoint_h
|
680
src/native/external/LinuxTracepoints/libeventheader-tracepoint/include/eventheader/eventheader.h
vendored
Normal file
680
src/native/external/LinuxTracepoints/libeventheader-tracepoint/include/eventheader/eventheader.h
vendored
Normal file
|
@ -0,0 +1,680 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_eventheader_h
|
||||
#define _included_eventheader_h 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define EVENTHEADER_LITTLE_ENDIAN 1
|
||||
#else // _WIN32
|
||||
#include <endian.h>
|
||||
#define EVENTHEADER_LITTLE_ENDIAN (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||
#endif // _WIN32
|
||||
|
||||
/*--EventHeader Events--------------------------------------------------------
|
||||
|
||||
EventHeader is a tracing convention layered on top of Linux Tracepoints.
|
||||
|
||||
To reduce the number of unique Tracepoint names tracked by the kernel, we
|
||||
use a small number of Tracepoints to manage a larger number of events. All
|
||||
events with the same attributes (provider name, severity level, category
|
||||
keyword, etc.) will share one Tracepoint.
|
||||
|
||||
- This means we cannot enable/disable events individually. Instead, all events
|
||||
with similar attributes will be enabled/disabled as a group.
|
||||
- This means we cannot rely on the kernel's Tracepoint metadata for event
|
||||
identity or event field names/types. Instead, all events contain a common
|
||||
header that provides event identity, core event attributes, and support for
|
||||
optional event attributes. The kernel's Tracepoint metadata is used only for
|
||||
the Tracepoint's name and to determine whether the event follows the
|
||||
EventHeader conventions.
|
||||
|
||||
We define a naming scheme to be used for the shared Tracepoints:
|
||||
|
||||
TracepointName = ProviderName + '_' + 'L' + EventLevel + 'K' + EventKeyword +
|
||||
[Options]
|
||||
|
||||
We define a common event layout to be used by all EventHeader events. The
|
||||
event has a header, optional header extensions, and then the event data:
|
||||
|
||||
Event = eventheader + [HeaderExtensions] + Data
|
||||
|
||||
We define a format to be used for header extensions:
|
||||
|
||||
HeaderExtension = eventheader_extension + ExtensionData
|
||||
|
||||
We define a header extension to be used for activity IDs.
|
||||
|
||||
We define a header extension to be used for event metadata (event name, field
|
||||
names, field types).
|
||||
|
||||
For use in the event metadata extension, we define a field type system that
|
||||
supports scalar, string, binary, array, and struct.
|
||||
|
||||
Note that we assume that the Tracepoint name corresponding to the event is
|
||||
available during event decoding. The event decoder obtains the provider name
|
||||
and keyword for an event by parsing the event's Tracepoint name.
|
||||
|
||||
--Provider Names--------------------------------------------------------------
|
||||
|
||||
A provider is a component that generates events. Each event from a provider is
|
||||
associated with a Provider Name that uniquely identifies the provider.
|
||||
|
||||
The provider name should be short, yet descriptive enough to minimize the
|
||||
chance of collision and to help developers track down the component generating
|
||||
the events. Hierarchical namespaces may be useful for provider names, e.g.
|
||||
"MyCompany_MyOrg_MyComponent".
|
||||
|
||||
Restrictions:
|
||||
|
||||
- ProviderName may not contain ' ' or ':' characters.
|
||||
- strlen(ProviderName + '_' + Attributes) must be less than
|
||||
EVENTHEADER_NAME_MAX (256) characters.
|
||||
- Some event APIs (e.g. tracefs) might impose additional restrictions on
|
||||
tracepoint names. For best compatibility, use only ASCII identifier
|
||||
characters [A-Za-z0-9_] in provider names.
|
||||
|
||||
Event attribute semantics should be consistent within a given provider. While
|
||||
some event attributes have generally-accepted semantics (e.g. level value 3
|
||||
is defined below as "warning"), the precise semantics of the attribute values
|
||||
are defined at the scope of a provider (e.g. different providers will use
|
||||
different criteria for what constitutes a warning). In addition, some
|
||||
attributes (tag, keyword) are completely provider-defined. All events with a
|
||||
particular provider name should use consistent semantics for all attributes
|
||||
(e.g. keyword bit 0x1 should have a consistent meaning for all events from a
|
||||
particular provider but will mean something different for other providers).
|
||||
|
||||
--Tracepoint Names------------------------------------------------------------
|
||||
|
||||
A Tracepoint is registered with the kernel for each unique combination of
|
||||
ProviderName + Attributes. This allows a larger number of distinct events to
|
||||
be controlled by a smaller number of kernel Tracepoints while still allowing
|
||||
events to be enabled/disabled at a reasonable granularity.
|
||||
|
||||
The Tracepoint name for an EventHeader event is defined as:
|
||||
|
||||
ProviderName + '_' + 'L' + eventLevel + 'K' + eventKeyword + [Options]
|
||||
or printf("%s_L%xK%lx%s", providerName, eventLevel, eventKeyword, options),
|
||||
e.g. "MyProvider_L3K2a" or "OtherProvider_L5K0Gperf".
|
||||
|
||||
Event level is a uint8 value 1..255 indicating event severity, formatted as
|
||||
lowercase hexadecimal, e.g. printf("L%x", eventLevel). The defined level values
|
||||
are: 1 = critical error, 2 = error, 3 = warning, 4 = information, 5 = verbose.
|
||||
|
||||
Event keyword is a uint64 bitmask indicating event category membership,
|
||||
formatted as lowercase hexadecimal, e.g. printf("K%lx", eventKeyword). Each
|
||||
bit in the keyword corresponds to a provider-defined category, e.g. a provider
|
||||
might define 0x2 = networking and 0x4 = I/O so that keyword value of 0x2|0x4 =
|
||||
0x6 would indicate that an event is in both the networking and I/O categories.
|
||||
|
||||
Options (optional attributes) can be specified after the keyword attribute.
|
||||
Each option consists of an uppercase ASCII letter (option type) followed by 0
|
||||
or more ASCII digits or lowercase ASCII letters (option value). To support
|
||||
consistent event names, the options must be sorted in alphabetical order, e.g.
|
||||
"Aoption" should come before "Boption".
|
||||
|
||||
The currently defined options are:
|
||||
|
||||
- 'G' = provider Group name. Defines a group of providers. This can be used by
|
||||
event analysis tools to find all providers that generate a certain kind of
|
||||
information.
|
||||
|
||||
Restrictions:
|
||||
|
||||
- ProviderName may not contain ' ' or ':' characters.
|
||||
- Tracepoint name must be less than EVENTHEADER_NAME_MAX (256)
|
||||
characters in length.
|
||||
- Some event APIs (e.g. tracefs) might impose additional restrictions on
|
||||
tracepoint names. For best compatibility, use only ASCII identifier
|
||||
characters [A-Za-z0-9_] in provider names.
|
||||
|
||||
--Header-----------------------------------------------------------------------
|
||||
|
||||
Because multiple events may share a single Tracepoint, each event must contain
|
||||
information to distinguish it from other events. To enable this, each event
|
||||
starts with an EventHeader structure which contains information about the
|
||||
event:
|
||||
|
||||
- flags: Bits indicating pointer size (32 or 64 bits), byte order
|
||||
(big-endian or little), and whether any header extensions are present.
|
||||
- opcode: Indicates special event semantics e.g. "normal event",
|
||||
"activity start event", "activity end event".
|
||||
- tag: Provider-defined 16-bit value. Can be used for anything.
|
||||
- id: 16-bit stable event identifier, or 0 if no identifier is assigned.
|
||||
- version: 8-bit event version, incremented for e.g. field type changes.
|
||||
- level: 8-bit event severity level, 1 = critical .. 5 = verbose.
|
||||
(level value in event header must match the level in the Tracepoint name.)
|
||||
|
||||
If the extension flag is not set, the header is immediately followed by the
|
||||
event payload.
|
||||
|
||||
If the extension flag is set, the header is immediately followed by one or more
|
||||
header extensions. Each header extension has a 16-bit size, a 15-bit type code,
|
||||
and a 1-bit flag indicating whether another header extension follows the
|
||||
current extension. The final header extension is immediately followed by the
|
||||
event payload.
|
||||
|
||||
The following header extensions are defined:
|
||||
|
||||
- Activity ID: Contains a 128-bit ID that can be used to correlate events. May
|
||||
also contain the 128-bit ID of the parent activity (typically used only for
|
||||
the first event of an activity).
|
||||
- Metadata: Contains the event's metadata: event name, event attributes, field
|
||||
names, field attributes, and field types. Both simple (e.g. Int32, HexInt16,
|
||||
Float64, Char32, Uuid) and complex (e.g. NulTerminatedString8,
|
||||
CountedString16, Binary, Struct, Array) types are supported.
|
||||
*/
|
||||
|
||||
/*
|
||||
eventheader struct: Core metadata for an EventHeader event.
|
||||
|
||||
Each EventHeader event starts with an instance of the eventheader structure.
|
||||
It contains core information recorded for every event to help with event
|
||||
identification, filtering, and decoding.
|
||||
|
||||
If eventheader.flags has the extension bit set then the eventheader is followed
|
||||
by one or more eventheader_extension blocks. Otherwise the eventheader is
|
||||
followed by the event payload data.
|
||||
|
||||
If eventheader_extension.kind has the chain flag set then the
|
||||
eventheader_extension block is followed immediately (no alignment/padding) by
|
||||
another extension block. Otherwise it is followed immediately (no
|
||||
alignment/padding) by the event payload data.
|
||||
|
||||
If there is a Metadata extension then it contains the event name, field names,
|
||||
and field types needed to decode the payload data. Otherwise, the payload
|
||||
decoding system is defined externally, i.e. you will use the provider name to
|
||||
find the appropriate decoding manifest, then use the event's id+version to
|
||||
find the decoding information within the manifest, then use that decoding
|
||||
information to decode the event payload data.
|
||||
|
||||
For a particular event definition (i.e. for a particular event name, or for a
|
||||
particular nonzero event id+version), the information in the eventheader (and
|
||||
in the Metadata extension, if present) should be constant. For example, instead
|
||||
of having a single event with a runtime-variable level, you should have a
|
||||
distinct event definition (with distinct event name and/or distinct event id)
|
||||
for each level.
|
||||
*/
|
||||
typedef struct eventheader {
|
||||
uint8_t flags; // eventheader_flags: pointer64, little_endian, extension.
|
||||
uint8_t version; // If id != 0 then increment version when event layout changes.
|
||||
uint16_t id; // Stable id for this event, or 0 if none.
|
||||
uint16_t tag; // Provider-defined event tag, or 0 if none.
|
||||
uint8_t opcode; // event_opcode: info, start activity, stop activity, etc.
|
||||
uint8_t level; // event_level: critical, error, warning, info, verbose.
|
||||
// Followed by: eventheader_extension block(s), then event payload.
|
||||
} eventheader;
|
||||
|
||||
/*
|
||||
Type string for use in the DIAG_IOCSREG command string.
|
||||
Use EVENTHEADER_FORMAT_COMMAND to generate the full command string.
|
||||
*/
|
||||
#define EVENTHEADER_COMMAND_TYPES "u8 eventheader_flags; u8 version; u16 id; u16 tag; u8 opcode; u8 level"
|
||||
|
||||
/*
|
||||
eventheader_flags enum: Values for eventheader.flags.
|
||||
*/
|
||||
typedef enum eventheader_flags {
|
||||
eventheader_flag_none = 0, // Pointer-32, big-endian, no extensions.
|
||||
eventheader_flag_pointer64 = 0x01, // Pointer is 64 bits, not 32 bits.
|
||||
eventheader_flag_little_endian = 0x02, // Event uses little-endian, not big-endian.
|
||||
eventheader_flag_extension = 0x04, // There is at least one eventheader_extension block.
|
||||
|
||||
// Pointer-size and byte-order as appropriate for the target, no
|
||||
// eventheader_extension blocks present.
|
||||
eventheader_flag_default = 0
|
||||
| (EVENTHEADER_LITTLE_ENDIAN ? eventheader_flag_little_endian : 0)
|
||||
| (sizeof(void*) == 8 ? eventheader_flag_pointer64 : 0),
|
||||
|
||||
// Pointer-size and byte-order as appropriate for the target, one or more
|
||||
// eventheader_extension blocks present.
|
||||
eventheader_flag_default_with_extension = eventheader_flag_default | eventheader_flag_extension,
|
||||
} eventheader_flags;
|
||||
|
||||
/*
|
||||
event_opcode enum: Values for eventheader.opcode. Special semantics for events.
|
||||
|
||||
Most events set opcode = info (0). Other opcode values add special semantics to
|
||||
an event that help the event analysis tool with grouping related events. The
|
||||
most frequently-used special semantics are activity-start and activity-stop.
|
||||
|
||||
To record an activity:
|
||||
|
||||
- Generate a new activity id. An activity id is a 128-bit value that must be
|
||||
unique within the trace. This can be a UUID or it can be generated by any
|
||||
other id-generation system that is unlikely to create the same value for any
|
||||
other activity id in the same trace.
|
||||
- Write an event with opcode = activity_start and with an ActivityId header
|
||||
extension. The ActivityId extension should have the newly-generated activity
|
||||
id, followed by the id of a parent activity (if any). If there is a parent
|
||||
activity, the extension length will be 32; otherwise it will be 16.
|
||||
- As appropriate, write any number of normal events (events with opcode set to
|
||||
something other than activity_start or activity_stop, e.g. opcode = info). To
|
||||
indicate that the events are part of the activity, each of these events
|
||||
should have an ActivityId header extension with the new activity id
|
||||
(extension length will be 16).
|
||||
- When the activity ends, write an event with opcode = activity_stop and with
|
||||
an ActivityId header extension containing the activity id of the activity
|
||||
that is ending (extension length will be 16).
|
||||
*/
|
||||
typedef enum event_opcode {
|
||||
event_opcode_info = 0, // Normal informational event.
|
||||
event_opcode_activity_start, // Begins an activity (the first event to use a particular activity id).
|
||||
event_opcode_activity_stop, // Ends an activity (the last event to use the particular activity id).
|
||||
event_opcode_collection_start,
|
||||
event_opcode_collection_stop,
|
||||
event_opcode_extension,
|
||||
event_opcode_reply,
|
||||
event_opcode_resume,
|
||||
event_opcode_suspend,
|
||||
event_opcode_send,
|
||||
event_opcode_receive = 0xf0,
|
||||
} event_opcode;
|
||||
|
||||
/*
|
||||
event_level enum: Values for eventheader.level.
|
||||
|
||||
0 is not a valid level. Values greater than 5 are permitted but are not
|
||||
well-defined.
|
||||
*/
|
||||
typedef enum event_level {
|
||||
event_level_invalid = 0,
|
||||
event_level_critical_error,
|
||||
event_level_error,
|
||||
event_level_warning,
|
||||
event_level_information,
|
||||
event_level_verbose,
|
||||
} event_level;
|
||||
|
||||
/*
|
||||
eventheader_extension struct: Optional information about an EventHeader event.
|
||||
|
||||
If eventheader.flags has the extension bit set then the eventheader is
|
||||
followed by one or more eventheader_extension blocks. Otherwise the eventheader
|
||||
is followed by the event payload data.
|
||||
|
||||
If eventheader_extension.kind has the chain flag set then the
|
||||
eventheader_extension block is followed immediately (no alignment/padding) by
|
||||
another extension block. Otherwise it is followed immediately (no
|
||||
alignment/padding) by the event payload data.
|
||||
*/
|
||||
typedef struct eventheader_extension {
|
||||
uint16_t size;
|
||||
uint16_t kind; // eventheader_extension_kind
|
||||
// Followed by size bytes of data. No padding/alignment.
|
||||
} eventheader_extension;
|
||||
|
||||
/*
|
||||
eventheader_extension_kind enum: Values for eventheader_extension.kind.
|
||||
*/
|
||||
typedef enum eventheader_extension_kind {
|
||||
eventheader_extension_kind_value_mask = 0x7FFF,
|
||||
|
||||
/*
|
||||
If not set, this is the last extension block (event payload data follows).
|
||||
If set, this is not the last extension block (another extension block
|
||||
follows).
|
||||
*/
|
||||
eventheader_extension_kind_chain_flag = 0x8000,
|
||||
|
||||
/*
|
||||
Invalid extension kind.
|
||||
*/
|
||||
eventheader_extension_kind_invalid = 0,
|
||||
|
||||
/*
|
||||
Extension contains an event definition (i.e. event metadata).
|
||||
|
||||
Event definition format:
|
||||
|
||||
- char event_name[]; // Nul-terminated utf-8 string: "eventName{;attribName=attribValue}"
|
||||
- 0 or more field definition blocks, tightly-packed (no padding).
|
||||
|
||||
Field definition block:
|
||||
|
||||
- char field_name[]; // Nul-terminated utf-8 string: "fieldName{;attribName=attribValue}"
|
||||
- uint8_t encoding; // encoding is 0..31, with 3 flag bits.
|
||||
- uint8_t format; // Present if 0 != (encoding & 128). format is 0..127, with 1 flag bit.
|
||||
- uint16_t tag; // Present if 0 != (format & 128). Contains provider-defined value.
|
||||
- uint16_t array_length; // Present if 0 != (encoding & 32). Contains element count of constant-length array.
|
||||
|
||||
Notes:
|
||||
|
||||
- event_name and field_name may not contain any ';' characters.
|
||||
- event_name and field_name may be followed by attribute strings.
|
||||
- attribute string is: ';' + attribName + '=' + attribValue.
|
||||
- attribName may not contain any ';' or '=' characters.
|
||||
- Semicolons in attribValue must be escaped by doubling, e.g.
|
||||
"my;value" is escaped as "my;;value".
|
||||
- array_length may not be 0, i.e. constant-length arrays may not be empty.
|
||||
*/
|
||||
eventheader_extension_kind_metadata,
|
||||
|
||||
/*
|
||||
Extension contains activity id information.
|
||||
|
||||
Any event that is part of an activity has an ActivityId extension.
|
||||
|
||||
- Activity is started by an event with opcode = activity_start. The
|
||||
ActivityId extension for the start event must contain a newly-generated
|
||||
activity id and may optionally contain the parent activity id.
|
||||
- Activity may contain any number of normal events (opcode something other
|
||||
than activity_start or activity_stop). The ActivityId extension for each
|
||||
normal event must contain the id of the associated activity (otherwise
|
||||
it is not considered to be part of the activity).
|
||||
- Activity is ended by an event with opcode = activity_stop. The ActivityId
|
||||
extension for the stop event must contain the id of the activity that is
|
||||
ending.
|
||||
|
||||
An activity id is a 128-bit value that is unique within this trace
|
||||
session. It may be a UUID. Since UUID generation can be non-trivial, this
|
||||
may also be a 128-bit LUID (locally-unique id) generated using any method
|
||||
that is unlikely to conflict with any other activity ids in the same trace.
|
||||
|
||||
If extension.size == 16 then value is a 128-bit activity id.
|
||||
|
||||
If extension.size == 32 then value is a 128-bit activity id followed by a
|
||||
128-bit related (parent) activity id.
|
||||
*/
|
||||
eventheader_extension_kind_activity_id,
|
||||
} eventheader_extension_kind;
|
||||
|
||||
/*
|
||||
event_field_encoding enum: Values for the encoding byte of a field definition.
|
||||
|
||||
The low 5 bits of the encoding byte contain the field's encoding. The encoding
|
||||
indicates how a decoder should determine the size of the field. It also
|
||||
indicates a default format behavior that should be used if the field has no
|
||||
format specified or if the specified format is 0, unrecognized, or unsupported.
|
||||
|
||||
The top 3 bits of the field encoding byte are flags:
|
||||
|
||||
- carray_flag indicates that this field is a constant-length array, with the
|
||||
element count specified as a 16-bit value in the event metadata. (The
|
||||
element count must not be 0, i.e. constant-length arrays may not be empty.)
|
||||
- varray_flag indicates that this field is a variable-length array, with the
|
||||
element count specified as a 16-bit value in the event payload (immediately
|
||||
before the array elements, may be 0).
|
||||
- chain_flag indicates that a format byte is present after the encoding byte.
|
||||
If chain_flag is not set, the format byte is omitted and is assumed to be 0.
|
||||
|
||||
Setting both carray_flag and varray_flag is invalid (reserved).
|
||||
*/
|
||||
typedef enum event_field_encoding {
|
||||
// Mask for the encoding types.
|
||||
event_field_encoding_value_mask = 0x1F,
|
||||
|
||||
// Mask for the encoding flags.
|
||||
event_field_encoding_flag_mask = 0xE0,
|
||||
|
||||
// Flag indicating that the field is a constant-length array, with a 16-bit
|
||||
// element count in the event metadata (must not be 0).
|
||||
event_field_encoding_carray_flag = 0x20,
|
||||
|
||||
// Flag indicating that the field is a variable-length array, with a 16-bit
|
||||
// element count in the payload immediately before the elements (may be 0).
|
||||
event_field_encoding_varray_flag = 0x40,
|
||||
|
||||
// Flag indicating that an event_field_format byte follows the
|
||||
// event_field_encoding byte.
|
||||
event_field_encoding_chain_flag = 0x80,
|
||||
|
||||
// Invalid encoding value.
|
||||
event_field_encoding_invalid = 0,
|
||||
|
||||
// 0-byte value, logically groups subsequent N fields, N = (format & 0x7F),
|
||||
// N must not be 0 (empty structs are not allowed).
|
||||
event_field_encoding_struct,
|
||||
|
||||
// 1-byte value, default format unsigned_int.
|
||||
//
|
||||
// Usable formats: unsigned_int, signed_int, hex_int, boolean, hex_bytes,
|
||||
// string8.
|
||||
event_field_encoding_value8,
|
||||
|
||||
// 2-byte value, default format unsigned_int.
|
||||
//
|
||||
// Usable formats: unsigned_int, signed_int, hex_int, boolean, hex_bytes,
|
||||
// string_utf, port.
|
||||
event_field_encoding_value16,
|
||||
|
||||
// 4-byte value, default format unsigned_int.
|
||||
//
|
||||
// Usable formats: unsigned_int, signed_int, hex_int, errno, pid, time,
|
||||
// boolean, float, hex_bytes, string_utf, IPv4.
|
||||
event_field_encoding_value32,
|
||||
|
||||
// 8-byte value, default format unsigned_int.
|
||||
//
|
||||
// Usable formats: unsigned_int, signed_int, hex_int, time, float,
|
||||
// hex_bytes.
|
||||
event_field_encoding_value64,
|
||||
|
||||
// 16-byte value, default format hex_bytes.
|
||||
//
|
||||
// Usable formats: hex_bytes, uuid, ipv6.
|
||||
event_field_encoding_value128,
|
||||
|
||||
// zero-terminated uint8[], default format string_utf.
|
||||
//
|
||||
// Usable formats: hex_bytes, string8, string_utf, string_utf_bom,
|
||||
// string_xml, string_json.
|
||||
event_field_encoding_zstring_char8,
|
||||
|
||||
// zero-terminated uint16[], default format string_utf.
|
||||
//
|
||||
// Usable formats: hex_bytes, string_utf, string_utf_bom, string_xml,
|
||||
// string_json.
|
||||
event_field_encoding_zstring_char16,
|
||||
|
||||
// zero-terminated uint32[], default format string_utf.
|
||||
//
|
||||
// Usable formats: hex_bytes, string_utf, string_utf_bom, string_xml,
|
||||
// string_json.
|
||||
event_field_encoding_zstring_char32,
|
||||
|
||||
// uint16 Length followed by uint8 Data[Length], default format string_utf.
|
||||
// Also used for binary data (format hex_bytes).
|
||||
//
|
||||
// Usable formats: hex_bytes, String8, string_utf, string_utf_bom,
|
||||
// string_xml, string_json.
|
||||
event_field_encoding_string_length16_char8,
|
||||
|
||||
// uint16 Length followed by uint16 Data[Length], default format
|
||||
// string_utf.
|
||||
//
|
||||
// Usable formats: hex_bytes, string_utf, string_utf_bom, string_xml,
|
||||
// string_json.
|
||||
event_field_encoding_string_length16_char16,
|
||||
|
||||
// uint16 Length followed by uint32 Data[Length], default format
|
||||
// string_utf.
|
||||
//
|
||||
// Usable formats: hex_bytes, string_utf, string_utf_bom, string_xml,
|
||||
// string_json.
|
||||
event_field_encoding_string_length16_char32,
|
||||
|
||||
// Invalid encoding value. Value will change in future versions of this
|
||||
// header.
|
||||
event_field_encoding_max,
|
||||
|
||||
// long-sized value, default format unsigned_int.
|
||||
// This is an alias for either value32 or value64.
|
||||
//
|
||||
// Usable formats: unsigned_int, signed_int, hex_int, Time, Float,
|
||||
// hex_bytes.
|
||||
event_field_encoding_value_long =
|
||||
sizeof(long) == 4 ? event_field_encoding_value32 :
|
||||
sizeof(long) == 8 ? event_field_encoding_value64 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
// pointer-sized value, default format unsigned_int.
|
||||
// This is an alias for either value32 or value64.
|
||||
//
|
||||
// Usable formats: unsigned_int, signed_int, hex_int, Time, Float,
|
||||
// hex_bytes.
|
||||
event_field_encoding_value_ptr =
|
||||
sizeof(void*) == 4 ? event_field_encoding_value32 :
|
||||
sizeof(void*) == 8 ? event_field_encoding_value64 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
// float-sized value, default format unsigned_int. (To treat as float,
|
||||
// use event_field_format_float.)
|
||||
//
|
||||
// This is an alias for either value32 or value64.
|
||||
event_field_encoding_value_float =
|
||||
sizeof(float) == 4 ? event_field_encoding_value32 :
|
||||
sizeof(float) == 8 ? event_field_encoding_value64 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
// double-sized value, default format unsigned_int. (To treat as float,
|
||||
// use event_field_format_float.)
|
||||
//
|
||||
// This is an alias for either value32 or value64.
|
||||
event_field_encoding_value_double =
|
||||
sizeof(double) == 4 ? event_field_encoding_value32 :
|
||||
sizeof(double) == 8 ? event_field_encoding_value64 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
// wchar-sized value, default format unsigned_int. (To treat as char, use
|
||||
// event_field_format_string_utf.)
|
||||
//
|
||||
// This is an alias for either value16 or value32.
|
||||
event_field_encoding_value_wchar =
|
||||
sizeof(wchar_t) == 2 ? event_field_encoding_value16 :
|
||||
sizeof(wchar_t) == 4 ? event_field_encoding_value32 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
// zero-terminated wchar_t[], default format string_utf.
|
||||
//
|
||||
// This is an alias for either zstring_char16 or zstring_char32.
|
||||
event_field_encoding_zstring_wchar =
|
||||
sizeof(wchar_t) == 2 ? event_field_encoding_zstring_char16 :
|
||||
sizeof(wchar_t) == 4 ? event_field_encoding_zstring_char32 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
// uint16 Length followed by uint16 Data[Length], default format
|
||||
// string_utf.
|
||||
//
|
||||
// This is an alias for either string_length16_char16 or
|
||||
// string_length16_char32.
|
||||
event_field_encoding_string_length16_wchar =
|
||||
sizeof(wchar_t) == 2 ? event_field_encoding_string_length16_char16 :
|
||||
sizeof(wchar_t) == 4 ? event_field_encoding_string_length16_char32 :
|
||||
event_field_encoding_invalid,
|
||||
|
||||
} event_field_encoding;
|
||||
|
||||
#if defined(__cplusplus) || defined(static_assert)
|
||||
static_assert(event_field_encoding_max <= event_field_encoding_carray_flag, "Too many encodings.");
|
||||
static_assert(event_field_encoding_invalid != event_field_encoding_value_long, "Unsupported sizeof(long).");
|
||||
static_assert(event_field_encoding_invalid != event_field_encoding_value_ptr, "Unsupported sizeof(void*).");
|
||||
static_assert(event_field_encoding_invalid != event_field_encoding_value_float, "Unsupported sizeof(float).");
|
||||
static_assert(event_field_encoding_invalid != event_field_encoding_value_double, "Unsupported sizeof(double).");
|
||||
static_assert(event_field_encoding_invalid != event_field_encoding_value_wchar, "Unsupported sizeof(wchar_t).");
|
||||
#endif
|
||||
|
||||
/*
|
||||
event_field_format enum: Values for the format byte of a field definition.
|
||||
|
||||
The low 7 bits of the format byte contain the field's format.
|
||||
In the case of the Struct encoding, the low 7 bits of the format byte contain
|
||||
the number of logical fields in the struct (which must not be 0).
|
||||
|
||||
The top bit of the field format byte is the FlagChain. If set, it indicates
|
||||
that a field tag (uint16) is present after the format byte. If not set, the
|
||||
field tag is not present and is assumed to be 0.
|
||||
*/
|
||||
typedef enum event_field_format {
|
||||
event_field_format_value_mask = 0x7F,
|
||||
event_field_format_chain_flag = 0x80, // A field tag (uint16) follows the format byte.
|
||||
|
||||
event_field_format_default = 0, // Use the default format of the encoding.
|
||||
event_field_format_unsigned_int, // unsigned integer, event byte order. Use with Value8..Value64 encodings.
|
||||
event_field_format_signed_int, // signed integer, event byte order. Use with Value8..Value64 encodings.
|
||||
event_field_format_hex_int, // hex integer, event byte order. Use with Value8..Value64 encodings.
|
||||
event_field_format_errno, // errno, event byte order. Use with Value32 encoding.
|
||||
event_field_format_pid, // process id, event byte order. Use with Value32 encoding.
|
||||
event_field_format_time, // signed integer, event byte order, seconds since 1970. Use with Value32 or Value64 encodings.
|
||||
event_field_format_boolean, // 0 = false, 1 = true, event byte order. Use with Value8..Value32 encodings.
|
||||
event_field_format_float, // floating point, event byte order. Use with Value32..Value64 encodings.
|
||||
event_field_format_hex_bytes, // binary, decoded as hex dump of bytes. Use with any encoding.
|
||||
event_field_format_string8, // 8-bit char string, unspecified character set (usually treated as ISO-8859-1 or CP-1252). Use with Value8 and Char8 encodings.
|
||||
event_field_format_string_utf, // UTF string, event byte order, code unit size based on encoding. Use with Value16..Value32 and Char8..Char32 encodings.
|
||||
event_field_format_string_utf_bom,// UTF string, BOM used if present, otherwise behaves like string_utf. Use with Char8..Char32 encodings.
|
||||
event_field_format_string_xml, // XML string, otherwise behaves like string_utf_bom. Use with Char8..Char32 encodings.
|
||||
event_field_format_string_json, // JSON string, otherwise behaves like string_utf_bom. Use with Char8..Char32 encodings.
|
||||
event_field_format_uuid, // UUID, network byte order (RFC 4122 format). Use with Value128 encoding.
|
||||
event_field_format_port, // IP port, network byte order (in_port_t layout). Use with Value16 encoding.
|
||||
event_field_format_ipv4, // IPv4 address, network byte order (in_addr layout). Use with Value32 encoding.
|
||||
event_field_format_ipv6, // IPv6 address, in6_addr layout. Use with Value128 encoding.
|
||||
} event_field_format;
|
||||
|
||||
enum {
|
||||
// Maximum length of a Tracepoint name "ProviderName_Attributes", including nul termination.
|
||||
EVENTHEADER_NAME_MAX = 256,
|
||||
|
||||
// Maximum length needed for a DIAG_IOCSREG command "ProviderName_Attributes CommandTypes".
|
||||
EVENTHEADER_COMMAND_MAX = EVENTHEADER_NAME_MAX + sizeof(EVENTHEADER_COMMAND_TYPES)
|
||||
};
|
||||
|
||||
/*
|
||||
Macro EVENTHEADER_FORMAT_TRACEPOINT_NAME generates the Tracepoint name for an
|
||||
event, tracepointName = "ProviderName_LnKnnnOptions":
|
||||
|
||||
char tracepointName[EVENTHEADER_NAME_MAX];
|
||||
EVENTHEADER_FORMAT_TRACEPOINT_NAME(
|
||||
tracepointName, sizeof(tracepointName),
|
||||
providerName, eventLevel, eventKeyword, options);
|
||||
|
||||
Returns the value returned by snprintf:
|
||||
- return >= 0 && return < tracepointNameMax indicates success.
|
||||
- return < 0 || return >= tracepointNameMax indicates error.
|
||||
|
||||
Requires: #include <stdio.h>, #include <inttypes.h>
|
||||
*/
|
||||
#define EVENTHEADER_FORMAT_TRACEPOINT_NAME( \
|
||||
tracepointName, tracepointNameMax, providerName, eventLevel, eventKeyword, options) \
|
||||
({ \
|
||||
/* Put arguments into temp vars for type-checking: */ \
|
||||
char const* const _providerName = (providerName); \
|
||||
uint8_t const _eventLevel = (eventLevel); \
|
||||
uint64_t const _eventKeyword = (eventKeyword); \
|
||||
char const* const _options = (options); \
|
||||
snprintf(tracepointName, tracepointNameMax, "%s_L%xK%" PRIx64 "%s", \
|
||||
_providerName, _eventLevel, _eventKeyword, _options ? _options : ""); \
|
||||
}) \
|
||||
|
||||
/*
|
||||
Macro EVENTHEADER_FORMAT_COMMAND generates the DIAG_IOCSREG command string for
|
||||
an event, command = "ProviderName_LnKnnnOptions CommandTypes":
|
||||
|
||||
char command[EVENTHEADER_COMMAND_MAX];
|
||||
EVENTHEADER_FORMAT_COMMAND(
|
||||
command, sizeof(command),
|
||||
providerName, eventLevel, eventKeyword, options);
|
||||
|
||||
Returns the value returned by snprintf:
|
||||
- return >= 0 && return < commandMax indicates success.
|
||||
- return < 0 || return >= commandMax indicates error.
|
||||
|
||||
Requires: #include <stdio.h>, #include <inttypes.h>
|
||||
*/
|
||||
#define EVENTHEADER_FORMAT_COMMAND( \
|
||||
command, commandMax, providerName, eventLevel, eventKeyword, options) \
|
||||
({ \
|
||||
/* Put arguments into temp vars for type-checking: */ \
|
||||
char const* const _providerName = (providerName); \
|
||||
uint8_t const _eventLevel = (eventLevel); \
|
||||
uint64_t const _eventKeyword = (eventKeyword); \
|
||||
char const* const _options = (options); \
|
||||
snprintf(command, commandMax, "%s_L%xK%" PRIx64 "%s %s", \
|
||||
_providerName, _eventLevel, _eventKeyword, _options ? _options : "", \
|
||||
EVENTHEADER_COMMAND_TYPES); \
|
||||
}) \
|
||||
|
||||
#endif // _included_eventheader_h
|
30
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/CMakeLists.txt
vendored
Normal file
30
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
add_executable(eventheader-dynamic-sample
|
||||
dynamic-sample.cpp)
|
||||
target_link_libraries(eventheader-dynamic-sample
|
||||
PUBLIC eventheader-tracepoint tracepoint)
|
||||
target_compile_features(eventheader-dynamic-sample
|
||||
PRIVATE cxx_std_17)
|
||||
|
||||
add_executable(eventheader-sample
|
||||
sample.cpp)
|
||||
target_link_libraries(eventheader-sample
|
||||
PUBLIC eventheader-tracepoint tracepoint)
|
||||
|
||||
add_executable(eventheader-tracepoint-sample
|
||||
tracepoint-sample.cpp
|
||||
TestProviderC.c
|
||||
TestProviderCpp.cpp)
|
||||
target_link_libraries(eventheader-tracepoint-sample
|
||||
PUBLIC eventheader-tracepoint tracepoint)
|
||||
target_compile_features(eventheader-tracepoint-sample
|
||||
PRIVATE cxx_std_17)
|
||||
|
||||
add_executable(eventheader-interceptor-sample
|
||||
interceptor-sample.cpp
|
||||
TestProviderC.c
|
||||
TestProviderCpp.cpp
|
||||
tracepoint-file.cpp)
|
||||
target_link_libraries(eventheader-interceptor-sample
|
||||
PUBLIC eventheader-tracepoint)
|
||||
target_compile_features(eventheader-interceptor-sample
|
||||
PRIVATE cxx_std_17)
|
42
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/TestProviderC.c
vendored
Normal file
42
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/TestProviderC.c
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
#include <stdbool.h>
|
||||
#include <uchar.h>
|
||||
|
||||
#define TestProvider TestProviderC
|
||||
#include "TestProviderCommon.h"
|
||||
|
||||
static bool TestTraceLoggingLangSpecific()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
TestProviderC,
|
||||
"TestProviderC",
|
||||
// {0da7a945-e9b1-510f-0ccf-ab1af0bc095b}
|
||||
(0x0da7a945, 0xe9b1, 0x510f, 0x0c, 0xcf, 0xab, 0x1a, 0xf0, 0xbc, 0x09, 0x5b));
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
TestProviderCG,
|
||||
"TestProviderC",
|
||||
// {0da7a945-e9b1-510f-0ccf-ab1af0bc095b}
|
||||
(0x0da7a945, 0xe9b1, 0x510f, 0x0c, 0xcf, 0xab, 0x1a, 0xf0, 0xbc, 0x09, 0x5b),
|
||||
TraceLoggingOptionGroupName("msft"));
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
bool TestC()
|
||||
{
|
||||
printf("TestProvider Name: %s\n", TraceLoggingProviderName(TestProvider));
|
||||
|
||||
int err = TraceLoggingRegister(TestProviderC);
|
||||
printf("TestProviderC register: %d\n", err);
|
||||
|
||||
bool ok = TestCommon() && TestTraceLoggingLangSpecific();
|
||||
|
||||
TraceLoggingUnregister(TestProviderC);
|
||||
return ok && err == 0;
|
||||
}
|
504
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/TestProviderCommon.h
vendored
Normal file
504
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/TestProviderCommon.h
vendored
Normal file
|
@ -0,0 +1,504 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
bool TestC(void);
|
||||
bool TestCpp(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
TRACELOGGING_DECLARE_PROVIDER(TestProviderC);
|
||||
TRACELOGGING_DECLARE_PROVIDER(TestProviderCG);
|
||||
TRACELOGGING_DECLARE_PROVIDER(TestProviderCpp);
|
||||
TRACELOGGING_DECLARE_PROVIDER(TestProviderCppG);
|
||||
|
||||
static bool TestCommon(void)
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// Validation of C/C++ provider interop.
|
||||
{
|
||||
bool enabled;
|
||||
|
||||
ok = TraceLoggingRegister(TestProviderCG) == 0 && ok;
|
||||
ok = TraceLoggingRegister(TestProviderCppG) == 0 && ok;
|
||||
|
||||
enabled = TraceLoggingProviderEnabled(TestProviderCG, 5, 0);
|
||||
TraceLoggingWrite(TestProviderCG, "EventCG", TraceLoggingBoolean(enabled));
|
||||
|
||||
enabled = TraceLoggingProviderEnabled(TestProviderCppG, 5, 0);
|
||||
TraceLoggingWrite(TestProviderCppG, "EventCppG", TraceLoggingBoolean(enabled));
|
||||
|
||||
TraceLoggingUnregister(TestProviderCG);
|
||||
TraceLoggingUnregister(TestProviderCppG);
|
||||
TraceLoggingUnregister(TestProviderCG);
|
||||
TraceLoggingUnregister(TestProviderCppG);
|
||||
|
||||
enabled = TraceLoggingProviderEnabled(TestProviderCG, 5, 0);
|
||||
TraceLoggingWrite(TestProviderCG, "EventCG", TraceLoggingBoolean(enabled));
|
||||
|
||||
enabled = TraceLoggingProviderEnabled(TestProviderCppG, 5, 0);
|
||||
TraceLoggingWrite(TestProviderCppG, "EventCppG", TraceLoggingBoolean(enabled));
|
||||
}
|
||||
|
||||
const bool b0 = 0;
|
||||
const bool b1 = 1;
|
||||
const uint8_t b8 = 1;
|
||||
const int32_t b32 = 1;
|
||||
const int8_t i8 = 100;
|
||||
const uint8_t u8 = 200;
|
||||
const int16_t i16 = 30000;
|
||||
const uint16_t u16 = 60000;
|
||||
const int32_t i32 = 2000000000;
|
||||
const uint32_t u32 = 4000000000;
|
||||
const long iL = 2000000000;
|
||||
const unsigned long uL = 4000000000;
|
||||
const int64_t i64 = 9000000000000000000;
|
||||
const uint64_t u64 = 18000000000000000000u;
|
||||
const float f32 = 3.14f;
|
||||
const double f64 = 6.28;
|
||||
const char ch = 'A';
|
||||
const char16_t u16ch = u'A';
|
||||
const char32_t u32ch = U'A';
|
||||
const wchar_t wch = L'B';
|
||||
const intptr_t iptr = 1234;
|
||||
const uintptr_t uptr = 4321;
|
||||
char ch10[10] = "HowAreU8?";
|
||||
char16_t u16ch10[10] = u"HowAreU16";
|
||||
char32_t u32ch10[10] = U"HowAreU32";
|
||||
wchar_t wch10[10] = L"Goodbye!!";
|
||||
uint8_t const guid[16] = { 1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
|
||||
void const* const pSamplePtr = (void*)(intptr_t)(-12345);
|
||||
unsigned short n1 = 1;
|
||||
unsigned short n5 = 5;
|
||||
const uint16_t port80 = htons(80);
|
||||
|
||||
const uint8_t ipv4data[] = { 127, 0, 0, 1 };
|
||||
in_addr_t ipv4;
|
||||
memcpy(&ipv4, ipv4data, sizeof(ipv4));
|
||||
|
||||
const uint8_t ipv6data[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
|
||||
struct in6_addr ipv6;
|
||||
memcpy(&ipv6, ipv6data, sizeof(ipv6));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "CScalars1");
|
||||
TraceLoggingWrite(
|
||||
TestProvider,
|
||||
"CScalars2",
|
||||
TraceLoggingLevel(1),
|
||||
TraceLoggingKeyword(0xf123456789abcdef),
|
||||
TraceLoggingOpcode(2));
|
||||
TraceLoggingWrite(
|
||||
TestProvider,
|
||||
"CScalars3",
|
||||
TraceLoggingIdVersion(1000, 11),
|
||||
TraceLoggingLevel(2),
|
||||
TraceLoggingKeyword(0x80),
|
||||
TraceLoggingOpcode(3),
|
||||
TraceLoggingLevel(4),
|
||||
TraceLoggingKeyword(0x05),
|
||||
TraceLoggingEventTag(0x1234),
|
||||
TraceLoggingDescription("Hello"),
|
||||
TraceLoggingStruct(20, "Struct20", "Desc", 0xbeef),
|
||||
TraceLoggingString("hi", "hi", "Descr", 0x12),
|
||||
TraceLoggingCharArray(ch10, 3, "ch10", "Descri", 0x10));
|
||||
|
||||
TraceLoggingWriteActivity(TestProvider, "Transfer00", NULL, NULL);
|
||||
TraceLoggingWriteActivity(TestProvider, "Transfer10", guid, NULL);
|
||||
TraceLoggingWriteActivity(TestProvider, "Transfer11", guid, guid);
|
||||
|
||||
TraceLoggingWrite(TestProvider, "i8", TraceLoggingInt8(i8), TraceLoggingInt8(INT8_MIN));
|
||||
TraceLoggingWrite(TestProvider, "u8", TraceLoggingUInt8(u8), TraceLoggingUInt8(UINT8_MAX));
|
||||
TraceLoggingWrite(TestProvider, "i16", TraceLoggingInt16(i16), TraceLoggingInt16(INT16_MIN));
|
||||
TraceLoggingWrite(TestProvider, "u16", TraceLoggingUInt16(u16), TraceLoggingUInt16(UINT16_MAX));
|
||||
TraceLoggingWrite(TestProvider, "i32", TraceLoggingInt32(i32), TraceLoggingInt32(INT32_MIN));
|
||||
TraceLoggingWrite(TestProvider, "u32", TraceLoggingUInt32(u32), TraceLoggingUInt32(UINT32_MAX));
|
||||
TraceLoggingWrite(TestProvider, "i64", TraceLoggingInt64(i64), TraceLoggingInt64(INT64_MIN));
|
||||
TraceLoggingWrite(TestProvider, "u64", TraceLoggingUInt64(u64), TraceLoggingUInt64(UINT64_MAX));
|
||||
TraceLoggingWrite(TestProvider, "iptr", TraceLoggingIntPtr(iptr), TraceLoggingIntPtr(INTPTR_MIN));
|
||||
TraceLoggingWrite(TestProvider, "uptr", TraceLoggingUIntPtr(uptr), TraceLoggingUIntPtr(UINTPTR_MAX));
|
||||
TraceLoggingWrite(TestProvider, "iL", TraceLoggingLong(iL), TraceLoggingLong(LONG_MIN));
|
||||
TraceLoggingWrite(TestProvider, "uL", TraceLoggingULong(uL), TraceLoggingULong(ULONG_MAX));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "hi8", TraceLoggingHexInt8(i8), TraceLoggingHexInt8(INT8_MIN));
|
||||
TraceLoggingWrite(TestProvider, "hu8", TraceLoggingHexUInt8(u8), TraceLoggingHexUInt8(UINT8_MAX));
|
||||
TraceLoggingWrite(TestProvider, "hi16", TraceLoggingHexInt16(i16), TraceLoggingHexInt16(INT16_MIN));
|
||||
TraceLoggingWrite(TestProvider, "hu16", TraceLoggingHexUInt16(u16), TraceLoggingHexUInt16(UINT16_MAX));
|
||||
TraceLoggingWrite(TestProvider, "hi32", TraceLoggingHexInt32(i32), TraceLoggingHexInt32(INT32_MIN));
|
||||
TraceLoggingWrite(TestProvider, "hu32", TraceLoggingHexUInt32(u32), TraceLoggingHexUInt32(UINT32_MAX));
|
||||
TraceLoggingWrite(TestProvider, "hi64", TraceLoggingHexInt64(i64), TraceLoggingHexInt64(INT64_MIN));
|
||||
TraceLoggingWrite(TestProvider, "hu64", TraceLoggingHexUInt64(u64), TraceLoggingHexUInt64(UINT64_MAX));
|
||||
TraceLoggingWrite(TestProvider, "hiptr", TraceLoggingHexIntPtr(iptr), TraceLoggingHexIntPtr(INTPTR_MIN));
|
||||
TraceLoggingWrite(TestProvider, "huptr", TraceLoggingHexUIntPtr(uptr), TraceLoggingHexUIntPtr(UINTPTR_MAX));
|
||||
TraceLoggingWrite(TestProvider, "hiL", TraceLoggingHexLong(iL), TraceLoggingHexLong(LONG_MIN));
|
||||
TraceLoggingWrite(TestProvider, "huL", TraceLoggingHexULong(uL), TraceLoggingHexULong(ULONG_MAX));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "f32", TraceLoggingFloat32(f32), TraceLoggingFloat32(1.0f / 3.0f, "1/3"), TraceLoggingFloat32(0.0f / 0.0f, "NaN"), TraceLoggingFloat32(-1.0f / 0.0f, "-Inf"));
|
||||
TraceLoggingWrite(TestProvider, "f64", TraceLoggingFloat64(f64), TraceLoggingFloat64(1.0 / 3.0, "1/3"), TraceLoggingFloat64(0.0 / 0.0, "NaN"), TraceLoggingFloat64(-1.0 / 0.0, "-Inf"));
|
||||
TraceLoggingWrite(TestProvider, "b8", TraceLoggingBoolean(b0), TraceLoggingBoolean(b1), TraceLoggingBoolean(UINT8_MAX));
|
||||
TraceLoggingWrite(TestProvider, "b32", TraceLoggingBool(b0), TraceLoggingBool(b1), TraceLoggingBool(INT32_MIN));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "ch", TraceLoggingChar(ch), TraceLoggingChar('\xFE', "FE"));
|
||||
TraceLoggingWrite(TestProvider, "u16ch", TraceLoggingChar16(u16ch), TraceLoggingChar16(u'\xFFFE', "FFFE"));
|
||||
TraceLoggingWrite(TestProvider, "u32ch", TraceLoggingChar32(u32ch), TraceLoggingChar32(U'\xFFFE', "FFFE"), TraceLoggingChar32(U'\x10FFFF', "10FFFF"), TraceLoggingChar32(U'\xFFFEFDFC', "FFFEFDFC"));
|
||||
TraceLoggingWrite(TestProvider, "wch", TraceLoggingWChar(wch), TraceLoggingWChar(L'\xFFFE', "FFFE"), TraceLoggingWChar(L'\x10FFFF', "10FFFF"), TraceLoggingWChar(WCHAR_MAX));
|
||||
TraceLoggingWrite(TestProvider, "ptr", TraceLoggingPointer(pSamplePtr), TraceLoggingPointer((void*)UINTPTR_MAX, "UINTPTR_MAX"));
|
||||
TraceLoggingWrite(TestProvider, "pid", TraceLoggingPid(i32), TraceLoggingPid(INT32_MAX));
|
||||
TraceLoggingWrite(TestProvider, "port", TraceLoggingPort(port80), TraceLoggingPort(UINT16_MAX));
|
||||
TraceLoggingWrite(TestProvider, "errno", TraceLoggingErrno(INT32_MIN), TraceLoggingErrno(1), TraceLoggingErrno(131));
|
||||
TraceLoggingWrite(TestProvider, "t32", TraceLoggingTime32(i32), TraceLoggingTime32(INT32_MIN), TraceLoggingTime32(INT32_MAX), TraceLoggingTime32(0));
|
||||
TraceLoggingWrite(TestProvider, "t64", TraceLoggingTime64(i64), TraceLoggingTime64(INT64_MIN), TraceLoggingTime64(INT64_MAX),
|
||||
TraceLoggingTime64(0),
|
||||
TraceLoggingTime64(-11644473600),
|
||||
TraceLoggingTime64(-11644473601),
|
||||
TraceLoggingTime64(910692730085),
|
||||
TraceLoggingTime64(910692730086));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "guid", TraceLoggingGuid(guid));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "sz",
|
||||
TraceLoggingString(NULL, "NULL"),
|
||||
TraceLoggingString(ch10));
|
||||
TraceLoggingWrite(TestProvider, "sz8",
|
||||
TraceLoggingUtf8String(NULL, "NULL"),
|
||||
TraceLoggingUtf8String(ch10));
|
||||
TraceLoggingWrite(TestProvider, "wsz",
|
||||
TraceLoggingWideString(NULL, "NULL"),
|
||||
TraceLoggingWideString(wch10));
|
||||
TraceLoggingWrite(TestProvider, "sz16",
|
||||
TraceLoggingString16(NULL, "NULL"),
|
||||
TraceLoggingString16(u16ch10));
|
||||
TraceLoggingWrite(TestProvider, "sz32",
|
||||
TraceLoggingString32(NULL, "NULL"),
|
||||
TraceLoggingString32(u32ch10));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "csz",
|
||||
TraceLoggingCountedString(NULL, 0, "NULL"),
|
||||
TraceLoggingCountedString(ch10, 5));
|
||||
TraceLoggingWrite(TestProvider, "csz8",
|
||||
TraceLoggingCountedUtf8String(NULL, 0, "NULL"),
|
||||
TraceLoggingCountedUtf8String(ch10, 5));
|
||||
TraceLoggingWrite(TestProvider, "cwsz",
|
||||
TraceLoggingCountedWideString(NULL, 0, "NULL"),
|
||||
TraceLoggingCountedWideString(wch10, 5));
|
||||
TraceLoggingWrite(TestProvider, "csz16",
|
||||
TraceLoggingCountedString16(NULL, 0, "NULL"),
|
||||
TraceLoggingCountedString16(u16ch10, 5));
|
||||
TraceLoggingWrite(TestProvider, "csz32",
|
||||
TraceLoggingCountedString32(NULL, 0, "NULL"),
|
||||
TraceLoggingCountedString32(u32ch10, 5));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "bin",
|
||||
TraceLoggingBinary(NULL, 0, "NULL"),
|
||||
TraceLoggingBinary(ch10, 5));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "ipV4",
|
||||
TraceLoggingIPv4Address(ipv4),
|
||||
TraceLoggingIPv4Address(UINT32_MAX));
|
||||
TraceLoggingWrite(TestProvider, "ipV6",
|
||||
TraceLoggingIPv6Address(&ipv6, "ipv6"),
|
||||
TraceLoggingIPv6Address("\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe\xfe", "fefe..fe00"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "ai8",
|
||||
TraceLoggingInt8FixedArray(&i8, 1, "a1"),
|
||||
TraceLoggingInt8Array(&i8, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "au8",
|
||||
TraceLoggingUInt8FixedArray(&u8, 1, "a1"),
|
||||
TraceLoggingUInt8Array(&u8, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "ai16",
|
||||
TraceLoggingInt16FixedArray(&i16, 1, "a1"),
|
||||
TraceLoggingInt16Array(&i16, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "au16",
|
||||
TraceLoggingUInt16FixedArray(&u16, 1, "a1"),
|
||||
TraceLoggingUInt16Array(&u16, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "ai32",
|
||||
TraceLoggingInt32FixedArray(&i32, 1, "a1"),
|
||||
TraceLoggingInt32Array(&i32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "au32",
|
||||
TraceLoggingUInt32FixedArray(&u32, 1, "a1"),
|
||||
TraceLoggingUInt32Array(&u32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "ai64",
|
||||
TraceLoggingInt64FixedArray(&i64, 1, "a1"),
|
||||
TraceLoggingInt64Array(&i64, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "au64",
|
||||
TraceLoggingUInt64FixedArray(&u64, 1, "a1"),
|
||||
TraceLoggingUInt64Array(&u64, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "aiptr",
|
||||
TraceLoggingIntPtrFixedArray(&iptr, 1, "a1"),
|
||||
TraceLoggingIntPtrArray(&iptr, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "auptr",
|
||||
TraceLoggingUIntPtrFixedArray(&uptr, 1, "a1"),
|
||||
TraceLoggingUIntPtrArray(&uptr, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "aiL",
|
||||
TraceLoggingLongFixedArray(&iL, 1, "a1"),
|
||||
TraceLoggingLongArray(&iL, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "auL",
|
||||
TraceLoggingULongFixedArray(&uL, 1, "a1"),
|
||||
TraceLoggingULongArray(&uL, n1, "s"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "hai8",
|
||||
TraceLoggingHexInt8FixedArray(&i8, 1, "a1"),
|
||||
TraceLoggingHexInt8Array(&i8, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hau8",
|
||||
TraceLoggingHexUInt8FixedArray(&u8, 1, "a1"),
|
||||
TraceLoggingHexUInt8Array(&u8, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hai16",
|
||||
TraceLoggingHexInt16FixedArray(&i16, 1, "a1"),
|
||||
TraceLoggingHexInt16Array(&i16, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hau16",
|
||||
TraceLoggingHexUInt16FixedArray(&u16, 1, "a1"),
|
||||
TraceLoggingHexUInt16Array(&u16, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hai32",
|
||||
TraceLoggingHexInt32FixedArray(&i32, 1, "a1"),
|
||||
TraceLoggingHexInt32Array(&i32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hau32",
|
||||
TraceLoggingHexUInt32FixedArray(&u32, 1, "a1"),
|
||||
TraceLoggingHexUInt32Array(&u32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hai64",
|
||||
TraceLoggingHexInt64FixedArray(&i64, 1, "a1"),
|
||||
TraceLoggingHexInt64Array(&i64, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hau64",
|
||||
TraceLoggingHexUInt64FixedArray(&u64, 1, "a1"),
|
||||
TraceLoggingHexUInt64Array(&u64, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "haiptr",
|
||||
TraceLoggingHexIntPtrFixedArray(&iptr, 1, "a1"),
|
||||
TraceLoggingHexIntPtrArray(&iptr, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hauptr",
|
||||
TraceLoggingHexUIntPtrFixedArray(&uptr, 1, "a1"),
|
||||
TraceLoggingHexUIntPtrArray(&uptr, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "haiL",
|
||||
TraceLoggingHexLongFixedArray(&iL, 1, "a1"),
|
||||
TraceLoggingHexLongArray(&iL, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "hauL",
|
||||
TraceLoggingHexULongFixedArray(&uL, 1, "a1"),
|
||||
TraceLoggingHexULongArray(&uL, n1, "s"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "af32",
|
||||
TraceLoggingFloat32FixedArray(&f32, 1, "a1"),
|
||||
TraceLoggingFloat32Array(&f32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "af64",
|
||||
TraceLoggingFloat64FixedArray(&f64, 1, "a1"),
|
||||
TraceLoggingFloat64Array(&f64, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "ab8",
|
||||
TraceLoggingBooleanFixedArray(&b8, 1, "a1"),
|
||||
TraceLoggingBooleanArray(&b8, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "ab32",
|
||||
TraceLoggingBoolFixedArray(&b32, 1, "a1"),
|
||||
TraceLoggingBoolArray(&b32, n1, "s"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "ach",
|
||||
TraceLoggingCharFixedArray(ch10, 4, "a4"),
|
||||
TraceLoggingCharArray(ch10, n5, "s5"));
|
||||
TraceLoggingWrite(TestProvider, "ach16",
|
||||
TraceLoggingChar16FixedArray(u16ch10, 4, "a4"),
|
||||
TraceLoggingChar16Array(u16ch10, n5, "s5"));
|
||||
TraceLoggingWrite(TestProvider, "ach32",
|
||||
TraceLoggingChar32FixedArray(u32ch10, 4, "a4"),
|
||||
TraceLoggingChar32Array(u32ch10, n5, "s5"));
|
||||
TraceLoggingWrite(TestProvider, "awch",
|
||||
TraceLoggingWCharFixedArray(wch10, 4, "a4"),
|
||||
TraceLoggingWCharArray(wch10, n5, "s5"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "aptr",
|
||||
TraceLoggingPointerFixedArray(&pSamplePtr, 1, "a1"),
|
||||
TraceLoggingPointerArray(&pSamplePtr, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "apid",
|
||||
TraceLoggingPidFixedArray(&i32, 1, "a1"),
|
||||
TraceLoggingPidArray(&i32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "aport",
|
||||
TraceLoggingPortFixedArray(&u16, 1, "a1"),
|
||||
TraceLoggingPortArray(&u16, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "aerrno",
|
||||
TraceLoggingErrnoFixedArray(&i32, 1, "a1"),
|
||||
TraceLoggingErrnoArray(&i32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "aft",
|
||||
TraceLoggingTime32FixedArray(&i32, 1, "a1"),
|
||||
TraceLoggingTime32Array(&i32, n1, "s"));
|
||||
TraceLoggingWrite(TestProvider, "auft",
|
||||
TraceLoggingTime64FixedArray(&i64, 1, "a1"),
|
||||
TraceLoggingTime64Array(&i64, n1, "s"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "ag",
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_value128 | event_field_encoding_varray_flag, event_field_format_uuid, "s0"),
|
||||
TraceLoggingPackedData(u"\x0", 2), // 0 elements in array
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_value128 | event_field_encoding_varray_flag, event_field_format_uuid, "s1"),
|
||||
TraceLoggingPackedData(u"\x1", 2), // 1 element in array
|
||||
TraceLoggingPackedData(guid, sizeof(guid)));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "ahexbytes",
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_value128 | event_field_encoding_varray_flag, event_field_format_hex_bytes, "s0"),
|
||||
TraceLoggingPackedData(u"\x0", 2), // 0 elements in array
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_value128 | event_field_encoding_varray_flag, event_field_format_hex_bytes, "s1"),
|
||||
TraceLoggingPackedData(u"\x1", 2), // 1 element in array
|
||||
TraceLoggingPackedData(guid, sizeof(guid)));
|
||||
|
||||
struct LChar8 { uint16_t x; uint16_t l; char c[10]; };
|
||||
struct LChar16 { uint16_t x; uint16_t l; char16_t c[10]; };
|
||||
struct LChar32 { uint16_t x; uint16_t l; char32_t c[10]; };
|
||||
|
||||
static struct LChar8 const lchar8 = { 0, 4, { 'h','j','k','l' } };
|
||||
static struct LChar16 const lchar16 = { 0, 4, { 'h','j','k','l' } };
|
||||
static struct LChar32 const lchar32 = { 0, 4, { 'h','j','k','l' } };
|
||||
TraceLoggingWrite(TestProvider, "Default",
|
||||
TraceLoggingPackedField(&u8, 1, event_field_encoding_value8, "V8"),
|
||||
TraceLoggingPackedField(&u16, 2, event_field_encoding_value16, "V16"),
|
||||
TraceLoggingPackedField(&u32, 4, event_field_encoding_value32, "V32"),
|
||||
TraceLoggingPackedField(&u64, 8, event_field_encoding_value64, "V64"),
|
||||
TraceLoggingPackedField(&guid, 16, event_field_encoding_value128, "V128"),
|
||||
TraceLoggingPackedField(lchar8.c, 5, event_field_encoding_zstring_char8, "NChar8"),
|
||||
TraceLoggingPackedField(lchar16.c, 10, event_field_encoding_zstring_char16, "NChar16"),
|
||||
TraceLoggingPackedField(lchar32.c, 20, event_field_encoding_zstring_char32, "NChar32"),
|
||||
TraceLoggingPackedField(&lchar8.l, 6, event_field_encoding_string_length16_char8, "LChar8"),
|
||||
TraceLoggingPackedField(&lchar16.l, 10, event_field_encoding_string_length16_char16, "LChar16"),
|
||||
TraceLoggingPackedField(&lchar32.l, 18, event_field_encoding_string_length16_char32, "LChar32"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "HexBytes",
|
||||
TraceLoggingPackedFieldEx(&guid, 1, event_field_encoding_value8, event_field_format_hex_bytes, "V8"),
|
||||
TraceLoggingPackedFieldEx(&guid, 2, event_field_encoding_value16, event_field_format_hex_bytes, "V16"),
|
||||
TraceLoggingPackedFieldEx(&guid, 4, event_field_encoding_value32, event_field_format_hex_bytes, "V32"),
|
||||
TraceLoggingPackedFieldEx(&guid, 8, event_field_encoding_value64, event_field_format_hex_bytes, "V64"),
|
||||
TraceLoggingPackedFieldEx(&guid, 16, event_field_encoding_value128, event_field_format_hex_bytes, "V128"),
|
||||
TraceLoggingPackedFieldEx(lchar8.c, 5, event_field_encoding_zstring_char8, event_field_format_hex_bytes, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lchar16.c, 10, event_field_encoding_zstring_char16, event_field_format_hex_bytes, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lchar32.c, 20, event_field_encoding_zstring_char32, event_field_format_hex_bytes, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lchar8.l, 6, event_field_encoding_string_length16_char8, event_field_format_hex_bytes, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lchar16.l, 10, event_field_encoding_string_length16_char16, event_field_format_hex_bytes, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lchar32.l, 18, event_field_encoding_string_length16_char32, event_field_format_hex_bytes, "LChar32"));
|
||||
|
||||
uint16_t false16 = 0;
|
||||
uint16_t true16 = 1;
|
||||
TraceLoggingWrite(TestProvider, "Bool16",
|
||||
TraceLoggingPackedFieldEx(&false16, 2, event_field_encoding_value16, event_field_format_boolean, "false16"),
|
||||
TraceLoggingPackedFieldEx(&true16, 2, event_field_encoding_value16, event_field_format_boolean, "true16"),
|
||||
TraceLoggingPackedFieldEx(&u16, 2, event_field_encoding_value16, event_field_format_boolean, "u16"),
|
||||
TraceLoggingPackedFieldEx(&i16, 2, event_field_encoding_value16, event_field_format_boolean, "i16"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "StringUtf",
|
||||
TraceLoggingPackedFieldEx(lchar8.c, 5, event_field_encoding_zstring_char8, event_field_format_string_utf, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lchar16.c, 10, event_field_encoding_zstring_char16, event_field_format_string_utf, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lchar32.c, 20, event_field_encoding_zstring_char32, event_field_format_string_utf, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lchar8.l, 6, event_field_encoding_string_length16_char8, event_field_format_string_utf, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lchar16.l, 10, event_field_encoding_string_length16_char16, event_field_format_string_utf, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lchar32.l, 18, event_field_encoding_string_length16_char32, event_field_format_string_utf, "LChar32"));
|
||||
|
||||
TraceLoggingWrite(TestProvider, "StringUtfBom-NoBom",
|
||||
TraceLoggingPackedFieldEx(lchar8.c, 5, event_field_encoding_zstring_char8, event_field_format_string_utf_bom, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lchar16.c, 10, event_field_encoding_zstring_char16, event_field_format_string_utf_bom, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lchar32.c, 20, event_field_encoding_zstring_char32, event_field_format_string_utf_bom, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lchar8.l, 6, event_field_encoding_string_length16_char8, event_field_format_string_utf_bom, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lchar16.l, 10, event_field_encoding_string_length16_char16, event_field_format_string_utf_bom, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lchar32.l, 18, event_field_encoding_string_length16_char32, event_field_format_string_utf_bom, "LChar32"));
|
||||
TraceLoggingWrite(TestProvider, "StringXml-NoBom",
|
||||
TraceLoggingPackedFieldEx(lchar8.c, 5, event_field_encoding_zstring_char8, event_field_format_string_xml, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lchar16.c, 10, event_field_encoding_zstring_char16, event_field_format_string_xml, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lchar32.c, 20, event_field_encoding_zstring_char32, event_field_format_string_xml, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lchar8.l, 6, event_field_encoding_string_length16_char8, event_field_format_string_xml, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lchar16.l, 10, event_field_encoding_string_length16_char16, event_field_format_string_xml, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lchar32.l, 18, event_field_encoding_string_length16_char32, event_field_format_string_xml, "LChar32"));
|
||||
TraceLoggingWrite(TestProvider, "StringJson-NoBom",
|
||||
TraceLoggingPackedFieldEx(lchar8.c, 5, event_field_encoding_zstring_char8, event_field_format_string_json, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lchar16.c, 10, event_field_encoding_zstring_char16, event_field_format_string_json, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lchar32.c, 20, event_field_encoding_zstring_char32, event_field_format_string_json, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lchar8.l, 6, event_field_encoding_string_length16_char8, event_field_format_string_json, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lchar16.l, 10, event_field_encoding_string_length16_char16, event_field_format_string_json, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lchar32.l, 18, event_field_encoding_string_length16_char32, event_field_format_string_json, "LChar32"));
|
||||
|
||||
static struct LChar8 const lcharBom8 = { 0, 7, { '\xEF', '\xBB', '\xBF', 'h','j','k','l' } };
|
||||
static struct LChar16 const lcharBom16 = { 0, 5, { 0xFEFF, 'h','j','k','l' } };
|
||||
static struct LChar32 const lcharBom32 = { 0, 5, { 0xFEFF, 'h','j','k','l' } };
|
||||
TraceLoggingWrite(TestProvider, "StringUtfBom-Bom",
|
||||
TraceLoggingPackedFieldEx(lcharBom8.c, 8, event_field_encoding_zstring_char8, event_field_format_string_utf_bom, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lcharBom16.c, 12, event_field_encoding_zstring_char16, event_field_format_string_utf_bom, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lcharBom32.c, 24, event_field_encoding_zstring_char32, event_field_format_string_utf_bom, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom8.l, 9, event_field_encoding_string_length16_char8, event_field_format_string_utf_bom, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom16.l, 12, event_field_encoding_string_length16_char16, event_field_format_string_utf_bom, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom32.l, 22, event_field_encoding_string_length16_char32, event_field_format_string_utf_bom, "LChar32"));
|
||||
TraceLoggingWrite(TestProvider, "StringXml-Bom",
|
||||
TraceLoggingPackedFieldEx(lcharBom8.c, 8, event_field_encoding_zstring_char8, event_field_format_string_xml, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lcharBom16.c, 12, event_field_encoding_zstring_char16, event_field_format_string_xml, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lcharBom32.c, 24, event_field_encoding_zstring_char32, event_field_format_string_xml, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom8.l, 9, event_field_encoding_string_length16_char8, event_field_format_string_xml, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom16.l, 12, event_field_encoding_string_length16_char16, event_field_format_string_xml, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom32.l, 22, event_field_encoding_string_length16_char32, event_field_format_string_xml, "LChar32"));
|
||||
TraceLoggingWrite(TestProvider, "StringJson-Bom",
|
||||
TraceLoggingPackedFieldEx(lcharBom8.c, 8, event_field_encoding_zstring_char8, event_field_format_string_json, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lcharBom16.c, 12, event_field_encoding_zstring_char16, event_field_format_string_json, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lcharBom32.c, 24, event_field_encoding_zstring_char32, event_field_format_string_json, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom8.l, 9, event_field_encoding_string_length16_char8, event_field_format_string_json, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom16.l, 12, event_field_encoding_string_length16_char16, event_field_format_string_json, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lcharBom32.l, 22, event_field_encoding_string_length16_char32, event_field_format_string_json, "LChar32"));
|
||||
|
||||
static struct LChar8 const lcharXBom8 = { 0, 7, { '\xEF', '\xBB', '\xBF', 'h','j','k','l' } };
|
||||
static struct LChar16 const lcharXBom16 = { 0, 5, { 0xFFFE, 0x6800, 0x6a00, 0x6b00, 0x6c00 } };
|
||||
static struct LChar32 const lcharXBom32 = { 0, 5, { 0xFFFE0000, 0x68000000, 0x6a000000, 0x6b000000, 0x6c000000 } };
|
||||
TraceLoggingWrite(TestProvider, "StringUtfBom-XBom",
|
||||
TraceLoggingPackedFieldEx(lcharXBom8.c, 8, event_field_encoding_zstring_char8, event_field_format_string_utf_bom, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lcharXBom16.c, 12, event_field_encoding_zstring_char16, event_field_format_string_utf_bom, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lcharXBom32.c, 24, event_field_encoding_zstring_char32, event_field_format_string_utf_bom, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom8.l, 9, event_field_encoding_string_length16_char8, event_field_format_string_utf_bom, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom16.l, 12, event_field_encoding_string_length16_char16, event_field_format_string_utf_bom, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom32.l, 22, event_field_encoding_string_length16_char32, event_field_format_string_utf_bom, "LChar32"));
|
||||
TraceLoggingWrite(TestProvider, "StringXml-XBom",
|
||||
TraceLoggingPackedFieldEx(lcharXBom8.c, 8, event_field_encoding_zstring_char8, event_field_format_string_xml, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lcharXBom16.c, 12, event_field_encoding_zstring_char16, event_field_format_string_xml, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lcharXBom32.c, 24, event_field_encoding_zstring_char32, event_field_format_string_xml, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom8.l, 9, event_field_encoding_string_length16_char8, event_field_format_string_xml, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom16.l, 12, event_field_encoding_string_length16_char16, event_field_format_string_xml, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom32.l, 22, event_field_encoding_string_length16_char32, event_field_format_string_xml, "LChar32"));
|
||||
TraceLoggingWrite(TestProvider, "StringJson-XBom",
|
||||
TraceLoggingPackedFieldEx(lcharXBom8.c, 8, event_field_encoding_zstring_char8, event_field_format_string_json, "NChar8"),
|
||||
TraceLoggingPackedFieldEx(lcharXBom16.c, 12, event_field_encoding_zstring_char16, event_field_format_string_json, "NChar16"),
|
||||
TraceLoggingPackedFieldEx(lcharXBom32.c, 24, event_field_encoding_zstring_char32, event_field_format_string_json, "NChar32"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom8.l, 9, event_field_encoding_string_length16_char8, event_field_format_string_json, "LChar8"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom16.l, 12, event_field_encoding_string_length16_char16, event_field_format_string_json, "LChar16"),
|
||||
TraceLoggingPackedFieldEx(&lcharXBom32.l, 22, event_field_encoding_string_length16_char32, event_field_format_string_json, "LChar32"));
|
||||
|
||||
uint16_t const n3 = 3;
|
||||
TraceLoggingWrite(TestProvider, "Packed",
|
||||
TraceLoggingInt32(5, "five"),
|
||||
TraceLoggingPackedStruct(1, "Struct1"),
|
||||
TraceLoggingPackedData(lchar8.c, 5),
|
||||
TraceLoggingPackedMetadata(event_field_encoding_zstring_char8, "NChar8"),
|
||||
TraceLoggingPackedStructArray(1, "StructArray"),
|
||||
TraceLoggingPackedData(&n3, 2),
|
||||
TraceLoggingPackedStruct(2, "Struct2"),
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_value8, event_field_format_string8, "K"),
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_zstring_char16, event_field_format_hex_bytes, "NChar16"),
|
||||
TraceLoggingPackedData("A", 1),
|
||||
TraceLoggingPackedData(lchar16.c, 10),
|
||||
TraceLoggingPackedData("B", 1),
|
||||
TraceLoggingPackedData(lcharBom16.c, 12),
|
||||
TraceLoggingPackedData("C", 1),
|
||||
TraceLoggingPackedData(lcharXBom16.c, 12),
|
||||
TraceLoggingInt32(5, "five"));
|
||||
TraceLoggingWrite(TestProvider, "Packed0",
|
||||
TraceLoggingInt32(5, "five"),
|
||||
TraceLoggingPackedStruct(1, "Struct1"),
|
||||
TraceLoggingPackedData(lchar8.c, 5),
|
||||
TraceLoggingPackedMetadata(event_field_encoding_zstring_char8, "NChar8"),
|
||||
TraceLoggingPackedStructArray(1, "StructArray"),
|
||||
TraceLoggingPackedData(u"", 2), // Zero items in array
|
||||
TraceLoggingPackedStruct(2, "Struct2"),
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_value8, event_field_format_string8, "K"),
|
||||
TraceLoggingPackedMetadataEx(event_field_encoding_zstring_char16, event_field_format_hex_bytes, "NChar16"),
|
||||
TraceLoggingInt32(5, "five"));
|
||||
static const char MyStrings3[] = "ABC\0\0XYZ";
|
||||
TraceLoggingWrite(TestProvider, "PackedComplexArray",
|
||||
TraceLoggingInt32(5, "five"),
|
||||
TraceLoggingPackedData(u"\x03", 2), // 3 items in array
|
||||
TraceLoggingPackedField(
|
||||
MyStrings3, sizeof(MyStrings3),
|
||||
event_field_encoding_zstring_char8 | event_field_encoding_varray_flag,
|
||||
"MyStrings3"),
|
||||
TraceLoggingInt32(5, "five"));
|
||||
|
||||
return true;
|
||||
}
|
124
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/TestProviderCpp.cpp
vendored
Normal file
124
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/TestProviderCpp.cpp
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
|
||||
#define TestProvider TestProviderCpp
|
||||
#include "TestProviderCommon.h"
|
||||
|
||||
static bool TestTraceLoggingLangSpecific()
|
||||
{
|
||||
void const* const pSamplePtr = (void*)(intptr_t)(-12345);
|
||||
|
||||
TraceLoggingWrite(TestProvider, "Value:bool",
|
||||
TraceLoggingValue(false, "false", "desc", 0x1234),
|
||||
TraceLoggingValue(true));
|
||||
TraceLoggingWrite(TestProvider, "Value:char",
|
||||
TraceLoggingValue('\0', "0"),
|
||||
TraceLoggingValue('A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:char16",
|
||||
TraceLoggingValue(u'\0', "0"),
|
||||
TraceLoggingValue(u'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:char32",
|
||||
TraceLoggingValue(U'\0', "0"),
|
||||
TraceLoggingValue(U'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:wchar",
|
||||
TraceLoggingValue(L'\0', "0"),
|
||||
TraceLoggingValue(L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:schar",
|
||||
TraceLoggingValue((signed char)0, "0"),
|
||||
TraceLoggingValue((signed char)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:uchar",
|
||||
TraceLoggingValue((unsigned char)0, "0"),
|
||||
TraceLoggingValue((unsigned char)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:sshort",
|
||||
TraceLoggingValue((signed short)0, "0"),
|
||||
TraceLoggingValue((signed short)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:ushort",
|
||||
TraceLoggingValue((unsigned short)0, "0"),
|
||||
TraceLoggingValue((unsigned short)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:sint",
|
||||
TraceLoggingValue((signed int)0, "0"),
|
||||
TraceLoggingValue((signed int)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:uint",
|
||||
TraceLoggingValue((unsigned int)0, "0"),
|
||||
TraceLoggingValue((unsigned int)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:slong",
|
||||
TraceLoggingValue((signed long)0, "0"),
|
||||
TraceLoggingValue((signed long)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:ulong",
|
||||
TraceLoggingValue((unsigned long)0, "0"),
|
||||
TraceLoggingValue((unsigned long)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:slonglong",
|
||||
TraceLoggingValue((signed long long)0, "0"),
|
||||
TraceLoggingValue((signed long long)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:ulonglong",
|
||||
TraceLoggingValue((unsigned long long)0, "0"),
|
||||
TraceLoggingValue((unsigned long long)L'A', "A"));
|
||||
TraceLoggingWrite(TestProvider, "Value:float",
|
||||
TraceLoggingValue(0.0f, "0"),
|
||||
TraceLoggingValue(65.0f, "65"));
|
||||
TraceLoggingWrite(TestProvider, "Value:double",
|
||||
TraceLoggingValue(0.0, "0"),
|
||||
TraceLoggingValue(65.0, "65"));
|
||||
TraceLoggingWrite(TestProvider, "Value:void*",
|
||||
TraceLoggingValue((void*)0, "0"),
|
||||
TraceLoggingValue((void*)pSamplePtr, "p"));
|
||||
TraceLoggingWrite(TestProvider, "Value:cvoid*",
|
||||
TraceLoggingValue((void const*)0, "0"),
|
||||
TraceLoggingValue((void const*)pSamplePtr, "p"));
|
||||
TraceLoggingWrite(TestProvider, "Value:char*",
|
||||
TraceLoggingValue((char*)0, "0"),
|
||||
TraceLoggingValue((char*)"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:cchar*",
|
||||
TraceLoggingValue((char const*)0, "0"),
|
||||
TraceLoggingValue((char const*)"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:char16_t*",
|
||||
TraceLoggingValue((char16_t*)0, "0"),
|
||||
TraceLoggingValue((char16_t*)u"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:cchar16_t*",
|
||||
TraceLoggingValue((char16_t const*)0, "0"),
|
||||
TraceLoggingValue((char16_t const*)u"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:char32_t*",
|
||||
TraceLoggingValue((char32_t*)0, "0"),
|
||||
TraceLoggingValue((char32_t*)U"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:cchar32_t*",
|
||||
TraceLoggingValue((char32_t const*)0, "0"),
|
||||
TraceLoggingValue((char32_t const*)U"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:wchar_t*",
|
||||
TraceLoggingValue((wchar_t*)0, "0"),
|
||||
TraceLoggingValue((wchar_t*)L"hello", "hello"));
|
||||
TraceLoggingWrite(TestProvider, "Value:cwchar_t*",
|
||||
TraceLoggingValue((wchar_t const*)0, "0"),
|
||||
TraceLoggingValue((wchar_t const*)L"hello", "hello"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
TestProviderCpp,
|
||||
"TestProviderCpp",
|
||||
// {3f3dc547-92d7-59d6-ed26-053336a36f9b}
|
||||
(0x3f3dc547, 0x92d7, 0x59d6, 0xed, 0x26, 0x05, 0x33, 0x36, 0xa3, 0x6f, 0x9b));
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
TestProviderCppG,
|
||||
"TestProviderCpp",
|
||||
// {3f3dc547-92d7-59d6-ed26-053336a36f9b}
|
||||
(0x3f3dc547, 0x92d7, 0x59d6, 0xed, 0x26, 0x05, 0x33, 0x36, 0xa3, 0x6f, 0x9b),
|
||||
TraceLoggingOptionGroupName("msft"));
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
bool TestCpp()
|
||||
{
|
||||
printf("TestProvider Name: %s\n", TraceLoggingProviderName(TestProvider));
|
||||
|
||||
int err = TraceLoggingRegister(TestProviderCpp);
|
||||
printf("TestProviderCpp register: %d\n", err);
|
||||
|
||||
bool ok = TestCommon() && TestTraceLoggingLangSpecific();
|
||||
|
||||
TraceLoggingUnregister(TestProviderCpp);
|
||||
return ok && err == 0;
|
||||
}
|
171
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/dynamic-sample.cpp
vendored
Normal file
171
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/dynamic-sample.cpp
vendored
Normal file
|
@ -0,0 +1,171 @@
|
|||
#include <eventheader/EventHeaderDynamic.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static char const guid1[16] = "123456789abcdef";
|
||||
static char const* const CharStrings[2] = {
|
||||
"abc", "123"
|
||||
};
|
||||
static wchar_t const* const WcharStrings[2] = {
|
||||
L"Labc", L"L123"
|
||||
};
|
||||
|
||||
static uint8_t arrayOf5Bytes[5] = { 1, 2, 3, 4, 5 };
|
||||
|
||||
int main()
|
||||
{
|
||||
int err;
|
||||
|
||||
/*
|
||||
A provider is a group of events. The provider has a provider name and an
|
||||
optional group name.
|
||||
|
||||
Provider name must be a valid C identifier: starts with underscore or ASCII
|
||||
letter; remaining chars may be underscores, ASCII letters, or ASCII digits.
|
||||
|
||||
The provider is not used to directly write events. Instead, you use the
|
||||
provider to create an EventSet or look up an existing EventSet, and then
|
||||
you use the EventSet to write the events.
|
||||
|
||||
The EventSet is thread-safe, but the provider is not thread-safe. Possible
|
||||
multi-threaded usage patterns for the provider would include the following:
|
||||
|
||||
- Have a reader-writer lock for the provider. Take an exclusive lock for
|
||||
non-const operations like RegisterSet() and Unregister(). Take a shared
|
||||
lock for other provider operations like FindSet().
|
||||
- Create the provider and do all of the necessary RegisterSet() calls
|
||||
before any other threads start using it. Then you can call the const
|
||||
methods like FindSet() on any thread as needed without any lock as long
|
||||
as nobody is calling any non-const methods.
|
||||
- Use your own thread-safe data structure to keep track of all of the
|
||||
EventSets you need. Take a lock if you ever need to register a new set.
|
||||
*/
|
||||
ehd::Provider provider1("EhdProv1");
|
||||
printf("provider1: Name=\"%.*s\" Options=\"%.*s\"\n",
|
||||
(int)provider1.Name().size(), provider1.Name().data(),
|
||||
(int)provider1.Options().size(), provider1.Options().data());
|
||||
|
||||
/*
|
||||
A provider may optionally have a group name. If present, it must contain
|
||||
only ASCII lowercase letters and ASCII digits.
|
||||
*/
|
||||
ehd::Provider provider2("EhdProv2", "mygroup");
|
||||
printf("provider2: Name=\"%.*s\" Options=\"%.*s\"\n",
|
||||
(int)provider2.Name().size(), provider2.Name().data(),
|
||||
(int)provider2.Options().size(), provider2.Options().data());
|
||||
|
||||
/*
|
||||
An event set is required for writing events. Each event set is for a
|
||||
provider + event level + event keyword combination. Each event set
|
||||
corresponds to one unique tracepoint name.
|
||||
|
||||
- Get an event set by calling provider.RegisterSet(). It will return a
|
||||
previously-created event set if one already exists, or make a new one
|
||||
if one does not already exist. It returns shared_ptr<EventSet> on
|
||||
success or nullptr if out of memory.
|
||||
- Get a previously-created event set by calling provider.FindSet(),
|
||||
which returns shared_ptr<EventSet>, or nullptr if not found.
|
||||
|
||||
The shared_ptr<EventSet> will stop working if the provider is closed,
|
||||
but nothing bad will happen if you use it after the provider closes.
|
||||
|
||||
Note that provider.RegisterSet() is not thread-safe, but the returned
|
||||
shared_ptr<EventSet> is thread-safe.
|
||||
|
||||
If RegisterSet() hits an out-of-memory error, it returns nullptr.
|
||||
|
||||
If RegisterSet() hits any other error, it returns an inactive EventSet.
|
||||
It is safe to use an inactive EventSet -- it will just always be disabled.
|
||||
|
||||
If RegisterSet() succeeds, it returns an active EventSet. The EventSet
|
||||
becomes inactive when the provider is unregistered or destroyed.
|
||||
*/
|
||||
auto EhdProv1_L5K1 = provider1.RegisterSet(event_level_verbose, 1);
|
||||
|
||||
/*
|
||||
For debugging purposes, you can check eventSet->Errno() to see whether the
|
||||
event set was registered successfully.
|
||||
*/
|
||||
if (EhdProv1_L5K1) // Protect against possible out-of-memory condition
|
||||
{
|
||||
printf("EhdProv1_L5K1: err=%u enabled=%u\n",
|
||||
EhdProv1_L5K1->Errno(), EhdProv1_L5K1->Enabled());
|
||||
}
|
||||
|
||||
auto EhdProv2_L4K2Gmygroup = provider2.RegisterSet(event_level_information, 2);
|
||||
if (EhdProv2_L4K2Gmygroup)
|
||||
{
|
||||
printf("EhdProv2_L4K2Gmygroup: err=%u enabled=%u\n",
|
||||
EhdProv2_L4K2Gmygroup->Errno(), EhdProv2_L4K2Gmygroup->Enabled());
|
||||
}
|
||||
|
||||
/*
|
||||
Use an EventBuilder to create the event. Call eventBuilder.Reset() to
|
||||
clear the eventBuilder and set the name and tag, call other methods to set
|
||||
attributes or add fields, and call eventBuilder.Write() to send the event
|
||||
to the kernel.
|
||||
|
||||
Note that EventBuilder is reusable. If you need to write several events,
|
||||
you might see a small performance improvement by reusing the same
|
||||
EventBuilder for several events instead of creating a new one for each
|
||||
event (it stores two std::vector<char> buffers, so reusing the builder
|
||||
can reduce heap allocation/deallocation).
|
||||
*/
|
||||
ehd::EventBuilder eb;
|
||||
size_t bookmark;
|
||||
|
||||
/*
|
||||
Building and writing an event is a waste of CPU time if the event is not
|
||||
enabled. It's usually more efficient to check whether the event is enabled
|
||||
before building and writing the event.
|
||||
*/
|
||||
if (EhdProv1_L5K1 && // If non-null (guard against out-of-memory from RegisterSet).
|
||||
EhdProv1_L5K1->Enabled()) // Only build and write if event is enabled.
|
||||
{
|
||||
eb.Reset("Name1", 0x123); // Clear the previous event (if any), then set event name and tag.
|
||||
eb.IdVersion(1, 2); // Set the event's durable id (if any).
|
||||
eb.Opcode(event_opcode_activity_start); // Set the event's opcode (if any).
|
||||
eb.AddValue("u8", (uint8_t)1, event_field_format_default); // Default format for 8-bit is unsigned.
|
||||
eb.AddValue("guid", *(ehd::Value128 const*)guid1, event_field_format_uuid); // Use Value128 struct for GUID and IPv6.
|
||||
eb.AddStruct("struct", 1, 0, &bookmark); // The next N fields are sub-fields of "struct".
|
||||
eb.AddString<char>("str", "str_val", event_field_format_default); // Default format for string is UTF.
|
||||
eb.AddNulTerminatedString("str", std::wstring_view(L"zstr_\0val"), event_field_format_default); // Chars after '\0' ignored.
|
||||
eb.SetStructFieldCount(bookmark, 2); // Update N to be 2.
|
||||
eb.AddValueRange("UintRange", &arrayOf5Bytes[0], &arrayOf5Bytes[5], event_field_format_default);
|
||||
eb.AddStringRange<char>("StringRange", &CharStrings[0], &CharStrings[2], event_field_format_default);
|
||||
eb.AddNulTerminatedStringRange<wchar_t>("NtStringRange", &WcharStrings[0], &WcharStrings[2], event_field_format_default);
|
||||
eb.AddValue("u32", (uint32_t)1, event_field_format_default);
|
||||
err = eb.Write(*EhdProv1_L5K1, guid1, guid1); // Write the event. Error code is only for debugging.
|
||||
printf("EhdProv1_L5K1: %u\n", err);
|
||||
}
|
||||
|
||||
/*
|
||||
For convenience (nicer syntax), the Enabled(eventSet) function returns
|
||||
true if eventSet is non-null and enabled.
|
||||
*/
|
||||
if (Enabled(EhdProv2_L4K2Gmygroup)) // If non-null and enabled.
|
||||
{
|
||||
/*
|
||||
If you prefer, you can use functional style to build and write the
|
||||
event in one statement.
|
||||
*/
|
||||
err = eb.Reset("Name2")
|
||||
.IdVersion(1, 2) // Set the event's durable id (if any).
|
||||
.Opcode(event_opcode_activity_start) // Set the event's opcode (if any).
|
||||
.AddValue("u8", (uint8_t)1, event_field_format_default) // Default format for 8-bit is unsigned.
|
||||
.AddValue("guid", *(ehd::Value128 const*)guid1, event_field_format_uuid) // Use Value128 struct for GUID and IPv6.
|
||||
.AddStruct("struct", 2) // The next 2 fields are sub-fields of "struct".
|
||||
.AddString<char>("str", "str_val", event_field_format_default) // Default format for string is UTF.
|
||||
.AddNulTerminatedString("str", std::wstring_view(L"zstr_\0val"), event_field_format_default) // Chars after '\0' ignored.
|
||||
.AddValueRange("UintRange", &arrayOf5Bytes[0], &arrayOf5Bytes[5], event_field_format_default)
|
||||
.AddStringRange<char>("StringRange", &CharStrings[0], &CharStrings[2], event_field_format_default)
|
||||
.AddNulTerminatedStringRange<wchar_t>("NtStringRange", &WcharStrings[0], &WcharStrings[2], event_field_format_default)
|
||||
.AddValue("u32", (uint32_t)1, event_field_format_default)
|
||||
.Write(*EhdProv2_L4K2Gmygroup);
|
||||
printf("EhdProv2_L4K2Gmygroup: %u\n", err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <errno.h>
|
||||
static_assert(EBADF == 9, "EBADF != 9");
|
82
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/interceptor-sample.cpp
vendored
Normal file
82
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/interceptor-sample.cpp
vendored
Normal file
|
@ -0,0 +1,82 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
LongProvider,
|
||||
"Long_Provider_Name_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0123456789",
|
||||
// {7a442600-4333-5126-6401-08ff132396f0}
|
||||
(0x7a442600, 0x4333, 0x5126, 0x64, 0x01, 0x08, 0xff, 0x13, 0x23, 0x96, 0xf0),
|
||||
TraceLoggingOptionGroupName("asdf"));
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool TestC(void);
|
||||
bool TestCpp(void);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
extern char const* g_interceptorFileName;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc > 1)
|
||||
{
|
||||
g_interceptorFileName = argv[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
g_interceptorFileName = "EventHeaderInterceptor"
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
"LE"
|
||||
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||
"BE"
|
||||
#endif
|
||||
#if __SIZEOF_POINTER__ == 8
|
||||
"64"
|
||||
#elif __SIZEOF_POINTER__ == 4
|
||||
"32"
|
||||
#endif
|
||||
".dat"
|
||||
;
|
||||
}
|
||||
|
||||
bool allOk = true;
|
||||
bool oneOk;
|
||||
|
||||
int result;
|
||||
|
||||
if (remove(g_interceptorFileName))
|
||||
{
|
||||
printf("Error %u clearing output file %s\n", errno, g_interceptorFileName);
|
||||
allOk = false;
|
||||
}
|
||||
|
||||
char str[EVENTHEADER_COMMAND_MAX];
|
||||
result = EVENTHEADER_FORMAT_COMMAND(str, EVENTHEADER_COMMAND_MAX,
|
||||
TraceLoggingProviderName(LongProvider), -1, -1, TraceLoggingProviderOptions(LongProvider));
|
||||
printf("%d %s\n", result, str);
|
||||
result = EVENTHEADER_FORMAT_TRACEPOINT_NAME(str, EVENTHEADER_NAME_MAX,
|
||||
TraceLoggingProviderName(LongProvider), -1, -1, TraceLoggingProviderOptions(LongProvider));
|
||||
printf("%d %s\n", result, str);
|
||||
|
||||
TraceLoggingRegister(LongProvider);
|
||||
TraceLoggingWrite(LongProvider, "LongProviderEvent");
|
||||
TraceLoggingUnregister(LongProvider);
|
||||
|
||||
oneOk = TestC();
|
||||
printf("TestProvider: %s\n", oneOk ? "ok" : "ERROR");
|
||||
allOk &= oneOk;
|
||||
|
||||
oneOk = TestCpp();
|
||||
printf("TestProvider: %s\n", oneOk ? "ok" : "ERROR");
|
||||
allOk &= oneOk;
|
||||
|
||||
printf("Events saved to \"%s\".\n", g_interceptorFileName);
|
||||
|
||||
return !allOk;
|
||||
}
|
94
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/sample.cpp
vendored
Normal file
94
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/sample.cpp
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
MyProvider,
|
||||
"MyProviderName",
|
||||
// {b7aa4d18-240c-5f41-5852-817dbf477472}
|
||||
(0xb7aa4d18, 0x240c, 0x5f41, 0x58, 0x52, 0x81, 0x7d, 0xbf, 0x47, 0x74, 0x72));
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
OtherProvider,
|
||||
"OtherProviderName",
|
||||
// {8ec53ac6-09b4-535e-5d19-e499de8832b4}
|
||||
(0x8ec53ac6, 0x09b4, 0x535e, 0x5d, 0x19, 0xe4, 0x99, 0xde, 0x88, 0x32, 0xb4),
|
||||
TraceLoggingOptionGroupName("mygroup"));
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
printf("\n");
|
||||
|
||||
TraceLoggingRegister(MyProvider);
|
||||
TraceLoggingRegister(OtherProvider);
|
||||
|
||||
for (unsigned iteration = 1;; iteration += 1)
|
||||
{
|
||||
event_level const event1_level = event_level_information;
|
||||
uint64_t const event1_keyword = 0x1;
|
||||
|
||||
// For sample purposes, show whether Event1 is currently enabled.
|
||||
// TraceLoggingProviderEnabled is usually unnecessary because every
|
||||
// TraceLoggingWrite automatically checks its own enable state.
|
||||
printf("MyProviderName_L4K1 Event1 status=%x\n",
|
||||
TraceLoggingProviderEnabled(MyProvider, event1_level, event1_keyword));
|
||||
|
||||
// If Event1 is enabled then evaluate args, pack fields, write the event.
|
||||
TraceLoggingWrite(
|
||||
MyProvider, // Provider to use for the event.
|
||||
"Event1", // Event name.
|
||||
TraceLoggingLevel(event1_level), // Event severity level.
|
||||
TraceLoggingKeyword(event1_keyword), // Event category bits.
|
||||
TraceLoggingInt32(argc, "ArgC"), // Int32 field named "ArgC".
|
||||
TraceLoggingStruct(2, "Structure"), // The following 2 fields are part of "Structure".
|
||||
TraceLoggingValue(argc, "ArgCount"), // int field named "ArgCount".
|
||||
TraceLoggingString(argv[0], "Arg0"), // char string field named "Arg0".
|
||||
TraceLoggingUInt32(iteration)); // uint32 field named "iteration".
|
||||
|
||||
event_level const event2_level = event_level_verbose;
|
||||
uint64_t const event2_keyword = 0x23;
|
||||
|
||||
// For sample purposes, show whether Event2 is currently enabled.
|
||||
printf("OtherProviderName_L5K23Gmygroup Event2 status=%x\n",
|
||||
TraceLoggingProviderEnabled(OtherProvider, event2_level, event2_keyword));
|
||||
|
||||
// If Event2 is enabled then evaluate args, pack fields, write the event.
|
||||
TraceLoggingWrite(
|
||||
OtherProvider,
|
||||
"Event2",
|
||||
TraceLoggingLevel(event2_level),
|
||||
TraceLoggingKeyword(event2_keyword),
|
||||
TraceLoggingUInt32(iteration),
|
||||
TraceLoggingString(NULL),
|
||||
TraceLoggingString(argv[0], "argv0"),
|
||||
TraceLoggingStruct(1, "struct"),
|
||||
TraceLoggingCountedString(argv[0], (uint16_t)strlen(argv[0]), "cargv0"),
|
||||
TraceLoggingBinary(argv[0], 2, "bin", "desc"),
|
||||
TraceLoggingCharArray(argv[0], 2, "vchar", "desc", 123),
|
||||
TraceLoggingCharFixedArray(argv[0], 2, "cchar"));
|
||||
|
||||
printf("Press enter to refresh, x + enter to exit...\n");
|
||||
char ch = (char)getchar();
|
||||
if (ch == 'x' || ch == 'X')
|
||||
{
|
||||
break;
|
||||
}
|
||||
while (ch != '\n')
|
||||
{
|
||||
ch = (char)getchar();
|
||||
}
|
||||
}
|
||||
|
||||
TraceLoggingUnregister(MyProvider);
|
||||
TraceLoggingUnregister(OtherProvider);
|
||||
return err;
|
||||
}
|
270
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/tracepoint-file.cpp
vendored
Normal file
270
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/tracepoint-file.cpp
vendored
Normal file
|
@ -0,0 +1,270 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Implementation of the tracepoint.h interface that writes events to a file.
|
||||
*/
|
||||
|
||||
#include <tracepoint/tracepoint.h>
|
||||
#include <tracepoint/tracepoint-impl.h>
|
||||
#include <eventheader/eventheader.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <shared_mutex>
|
||||
|
||||
static uint16_t const WriteIndexMax = 65535;
|
||||
|
||||
struct TracepointInfo
|
||||
{
|
||||
std::string Name;
|
||||
unsigned* StatusPtr = nullptr;
|
||||
};
|
||||
|
||||
static std::shared_mutex s_eventsMutex; // Also guards access to any tracepoint_provider_state
|
||||
static std::vector<TracepointInfo> s_eventsByWriteIndex;
|
||||
static int s_eventsFile = -1;
|
||||
static unsigned s_eventsFileRefCount = 0;
|
||||
|
||||
static char const* const InterceptorFileNameDefault = "Interceptor.dat";
|
||||
char const* g_interceptorFileName = InterceptorFileNameDefault;
|
||||
|
||||
void
|
||||
tracepoint_close_provider(tracepoint_provider_state* providerState)
|
||||
{
|
||||
int fileToClose = -1;
|
||||
|
||||
// Scope for lock.
|
||||
{
|
||||
auto lock = std::lock_guard(s_eventsMutex);
|
||||
|
||||
if (providerState->data_file != -1)
|
||||
{
|
||||
assert(providerState->data_file > -1);
|
||||
|
||||
assert(s_eventsFileRefCount != 0);
|
||||
s_eventsFileRefCount -= 1;
|
||||
if (s_eventsFileRefCount == 0)
|
||||
{
|
||||
fileToClose = s_eventsFile;
|
||||
s_eventsFile = -1;
|
||||
s_eventsByWriteIndex.clear();
|
||||
}
|
||||
}
|
||||
|
||||
tracepoint_close_provider_impl(providerState);
|
||||
}
|
||||
|
||||
if (fileToClose != -1)
|
||||
{
|
||||
close(fileToClose);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tracepoint_open_provider(tracepoint_provider_state* providerState)
|
||||
{
|
||||
int err;
|
||||
auto lock = std::lock_guard(s_eventsMutex);
|
||||
|
||||
if (providerState->data_file != -1)
|
||||
{
|
||||
assert(providerState->data_file == -1); // PRECONDITION
|
||||
abort(); // PRECONDITION
|
||||
}
|
||||
|
||||
if (s_eventsFile == -1)
|
||||
{
|
||||
assert(s_eventsFileRefCount == 0);
|
||||
|
||||
s_eventsFile = open(g_interceptorFileName,
|
||||
O_WRONLY | O_CLOEXEC | O_CREAT | O_APPEND,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (s_eventsFile == -1)
|
||||
{
|
||||
err = errno;
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
s_eventsFileRefCount += 1;
|
||||
tracepoint_open_provider_impl(providerState, s_eventsFile);
|
||||
err = 0;
|
||||
|
||||
Done:
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
tracepoint_connect(
|
||||
tracepoint_state* eventState,
|
||||
tracepoint_provider_state* providerState,
|
||||
char const* eventNameArgs)
|
||||
{
|
||||
int err;
|
||||
int writeIndex = -1;
|
||||
|
||||
auto lock = std::lock_guard(s_eventsMutex);
|
||||
|
||||
if (providerState == NULL)
|
||||
{
|
||||
auto const wi = static_cast<uint32_t>(__atomic_load_n(&eventState->write_index, __ATOMIC_RELAXED));
|
||||
if (wi >= s_eventsByWriteIndex.size())
|
||||
{
|
||||
err = EINVAL;
|
||||
}
|
||||
else if (auto& e = s_eventsByWriteIndex[wi];
|
||||
e.StatusPtr == nullptr)
|
||||
{
|
||||
err = EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.StatusPtr = nullptr;
|
||||
e.Name.clear();
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
else try
|
||||
{
|
||||
// eventNameArgs = "EventName ArgList". We just want EventName.
|
||||
auto const eventNameEnd = strchr(eventNameArgs, ' ');
|
||||
if (eventNameEnd == nullptr)
|
||||
{
|
||||
err = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
auto const eventName = std::string_view(eventNameArgs, eventNameEnd - eventNameArgs);
|
||||
if (eventName.size() >= EVENTHEADER_NAME_MAX)
|
||||
{
|
||||
err = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
if (s_eventsByWriteIndex.size() > WriteIndexMax)
|
||||
{
|
||||
err = E2BIG;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
auto const pStatusWord = &eventState->status_word;
|
||||
s_eventsByWriteIndex.push_back({ std::string(eventName), pStatusWord });
|
||||
|
||||
// In this sample, events are always enabled.
|
||||
__atomic_store_n(pStatusWord, 1, __ATOMIC_RELAXED);
|
||||
|
||||
writeIndex = static_cast<int>(s_eventsByWriteIndex.size() - 1);
|
||||
err = 0;
|
||||
}
|
||||
catch (std::bad_alloc const&)
|
||||
{
|
||||
err = ENOMEM;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
err = EINVAL;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
tracepoint_connect_impl(eventState, providerState, writeIndex);
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
tracepoint_open_provider_with_tracepoints(
|
||||
tracepoint_provider_state* provider_state,
|
||||
tracepoint_definition const** tp_definition_start,
|
||||
tracepoint_definition const** tp_definition_stop)
|
||||
{
|
||||
return tracepoint_open_provider_with_tracepoints_impl(
|
||||
provider_state,
|
||||
tp_definition_start,
|
||||
tp_definition_stop);
|
||||
}
|
||||
|
||||
int
|
||||
tracepoint_write(
|
||||
tracepoint_state const* eventState,
|
||||
unsigned dataCount,
|
||||
struct iovec* dataVecs)
|
||||
{
|
||||
assert((int)dataCount >= 1);
|
||||
assert(dataVecs[0].iov_len == 0);
|
||||
|
||||
if (!TRACEPOINT_ENABLED(eventState))
|
||||
{
|
||||
return EBADF;
|
||||
}
|
||||
|
||||
size_t size = 0;
|
||||
for (unsigned i = 1; i < dataCount; i += 1)
|
||||
{
|
||||
size += dataVecs[i].iov_len;
|
||||
if (size < dataVecs[i].iov_len)
|
||||
{
|
||||
return E2BIG;
|
||||
}
|
||||
}
|
||||
|
||||
auto const providerState = __atomic_load_n(&eventState->provider_state, __ATOMIC_RELAXED);
|
||||
if (providerState == NULL)
|
||||
{
|
||||
return EBADF;
|
||||
}
|
||||
|
||||
auto lock = std::shared_lock(s_eventsMutex);
|
||||
|
||||
// Look up our tracking info for this event.
|
||||
auto const writeIndex = static_cast<uint32_t>(__atomic_load_n(&eventState->write_index, __ATOMIC_RELAXED));
|
||||
if (writeIndex >= s_eventsByWriteIndex.size())
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
auto const& tpi = s_eventsByWriteIndex[writeIndex];
|
||||
if (tpi.StatusPtr == nullptr)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
auto const headerSize = sizeof(uint32_t) + tpi.Name.size() + 1;
|
||||
size += headerSize;
|
||||
if (size < headerSize || size != (uint32_t)size)
|
||||
{
|
||||
return E2BIG;
|
||||
}
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t LittleEndianRecordSize;
|
||||
char TracepointName[EVENTHEADER_NAME_MAX];
|
||||
} header;
|
||||
|
||||
header.LittleEndianRecordSize = htole32((uint32_t)size);
|
||||
|
||||
assert(tpi.Name.size() < sizeof(header.TracepointName)); // Was checked in tracepoint_connect.
|
||||
memcpy(header.TracepointName, tpi.Name.c_str(), tpi.Name.size() + 1);
|
||||
|
||||
assert(s_eventsFile == providerState->data_file);
|
||||
|
||||
/*
|
||||
On-disk record format:
|
||||
uint32_t LittleEndianRecordSize;
|
||||
char[] NulTerminatedTracepointName;
|
||||
char[] EventData;
|
||||
*/
|
||||
dataVecs[0].iov_base = &header;
|
||||
dataVecs[0].iov_len = headerSize;
|
||||
return 0 <= writev(providerState->data_file, dataVecs, (int)dataCount)
|
||||
? 0
|
||||
: errno;
|
||||
}
|
51
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/tracepoint-sample.cpp
vendored
Normal file
51
src/native/external/LinuxTracepoints/libeventheader-tracepoint/samples/tracepoint-sample.cpp
vendored
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/TraceLoggingProvider.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
TRACELOGGING_DEFINE_PROVIDER(
|
||||
LongProvider,
|
||||
"Long_Provider_Name_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0123456789",
|
||||
// {7a442600-4333-5126-6401-08ff132396f0}
|
||||
(0x7a442600, 0x4333, 0x5126, 0x64, 0x01, 0x08, 0xff, 0x13, 0x23, 0x96, 0xf0),
|
||||
TraceLoggingOptionGroupName("asdf"));
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool TestC(void);
|
||||
bool TestCpp(void);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int main()
|
||||
{
|
||||
bool allOk = true;
|
||||
bool oneOk;
|
||||
|
||||
int result;
|
||||
|
||||
char str[EVENTHEADER_COMMAND_MAX];
|
||||
result = EVENTHEADER_FORMAT_COMMAND(str, EVENTHEADER_COMMAND_MAX,
|
||||
TraceLoggingProviderName(LongProvider), -1, -1, TraceLoggingProviderOptions(LongProvider));
|
||||
printf("%d %s\n", result, str);
|
||||
result = EVENTHEADER_FORMAT_TRACEPOINT_NAME(str, EVENTHEADER_NAME_MAX,
|
||||
TraceLoggingProviderName(LongProvider), -1, -1, TraceLoggingProviderOptions(LongProvider));
|
||||
printf("%d %s\n", result, str);
|
||||
|
||||
TraceLoggingRegister(LongProvider);
|
||||
TraceLoggingWrite(LongProvider, "LongProviderEvent");
|
||||
TraceLoggingUnregister(LongProvider);
|
||||
|
||||
oneOk = TestC();
|
||||
printf("TestProvider: %s\n", oneOk ? "ok" : "ERROR");
|
||||
allOk &= oneOk;
|
||||
|
||||
oneOk = TestCpp();
|
||||
printf("TestProvider: %s\n", oneOk ? "ok" : "ERROR");
|
||||
allOk &= oneOk;
|
||||
|
||||
return !allOk;
|
||||
}
|
23
src/native/external/LinuxTracepoints/libeventheader-tracepoint/src/CMakeLists.txt
vendored
Normal file
23
src/native/external/LinuxTracepoints/libeventheader-tracepoint/src/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
# eventheader-tracepoint = libeventheader-tracepoint, EVENTHEADER_HEADERS
|
||||
add_library(eventheader-tracepoint
|
||||
eventheader-tracepoint.c)
|
||||
target_link_libraries(eventheader-tracepoint
|
||||
PUBLIC eventheader-headers tracepoint-headers)
|
||||
install(TARGETS eventheader-tracepoint
|
||||
EXPORT eventheader-tracepointTargets)
|
||||
install(EXPORT eventheader-tracepointTargets
|
||||
FILE "eventheader-tracepointTargets.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-tracepoint")
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/eventheader-tracepointConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-tracepointConfig.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-tracepoint"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-tracepointConfigVersion.cmake"
|
||||
COMPATIBILITY SameMinorVersion)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-tracepointConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/eventheader-tracepointConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/eventheader-tracepoint")
|
193
src/native/external/LinuxTracepoints/libeventheader-tracepoint/src/eventheader-tracepoint.c
vendored
Normal file
193
src/native/external/LinuxTracepoints/libeventheader-tracepoint/src/eventheader-tracepoint.c
vendored
Normal file
|
@ -0,0 +1,193 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <eventheader/eventheader-tracepoint.h>
|
||||
#include <tracepoint/tracepoint.h>
|
||||
#include <tracepoint/tracepoint-impl.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _uehp_FUNC_ATTRIBUTES
|
||||
#define _uehp_FUNC_ATTRIBUTES //__attribute__((weak, visibility("hidden")))
|
||||
#endif // _uehp_FUNC_ATTRIBUTES
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
int
|
||||
eventheader_open_provider(
|
||||
eventheader_provider const* pProvider) _uehp_FUNC_ATTRIBUTES;
|
||||
int
|
||||
eventheader_open_provider(
|
||||
eventheader_provider const* pProvider)
|
||||
{
|
||||
assert(pProvider->state);
|
||||
assert(pProvider->name);
|
||||
assert(NULL == strchr(pProvider->name, ' '));
|
||||
assert(NULL == strchr(pProvider->name, ':'));
|
||||
|
||||
if (pProvider->options != NULL)
|
||||
{
|
||||
assert(NULL == strchr(pProvider->options, ' '));
|
||||
assert(NULL == strchr(pProvider->options, ':'));
|
||||
assert(NULL == strchr(pProvider->options, '_'));
|
||||
}
|
||||
|
||||
return tracepoint_open_provider(pProvider->state);
|
||||
}
|
||||
|
||||
int
|
||||
eventheader_open_provider_with_events(
|
||||
eventheader_provider const* pProvider,
|
||||
eventheader_tracepoint const** pEventsStart,
|
||||
eventheader_tracepoint const** pEventsStop) _uehp_FUNC_ATTRIBUTES;
|
||||
int
|
||||
eventheader_open_provider_with_events(
|
||||
eventheader_provider const* pProvider,
|
||||
eventheader_tracepoint const** pEventsStart,
|
||||
eventheader_tracepoint const** pEventsStop)
|
||||
{
|
||||
int err = eventheader_open_provider(pProvider);
|
||||
if (err != 0)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
eventheader_tracepoint const** adjustedEventPtrsStop =
|
||||
tracepoint_fix_array((void const**)pEventsStart, (void const**)pEventsStop);
|
||||
|
||||
int const eventCount = (int)(adjustedEventPtrsStop - pEventsStart);
|
||||
for (int i = 0; i < eventCount; i += 1)
|
||||
{
|
||||
eventheader_tracepoint const* const pEvent = pEventsStart[i];
|
||||
|
||||
assert(0 == __atomic_load_n(&pEvent->state->status_word, __ATOMIC_RELAXED));
|
||||
assert(-1 == __atomic_load_n(&pEvent->state->write_index, __ATOMIC_RELAXED));
|
||||
assert(NULL == __atomic_load_n(&pEvent->state->provider_state, __ATOMIC_RELAXED));
|
||||
|
||||
(void)eventheader_connect(pEvent, pProvider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
eventheader_close_provider(
|
||||
eventheader_provider const* pProvider) _uehp_FUNC_ATTRIBUTES;
|
||||
void
|
||||
eventheader_close_provider(
|
||||
eventheader_provider const* pProvider)
|
||||
{
|
||||
tracepoint_close_provider(pProvider->state);
|
||||
}
|
||||
|
||||
int
|
||||
eventheader_connect(
|
||||
eventheader_tracepoint const* pEvent,
|
||||
eventheader_provider const* pProvider) _uehp_FUNC_ATTRIBUTES;
|
||||
int
|
||||
eventheader_connect(
|
||||
eventheader_tracepoint const* pEvent,
|
||||
eventheader_provider const* pProvider)
|
||||
{
|
||||
int err;
|
||||
|
||||
char command[EVENTHEADER_COMMAND_MAX];
|
||||
if (pProvider == NULL)
|
||||
{
|
||||
err = tracepoint_connect(pEvent->state, NULL, NULL);
|
||||
}
|
||||
else if (EVENTHEADER_COMMAND_MAX <= (unsigned)EVENTHEADER_FORMAT_COMMAND(
|
||||
command, sizeof(command),
|
||||
pProvider->name, pEvent->header.level, pEvent->keyword, pProvider->options))
|
||||
{
|
||||
assert(!"Full name too long");
|
||||
err = E2BIG;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = tracepoint_connect(pEvent->state, pProvider->state, command);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
eventheader_write(
|
||||
eventheader_tracepoint const* pEvent,
|
||||
void const* pActivityId,
|
||||
void const* pRelatedActivityId,
|
||||
uint32_t dataCount,
|
||||
struct iovec* dataVecs) _uehp_FUNC_ATTRIBUTES;
|
||||
int
|
||||
eventheader_write(
|
||||
eventheader_tracepoint const* pEvent,
|
||||
void const* pActivityId,
|
||||
void const* pRelatedActivityId,
|
||||
uint32_t dataCount,
|
||||
struct iovec* dataVecs)
|
||||
{
|
||||
uint8_t headers[0
|
||||
+ sizeof(eventheader)
|
||||
+ sizeof(eventheader_extension) + 32]; // ActivityId + RelatedActivityId
|
||||
size_t iHeaders = 0;
|
||||
|
||||
eventheader* pHeader = (eventheader*)&headers[iHeaders];
|
||||
iHeaders += sizeof(eventheader);
|
||||
*pHeader = pEvent->header;
|
||||
|
||||
if (pActivityId == NULL)
|
||||
{
|
||||
assert(pRelatedActivityId == NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
pHeader->flags |= eventheader_flag_extension;
|
||||
|
||||
eventheader_extension* pExt = (eventheader_extension*)&headers[iHeaders];
|
||||
iHeaders += sizeof(eventheader_extension);
|
||||
pExt->kind = pEvent->metadata || (pEvent->header.flags & eventheader_flag_extension)
|
||||
? (eventheader_extension_kind_activity_id | eventheader_extension_kind_chain_flag)
|
||||
: (eventheader_extension_kind_activity_id);
|
||||
|
||||
pExt->size = 16;
|
||||
memcpy(&headers[iHeaders], pActivityId, 16);
|
||||
iHeaders += 16;
|
||||
|
||||
if (pRelatedActivityId != NULL)
|
||||
{
|
||||
pExt->size = 32;
|
||||
memcpy(&headers[iHeaders], pRelatedActivityId, 16);
|
||||
iHeaders += 16;
|
||||
}
|
||||
}
|
||||
|
||||
assert(iHeaders <= sizeof(headers));
|
||||
|
||||
assert(dataVecs != NULL);
|
||||
assert((int)dataCount >= EVENTHEADER_PREFIX_DATAVEC_COUNT_NO_METADATA);
|
||||
dataVecs[0].iov_len = 0;
|
||||
dataVecs[1].iov_base = headers;
|
||||
dataVecs[1].iov_len = iHeaders;
|
||||
|
||||
if (pEvent->metadata != NULL)
|
||||
{
|
||||
pHeader->flags |= eventheader_flag_extension;
|
||||
|
||||
assert((int)dataCount >= EVENTHEADER_PREFIX_DATAVEC_COUNT);
|
||||
dataVecs[2].iov_base = (void*)pEvent->metadata;
|
||||
dataVecs[2].iov_len = pEvent->metadata->size + sizeof(eventheader_extension);
|
||||
}
|
||||
|
||||
return tracepoint_write(pEvent->state, dataCount, dataVecs);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
|
@ -0,0 +1,2 @@
|
|||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/eventheader-tracepointTargets.cmake")
|
41
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/CMakeLists.txt
vendored
Normal file
41
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
include(../version.cmake)
|
||||
project(tracepoint-control-cpp
|
||||
VERSION ${LINUXTRACEPOINTS_VERSION}
|
||||
DESCRIPTION "Linux tracepoint collection for C++"
|
||||
HOMEPAGE_URL "https://github.com/microsoft/LinuxTracepoints"
|
||||
LANGUAGES CXX)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(BUILD_SAMPLES ON CACHE BOOL "Build sample code")
|
||||
set(BUILD_TOOLS ON CACHE BOOL "Build tool code")
|
||||
|
||||
if(NOT WIN32)
|
||||
|
||||
if(NOT TARGET tracepoint-decode)
|
||||
find_package(tracepoint-decode ${TRACEPOINT_DECODE_MINVER} REQUIRED)
|
||||
endif()
|
||||
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wformat
|
||||
-Wformat-security
|
||||
-Werror=format-security
|
||||
-Wstack-protector
|
||||
-Werror=stack-protector)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-D_FORTIFY_SOURCE=2)
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
if(BUILD_SAMPLES)
|
||||
add_subdirectory(samples)
|
||||
endif()
|
||||
|
||||
if(BUILD_TOOLS)
|
||||
add_subdirectory(tools)
|
||||
endif()
|
||||
|
||||
endif()
|
11
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/README.md
vendored
Normal file
11
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/README.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# libtracepoint-control-cpp
|
||||
|
||||
- `TracepointSession.h` implements an event collection session that can
|
||||
collect tracepoint events and enumerate the events that the session has
|
||||
collected.
|
||||
- `TracepointPath.h` has functions for finding the `/sys/kernel/tracing`
|
||||
mount point and reading `format` files.
|
||||
- `TracepointName.h` represents a tracepoint name (system name + event
|
||||
name); for instance, `user_events/eventName`.
|
||||
- `TracepointCache.h` implements a cache for tracking parsed `format` files
|
||||
and locating cached data by `TracepointName` or by `common_type` id.
|
241
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointCache.h
vendored
Normal file
241
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointCache.h
vendored
Normal file
|
@ -0,0 +1,241 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
TracepointCache: class that loads, parses, and caches the metadata (format)
|
||||
information for tracepoints.
|
||||
|
||||
The TracepointSession class uses TracepointCache to manage format information
|
||||
for its tracepoints.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_TracepointCache_h
|
||||
#define _included_TracepointCache_h 1
|
||||
|
||||
#include "TracepointName.h"
|
||||
#include <tracepoint/PerfEventMetadata.h>
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _Success_
|
||||
#define _Success_(condition)
|
||||
#endif
|
||||
#ifndef _In_z_
|
||||
#define _In_z_
|
||||
#endif
|
||||
#ifndef _Out_
|
||||
#define _Out_
|
||||
#endif
|
||||
|
||||
namespace tracepoint_control
|
||||
{
|
||||
class TracepointSpec; // Forward declaration
|
||||
|
||||
/*
|
||||
Loads, parses, and caches the metadata (format) information for tracepoints.
|
||||
*/
|
||||
class TracepointCache
|
||||
{
|
||||
public:
|
||||
|
||||
TracepointCache(TracepointCache const&) = delete;
|
||||
void operator=(TracepointCache const&) = delete;
|
||||
~TracepointCache();
|
||||
|
||||
/*
|
||||
May throw std::bad_alloc.
|
||||
*/
|
||||
TracepointCache() noexcept(false);
|
||||
|
||||
/*
|
||||
If no events are present in cache, returns -1.
|
||||
Otherwise, returns the offset of the common_type field (usually 0).
|
||||
*/
|
||||
int8_t
|
||||
CommonTypeOffset() const noexcept;
|
||||
|
||||
/*
|
||||
If no events are present in cache, returns 0.
|
||||
Otherwise, returns the size of the common_type field (1, 2, or 4; usually 2).
|
||||
*/
|
||||
uint8_t
|
||||
CommonTypeSize() const noexcept;
|
||||
|
||||
/*
|
||||
If metadata for an event with the specified ID is cached, return it.
|
||||
Otherwise, return NULL. Note that ID is from the event's common_type field
|
||||
and is not the PERF_SAMPLE_ID or PERF_SAMPLE_IDENTIFIER value.
|
||||
*/
|
||||
tracepoint_decode::PerfEventMetadata const*
|
||||
FindById(uint32_t id) const noexcept;
|
||||
|
||||
/*
|
||||
If metadata for an event with the specified name is cached, return it.
|
||||
Otherwise, return NULL.
|
||||
*/
|
||||
tracepoint_decode::PerfEventMetadata const*
|
||||
FindByName(TracepointName const& name) const noexcept;
|
||||
|
||||
/*
|
||||
If metadata for an event with the specified data is cached,
|
||||
return it. Otherwise, return NULL.
|
||||
|
||||
Implementation:
|
||||
|
||||
- Assume that rawData is host-endian.
|
||||
- Use CommonTypeOffset() and CommonTypeSize() to extract the common_type
|
||||
field value from the rawData.
|
||||
- Use FindById() to find the matching metadata.
|
||||
*/
|
||||
tracepoint_decode::PerfEventMetadata const*
|
||||
FindByRawData(std::string_view rawData) const noexcept;
|
||||
|
||||
/*
|
||||
Parse the formatFileContents to get the metadata. If systemName or
|
||||
formatFileContents is invalid, return EINVAL. If metadata for an
|
||||
event with the same name or ID is already cached, return EEXIST.
|
||||
Otherwise, add the metadata to the cache.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
AddFromFormat(
|
||||
std::string_view systemName,
|
||||
std::string_view formatFileContents,
|
||||
bool longSize64 = sizeof(long) == 8) noexcept;
|
||||
|
||||
/*
|
||||
Load and parse the "/sys/.../tracing/events/systemName/eventName/format"
|
||||
file. If name or the format data is invalid, return EINVAL. If metadata
|
||||
for an event with the same name or ID is already cached, return EEXIST.
|
||||
Otherwise, add the metadata to the cache.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
AddFromSystem(TracepointName const& name) noexcept;
|
||||
|
||||
/*
|
||||
If metadata for an event with the specified name is cached, return it.
|
||||
Otherwise, return AddFromSystem(name).
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
FindOrAddFromSystem(
|
||||
TracepointName const& name,
|
||||
_Out_ tracepoint_decode::PerfEventMetadata const** ppMetadata) noexcept;
|
||||
|
||||
/*
|
||||
Given the name of a user_events EventHeader tracepoint, pre-register and
|
||||
cache the specified event.
|
||||
|
||||
Example eventName: "user_events:MyProvider_L1Kff"
|
||||
|
||||
Details:
|
||||
|
||||
- If the specified name is not a valid user_events EventHeader name, return EINVAL.
|
||||
- If metadata for "user_events:eventName" is already cached, return EEXIST.
|
||||
- Try to register an EventHeader tracepoint with the given tracepoint name. If
|
||||
this fails, return the error.
|
||||
- Return AddFromSystem("user_events:eventName").
|
||||
|
||||
If this operation succeeds, the event will remain registered as long as this cache
|
||||
object exists.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
PreregisterEventHeaderTracepoint(TracepointName const& name) noexcept;
|
||||
|
||||
/*
|
||||
Given a tracepoint definition, pre-register and cache the specified event.
|
||||
|
||||
Details:
|
||||
|
||||
- If spec.Kind is not Definition or EventHeaderDefinition, return EINVAL.
|
||||
- If spec.SystemName is not "user_events", return EINVAL.
|
||||
- If spec.EventName, spec.Flags, or spec.Fields is invalid, return EINVAL.
|
||||
- If metadata for "user_events:eventName" is already cached, return EEXIST.
|
||||
- Try to register a tracepoint with the given tracepoint name, flags, and
|
||||
fields. If this fails, return the error.
|
||||
- Return AddFromSystem("user_events:eventName").
|
||||
|
||||
If this operation succeeds, the event will remain registered as long as this cache
|
||||
object exists.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
PreregisterTracepointDefinition(TracepointSpec const& spec) noexcept;
|
||||
|
||||
/*
|
||||
Given the registration command for a user_events tracepoint, pre-register and
|
||||
cache the specified event.
|
||||
|
||||
Example registerCommand: "MyEventName __rel_loc u8[] MyField1; int MyField2"
|
||||
|
||||
Details:
|
||||
|
||||
- Parse the command to determine the eventName. If invalid, return EINVAL.
|
||||
- If metadata for "user_events:eventName" is already cached, return EEXIST.
|
||||
- Try to register a user_events tracepoint using the specified command string. If
|
||||
this fails, return the error.
|
||||
- Return AddFromSystem("user_events:eventName").
|
||||
|
||||
If this operation succeeds, the event will remain registered as long as this cache
|
||||
object exists.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
PreregisterTracepoint(_In_z_ char const* registerCommand) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
struct TracepointRegistration
|
||||
{
|
||||
int DataFile;
|
||||
int WriteIndex;
|
||||
unsigned StatusWord;
|
||||
|
||||
TracepointRegistration(TracepointRegistration const&) = delete;
|
||||
void operator=(TracepointRegistration const&) = delete;
|
||||
~TracepointRegistration();
|
||||
TracepointRegistration() noexcept;
|
||||
};
|
||||
|
||||
struct CacheVal
|
||||
{
|
||||
std::vector<char> SystemAndFormat; // = "SystemName\nFormatFileContents"
|
||||
tracepoint_decode::PerfEventMetadata Metadata; // Points into SystemAndFormat
|
||||
std::unique_ptr<TracepointRegistration> Registration;
|
||||
|
||||
CacheVal(CacheVal const&) = delete;
|
||||
void operator=(CacheVal const&) = delete;
|
||||
~CacheVal();
|
||||
|
||||
CacheVal(
|
||||
std::vector<char>&& systemAndFormat,
|
||||
tracepoint_decode::PerfEventMetadata&& metadata,
|
||||
std::unique_ptr<TracepointRegistration> registration) noexcept;
|
||||
};
|
||||
|
||||
struct NameHashOps
|
||||
{
|
||||
size_t operator()(TracepointName const&) const noexcept; // Hash
|
||||
size_t operator()(TracepointName const&, TracepointName const&) const noexcept; // Equal
|
||||
};
|
||||
|
||||
_Success_(return == 0) int
|
||||
PreregisterTracepointImpl(_In_z_ char const* registerCommand, unsigned eventNameSize) noexcept;
|
||||
|
||||
/*
|
||||
systemAndFormat = "SystemName\nFormatFileContents".
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
Add(std::vector<char>&& systemAndFormat,
|
||||
size_t systemNameSize,
|
||||
bool longSize64,
|
||||
std::unique_ptr<TracepointRegistration> registration) noexcept;
|
||||
|
||||
std::unordered_map<uint32_t, CacheVal> m_byId;
|
||||
std::unordered_map<TracepointName, CacheVal const&, NameHashOps, NameHashOps> m_byName;
|
||||
int8_t m_commonTypeOffset; // -1 = unset
|
||||
uint8_t m_commonTypeSize; // 0 = unset
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_control
|
||||
|
||||
#endif // _included_TracepointCache_h
|
259
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointName.h
vendored
Normal file
259
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointName.h
vendored
Normal file
|
@ -0,0 +1,259 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
TracepointName is a view of a SystemName and an EventName.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_TracepointName_h
|
||||
#define _included_TracepointName_h 1
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace tracepoint_control
|
||||
{
|
||||
/*
|
||||
The name of the "user_events" system.
|
||||
*/
|
||||
static constexpr std::string_view UserEventsSystemName = std::string_view("user_events", 11);
|
||||
|
||||
/*
|
||||
Maximum length of a SystemName = 255. (Does not count nul-termination.)
|
||||
*/
|
||||
static constexpr unsigned SystemNameMaxSize = 255;
|
||||
|
||||
/*
|
||||
Maximum length of an EventName = 255. (Does not count nul-termination.)
|
||||
*/
|
||||
static constexpr unsigned EventNameMaxSize = 255;
|
||||
|
||||
/*
|
||||
Returns true if the specified string is a valid tracepoint system name.
|
||||
|
||||
At present, this returns true if:
|
||||
- systemName is not empty.
|
||||
- systemName.size() <= SystemNameMaxSize.
|
||||
- systemName does not contain nul, space, slash, or colon.
|
||||
*/
|
||||
constexpr bool
|
||||
SystemNameIsValid(std::string_view systemName) noexcept
|
||||
{
|
||||
return systemName.size() > 0
|
||||
&& systemName.size() <= SystemNameMaxSize
|
||||
&& systemName.find('\0') == std::string_view::npos
|
||||
&& systemName.find(' ') == std::string_view::npos
|
||||
&& systemName.find('/') == std::string_view::npos
|
||||
&& systemName.find(':') == std::string_view::npos;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if the specified string is a valid tracepoint event name.
|
||||
|
||||
At present, this returns true if:
|
||||
- eventName is not empty.
|
||||
- eventName.size() <= EventNameMaxSize.
|
||||
- eventName does not contain nul, space, slash, or colon.
|
||||
*/
|
||||
constexpr bool
|
||||
EventNameIsValid(std::string_view eventName) noexcept
|
||||
{
|
||||
return eventName.size() > 0
|
||||
&& eventName.size() <= EventNameMaxSize
|
||||
&& eventName.find('\0') == std::string_view::npos
|
||||
&& eventName.find(' ') == std::string_view::npos
|
||||
&& eventName.find('/') == std::string_view::npos
|
||||
&& eventName.find(':') == std::string_view::npos;
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if the specified string is a valid EventHeader tracepoint name,
|
||||
e.g. "MyComponent_MyProvider_L1K2e" or "MyComponent_MyProv_L5K1Gmyprovider".
|
||||
|
||||
A valid EventHeader tracepoint name is a valid tracepoint event name that ends
|
||||
with a "_LxKx..." suffix, where "x" is 1 or more lowercase hex digits and "..."
|
||||
is 0 or more ASCII letters or digits.
|
||||
*/
|
||||
static constexpr bool
|
||||
EventHeaderEventNameIsValid(std::string_view eventName) noexcept
|
||||
{
|
||||
auto const eventNameSize = eventName.size();
|
||||
|
||||
if (eventNameSize < 5 || // 5 = "_L1K1".size()
|
||||
!EventNameIsValid(eventName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto i = eventName.rfind('_');
|
||||
if (i > eventNameSize - 5 || // 5 = "_L1K1".size()
|
||||
eventName[i + 1] != 'L')
|
||||
{
|
||||
// Does not end with "_L...".
|
||||
return false;
|
||||
}
|
||||
|
||||
i += 2; // Skip "_L".
|
||||
|
||||
// Skip level value (lowercase hex digits).
|
||||
auto const levelStart = i;
|
||||
for (; i != eventNameSize; i += 1)
|
||||
{
|
||||
auto const ch = eventName[i];
|
||||
if ((ch < '0' || '9' < ch) && (ch < 'a' || 'f' < ch))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (levelStart == i)
|
||||
{
|
||||
// Does not end with "_Lx...".
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i == eventNameSize || eventName[i] != 'K')
|
||||
{
|
||||
// Does not end with "_LxK...".
|
||||
return false;
|
||||
}
|
||||
|
||||
i += 1; // Skip "K"
|
||||
|
||||
// Skip keyword value (lowercase hex digits).
|
||||
auto const keywordStart = i;
|
||||
for (; i != eventNameSize; i += 1)
|
||||
{
|
||||
auto const ch = eventName[i];
|
||||
if ((ch < '0' || '9' < ch) && (ch < 'a' || 'f' < ch))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (keywordStart == i)
|
||||
{
|
||||
// Does not end with "_LxKx...".
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there are attributes, validate them.
|
||||
if (i != eventNameSize)
|
||||
{
|
||||
if (eventName[i] < 'A' || 'Z' < eventName[i])
|
||||
{
|
||||
// Invalid attribute lead char.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip attributes and their values.
|
||||
for (; i != eventNameSize; i += 1)
|
||||
{
|
||||
auto const ch = eventName[i];
|
||||
if ((ch < '0' || '9' < ch) &&
|
||||
(ch < 'A' || 'Z' < ch) &&
|
||||
(ch < 'a' || 'z' < ch))
|
||||
{
|
||||
// Invalid attribute character.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
A TracepointName is a string identifier for a tracepoint on a system.
|
||||
It contains two parts: SystemName and EventName.
|
||||
|
||||
Construct a TracepointName by one of the following:
|
||||
- TracepointName("SystemName", "EventName")
|
||||
- TracepointName("SystemName:EventName")
|
||||
- TracepointName("SystemName/EventName")
|
||||
- TracepointName("EventName") // Uses SystemName = "user_events"
|
||||
*/
|
||||
struct TracepointName
|
||||
{
|
||||
/*
|
||||
SystemName is the name of a subdirectory of
|
||||
"/sys/kernel/tracing/events" such as "user_events" or "ftrace".
|
||||
*/
|
||||
std::string_view SystemName;
|
||||
|
||||
/*
|
||||
EventName is the name of a subdirectory of
|
||||
"/sys/kernel/tracing/events/SystemName" such as "MyEvent" or "function".
|
||||
*/
|
||||
std::string_view EventName;
|
||||
|
||||
/*
|
||||
Create a TracepointName from systemName and eventName, e.g.
|
||||
TracepointName("user_events", "MyEvent_L1K1").
|
||||
|
||||
- systemName is the name of a subdirectory of
|
||||
"/sys/kernel/tracing/events" such as "user_events" or "ftrace".
|
||||
- eventName is the name of a subdirectory of
|
||||
"/sys/kernel/tracing/events/systemName", e.g. "MyEvent" or
|
||||
"function".
|
||||
*/
|
||||
constexpr
|
||||
TracepointName(std::string_view systemName, std::string_view eventName) noexcept
|
||||
: SystemName(systemName)
|
||||
, EventName(eventName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Create a TracepointName from a combined "systemName:eventName" or
|
||||
"systemName/eventName" string. If the string does not contain ':' or '/',
|
||||
the SystemName is assumed to be "user_events".
|
||||
*/
|
||||
explicit constexpr
|
||||
TracepointName(std::string_view systemAndEventName) noexcept
|
||||
: SystemName()
|
||||
, EventName()
|
||||
{
|
||||
auto const splitPos = systemAndEventName.find_first_of(":/", 0, 2);
|
||||
if (splitPos == systemAndEventName.npos)
|
||||
{
|
||||
SystemName = UserEventsSystemName;
|
||||
EventName = systemAndEventName;
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemName = systemAndEventName.substr(0, splitPos);
|
||||
EventName = systemAndEventName.substr(splitPos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Require SystemName and EventName to always be specified.
|
||||
*/
|
||||
TracepointName() = delete;
|
||||
|
||||
/*
|
||||
Returns true if SystemName is a valid tracepoint system name and EventName
|
||||
is a valid tracepoint event name.
|
||||
*/
|
||||
constexpr bool
|
||||
IsValid() const noexcept
|
||||
{
|
||||
return SystemNameIsValid(SystemName) && EventNameIsValid(EventName);
|
||||
}
|
||||
|
||||
/*
|
||||
Returns true if SystemName is a valid tracepoint system name and EventName
|
||||
is a valid EventHeader tracepoint event name.
|
||||
*/
|
||||
constexpr bool
|
||||
IsValidEventHeader() const noexcept
|
||||
{
|
||||
return SystemNameIsValid(SystemName) && EventHeaderEventNameIsValid(EventName);
|
||||
}
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_control
|
||||
|
||||
#endif // _included_TracepointName_h
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Helpers for locating the "/sys/.../tracing" directory and loading "format"
|
||||
files from it.
|
||||
|
||||
The TracepointCache class uses these functions to locate and load format
|
||||
information.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_TracepointPath_h
|
||||
#define _included_TracepointPath_h 1
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _In_z_
|
||||
#define _In_z_
|
||||
#endif
|
||||
#ifndef _Ret_z_
|
||||
#define _Ret_z_
|
||||
#endif
|
||||
#ifndef _Success_
|
||||
#define _Success_(condition)
|
||||
#endif
|
||||
|
||||
namespace tracepoint_control
|
||||
{
|
||||
/*
|
||||
Returns the path to the "/sys/.../tracing" directory, usually either
|
||||
"/sys/kernel/tracing" or "/sys/kernel/debug/tracing".
|
||||
|
||||
Returns "" if no tracing directory could be found (e.g. tracefs not mounted).
|
||||
|
||||
Implementation: The first time this is called, it checks for the existence
|
||||
of "/sys/kernel/tracing/events" and if that is a directory, uses
|
||||
"/sys/kernel/tracing"; otherwise, it parses "/proc/mounts" to find the
|
||||
tracefs or debugfs mount point and uses the corresponding ".../tracing"
|
||||
directory if a mount point is listed; otherwise, returns "".
|
||||
Subsequent calls return the cached result. This function is thread-safe.
|
||||
*/
|
||||
_Ret_z_ char const*
|
||||
GetTracingDirectory() noexcept;
|
||||
|
||||
/*
|
||||
Returns a file descriptor for the user_events_data file. Result will be
|
||||
non-negative on success or negative (-errno) on error.
|
||||
|
||||
Do not close the returned descriptor. Use it only for ioctl and writev.
|
||||
|
||||
Implementation: The first time this is called, it calls GetTracingDirectory()
|
||||
to find the tracefs or debugfs mount point, then opens
|
||||
"TracingDirectory/user_events_data" and caches the result. Subsequent calls
|
||||
return the cached result. This function is thread-safe.
|
||||
*/
|
||||
_Success_(return >= 0) int
|
||||
GetUserEventsDataFile() noexcept;
|
||||
|
||||
/*
|
||||
Given full path to a file, appends the file's contents to the specified
|
||||
dest string.
|
||||
|
||||
Returns 0 for success, errno for error.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
AppendTracingFile(
|
||||
std::vector<char>& dest,
|
||||
_In_z_ char const* fileName) noexcept;
|
||||
|
||||
/*
|
||||
Given systemName and eventName, appends the corresponding event's format
|
||||
data to the specified dest string (i.e. appends the contents of format file
|
||||
"$(tracingDirectory)/events/$(systemName)/$(eventName)/format").
|
||||
|
||||
For example, AppendTracingFormatFile("user_events", "MyEventName", format) would
|
||||
append the contents of "/sys/.../tracing/events/user_events/MyEventName/format"
|
||||
(using the "/sys/.../tracing" directory as returned by GetTracingDirectory()).
|
||||
|
||||
Returns 0 for success, errno for error.
|
||||
*/
|
||||
_Success_(return == 0) int
|
||||
AppendTracingFormatFile(
|
||||
std::vector<char>& dest,
|
||||
std::string_view systemName,
|
||||
std::string_view eventName) noexcept;
|
||||
}
|
||||
// namespace tracepoint_control
|
||||
|
||||
#endif // _included_TracepointPath_h
|
1410
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointSession.h
vendored
Normal file
1410
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointSession.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
106
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointSpec.h
vendored
Normal file
106
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/include/tracepoint/TracepointSpec.h
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
A TracepointSpec stores a view of the information needed to add a tracepoint to
|
||||
a trace collection session. It may or may not have the information needed to
|
||||
pre-register the tracepoint.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_TracepointSpec_h
|
||||
#define _included_TracepointSpec_h 1
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace tracepoint_control
|
||||
{
|
||||
/*
|
||||
Value indicating whether the TracepointSpec is empty, an identifier, a
|
||||
definition, an EventHeader definition, or an error.
|
||||
*/
|
||||
enum class TracepointSpecKind : unsigned char
|
||||
{
|
||||
Empty, // Empty spec, all whitespace, or started with "#" (comment).
|
||||
Identifier, // Name only, event cannot be pre-registered.
|
||||
Definition, // Name plus field information, event can be pre-registered.
|
||||
EventHeaderDefinition, // EventHeader name, event can be pre-registered.
|
||||
|
||||
ErrorIdentifierCannotHaveFields,
|
||||
ErrorIdentifierCannotHaveFlags,
|
||||
ErrorDefinitionCannotHaveColonAfterFlags,
|
||||
ErrorIdentifierEventNameEmpty,
|
||||
ErrorDefinitionEventNameEmpty,
|
||||
ErrorIdentifierEventNameInvalid,
|
||||
ErrorDefinitionEventNameInvalid,
|
||||
ErrorEventHeaderDefinitionEventNameInvalid,
|
||||
ErrorIdentifierSystemNameEmpty,
|
||||
ErrorDefinitionSystemNameEmpty, // Unreachable via specString.
|
||||
ErrorIdentifierSystemNameInvalid,
|
||||
ErrorDefinitionSystemNameInvalid,
|
||||
};
|
||||
|
||||
/*
|
||||
A TracepointSpec stores the information needed to add a tracepoint to a
|
||||
trace collection session.
|
||||
|
||||
The TracepointSpec is either a tracepoint identifier (name only, not enough
|
||||
information to pre-register the tracepoint) or a tracepoint definition
|
||||
(enough information to pre-register the tracepoint if not already
|
||||
registered). A tracepoint definition can be either a normal tracepoint
|
||||
definition (explicitly-specified fields) or an EventHeader tracepoint
|
||||
definition (implicit well-known fields).
|
||||
*/
|
||||
struct TracepointSpec
|
||||
{
|
||||
std::string_view Trimmed = {}; // Input with leading/trailing whitespace removed = Trim(specString).
|
||||
std::string_view SystemName = {}; // e.g. "user_events".
|
||||
std::string_view EventName = {}; // e.g. "MyEvent" or "MyProvider_L2K1Gmygroup".
|
||||
std::string_view Flags = {}; // e.g. "" or "flag1,flag2".
|
||||
std::string_view Fields = {}; // e.g. "" or "u32 Field1; u16 Field2".
|
||||
TracepointSpecKind Kind = {}; // Empty, Identifier, Definition, EventHeaderDefinition, or Error.
|
||||
|
||||
/*
|
||||
Initializes an empty TracepointSpec.
|
||||
*/
|
||||
constexpr
|
||||
TracepointSpec() noexcept = default;
|
||||
|
||||
/*
|
||||
Initializes a TracepointSpec from the specified string.
|
||||
Leading and trailing whitespace is always ignored.
|
||||
If SystemName is not specified, "user_events" is assumed.
|
||||
|
||||
Accepted inputs:
|
||||
|
||||
* Empty string, or string starting with "#" --> Kind = Empty.
|
||||
|
||||
* Leading colon --> Kind = Identifier.
|
||||
|
||||
Examples: ":EventName", ":SystemName:EventName".
|
||||
|
||||
* No leading colon, fields present --> Kind = Definition.
|
||||
|
||||
Use a trailing space + semicolon to indicate no fields. The space is
|
||||
required because semicolons are valid in event names.
|
||||
|
||||
Examples: "EventName ;", "SystemName:EventName:Flags Field1; Field2".
|
||||
|
||||
* No leading colon, no fields present --> Kind = EventHeaderDefinition.
|
||||
|
||||
Examples: "ProviderName_L1K1", or "SystemName:ProviderName_L1KffGgroup:Flags".
|
||||
*/
|
||||
explicit
|
||||
TracepointSpec(std::string_view const specString) noexcept;
|
||||
|
||||
/*
|
||||
Returns specString with all leading and trailing whitespace removed.
|
||||
Uses the same definition of whitespace as the TracepointSpec constructor.
|
||||
*/
|
||||
static std::string_view
|
||||
Trim(std::string_view const specString) noexcept;
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_control
|
||||
|
||||
#endif // _included_TracepointSpec_h
|
20
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/CMakeLists.txt
vendored
Normal file
20
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
add_executable(control-lookup
|
||||
control-lookup.cpp)
|
||||
target_link_libraries(control-lookup
|
||||
PUBLIC tracepoint-control)
|
||||
target_compile_features(control-lookup
|
||||
PRIVATE cxx_std_17)
|
||||
|
||||
add_executable(control-session
|
||||
control-session.cpp)
|
||||
target_link_libraries(control-session
|
||||
PUBLIC tracepoint-control tracepoint-decode)
|
||||
target_compile_features(control-session
|
||||
PRIVATE cxx_std_17)
|
||||
|
||||
add_executable(save-session
|
||||
save-session.cpp)
|
||||
target_link_libraries(save-session
|
||||
PUBLIC tracepoint-control tracepoint-decode)
|
||||
target_compile_features(save-session
|
||||
PRIVATE cxx_std_17)
|
53
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/control-lookup.cpp
vendored
Normal file
53
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/control-lookup.cpp
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Demonstrates use of TracepointCache to look up tracefs metadata.
|
||||
*/
|
||||
|
||||
#include <tracepoint/TracepointCache.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace tracepoint_control;
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
TracepointCache cache;
|
||||
for (int argi = 1; argi < argc; argi += 1)
|
||||
{
|
||||
int error;
|
||||
auto const name = TracepointName(argv[argi]);
|
||||
|
||||
error = cache.AddFromSystem(name);
|
||||
fprintf(stdout, "AddFromSystem(%.*s:%.*s)=%u\n",
|
||||
(unsigned)name.SystemName.size(), name.SystemName.data(),
|
||||
(unsigned)name.EventName.size(), name.EventName.data(),
|
||||
error);
|
||||
|
||||
unsigned id = 0;
|
||||
if (auto const meta = cache.FindByName(name); meta)
|
||||
{
|
||||
fprintf(stdout, "- FindByName=%u\n", meta->Id());
|
||||
fprintf(stdout, " Sys = %.*s\n", (unsigned)meta->SystemName().size(), meta->SystemName().data());
|
||||
fprintf(stdout, " Name= %.*s\n", (unsigned)meta->Name().size(), meta->Name().data());
|
||||
fprintf(stdout, " Fmt = %.*s\n", (unsigned)meta->PrintFmt().size(), meta->PrintFmt().data());
|
||||
fprintf(stdout, " Flds= %u\n", (unsigned)meta->Fields().size());
|
||||
fprintf(stdout, " Id = %u\n", (unsigned)meta->Id());
|
||||
fprintf(stdout, " CmnC= %u\n", (unsigned)meta->CommonFieldCount());
|
||||
fprintf(stdout, " Kind= %u\n", (unsigned)meta->Kind());
|
||||
id = meta->Id();
|
||||
}
|
||||
|
||||
if (auto const meta = cache.FindById(id); meta)
|
||||
{
|
||||
fprintf(stdout, "- FindById(%u)=%u\n", id, meta->Id());
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "CommonTypeOffset=%d\n", cache.CommonTypeOffset());
|
||||
fprintf(stdout, "CommonTypeSize =%u\n", cache.CommonTypeSize());
|
||||
|
||||
return 0;
|
||||
}
|
135
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/control-session.cpp
vendored
Normal file
135
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/control-session.cpp
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/TracepointSession.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <tracepoint/PerfEventAbi.h>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace tracepoint_control;
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (argc < 2 ||
|
||||
(0 != strcmp(argv[1], "0") && 0 != strcmp(argv[1], "1")))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: control-session [0|1] systemName:eventName ...\n"
|
||||
"0 = circular, 1 = realtime\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto const mode = 0 == strcmp(argv[1], "0")
|
||||
? TracepointSessionMode::Circular
|
||||
: TracepointSessionMode::RealTime;
|
||||
|
||||
TracepointCache cache;
|
||||
TracepointSession session(
|
||||
cache,
|
||||
TracepointSessionOptions(mode, 0) // 0 should round up to a 1-page buffer.
|
||||
.WakeupWatermark(100)); // WaitForWakeup waits for a buffer to have >= 100 bytes of data.
|
||||
|
||||
fprintf(stderr, "Session: BC=%u BS=%x RT=%u MODE=%u\n",
|
||||
session.BufferCount(), session.BufferSize(), session.IsRealtime(), (unsigned)session.Mode());
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for (int argi = 2; argi < argc; argi += 1)
|
||||
{
|
||||
TracepointName name(argv[argi]);
|
||||
error = cache.AddFromSystem(name);
|
||||
if (error != ENOENT || name.SystemName != UserEventsSystemName ||
|
||||
!name.IsValidEventHeader())
|
||||
{
|
||||
fprintf(stderr, "AddFromSystem(%s) = %u\n", argv[argi], error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// User-specified EventHeader event is not registered.
|
||||
// Pre-register it and try to collect it anyway.
|
||||
error = cache.PreregisterEventHeaderTracepoint(name);
|
||||
fprintf(stderr, "PreregisterEventHeaderTracepoint(%s) = %u\n", argv[argi], error);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
unsigned enabled = 0;
|
||||
for (int argi = 2; argi < argc; argi += 1)
|
||||
{
|
||||
error = session.EnableTracepoint(TracepointName(argv[argi]));
|
||||
fprintf(stderr, "EnableTracepoint(%s) = %u\n", argv[argi], error);
|
||||
enabled += error == 0;
|
||||
}
|
||||
|
||||
if (enabled == 0)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (mode == TracepointSessionMode::Circular)
|
||||
{
|
||||
sleep(5);
|
||||
}
|
||||
else
|
||||
{
|
||||
int activeCount;
|
||||
error = session.WaitForWakeup(nullptr, nullptr, &activeCount);
|
||||
fprintf(stderr, "WaitForWakeup() = %u, active = %d\n", error, activeCount);
|
||||
if (error != 0)
|
||||
{
|
||||
sleep(5);
|
||||
}
|
||||
}
|
||||
|
||||
error = session.EnumerateSampleEventsUnordered(
|
||||
[](PerfSampleEventInfo const& event) -> int
|
||||
{
|
||||
auto ts = event.session_info->TimeToRealTime(event.time);
|
||||
time_t const secs = (time_t)ts.tv_sec;
|
||||
tm t = {};
|
||||
gmtime_r(&secs, &t);
|
||||
fprintf(stdout, "CPU%u: tid=%x time=%04u-%02u-%02uT%02u:%02u:%02u.%09uZ raw=0x%lx n=%s\n",
|
||||
event.cpu,
|
||||
event.tid,
|
||||
1900 + t.tm_year, 1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec, ts.tv_nsec,
|
||||
(long unsigned)event.raw_data_size,
|
||||
event.Name());
|
||||
return 0;
|
||||
});
|
||||
fprintf(stderr, "Enum: %u, Count=%llu, Lost=%llu, Bad=%llu, BadBuf=%llu\n",
|
||||
error,
|
||||
(long long unsigned)session.SampleEventCount(),
|
||||
(long long unsigned)session.LostEventCount(),
|
||||
(long long unsigned)session.CorruptEventCount(),
|
||||
(long long unsigned)session.CorruptBufferCount());
|
||||
for (auto& info : session.TracepointInfos())
|
||||
{
|
||||
auto& metadata = info.Metadata();
|
||||
auto name = metadata.Name();
|
||||
uint64_t count = 0;
|
||||
error = info.GetEventCount(&count);
|
||||
fprintf(stderr, " %.*s EnableState=%u Count=%llu Err=%u\n",
|
||||
(int)name.size(), name.data(),
|
||||
(int)info.EnableState(),
|
||||
(long long unsigned)count,
|
||||
error);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
107
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/save-session.cpp
vendored
Normal file
107
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/samples/save-session.cpp
vendored
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Demonstrates the use of SavePerfDataFile to save session data to a perf file.
|
||||
*/
|
||||
|
||||
#include <tracepoint/TracepointSession.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace tracepoint_control;
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int error = 0;
|
||||
TracepointTimestampRange writtenRange;
|
||||
|
||||
if (argc < 3 ||
|
||||
(0 != strcmp(argv[1], "0") && 0 != strcmp(argv[1], "1")))
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: save-session [0|1] outFileName systemName:eventName ...\n"
|
||||
"0 = circular, 1 = realtime\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto const mode = 0 == strcmp(argv[1], "0")
|
||||
? TracepointSessionMode::Circular
|
||||
: TracepointSessionMode::RealTime;
|
||||
|
||||
TracepointCache cache;
|
||||
TracepointSession session(cache, mode, 0); // 0 should round up to a 1-page buffer.
|
||||
|
||||
fprintf(stderr, "Session: BC=%u BS=%x RT=%u MODE=%u\n",
|
||||
session.BufferCount(), session.BufferSize(), session.IsRealtime(), (unsigned)session.Mode());
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
for (int argi = 3; argi < argc; argi += 1)
|
||||
{
|
||||
TracepointName name(argv[argi]);
|
||||
error = cache.AddFromSystem(name);
|
||||
if (error != ENOENT || name.SystemName != UserEventsSystemName ||
|
||||
!name.IsValidEventHeader())
|
||||
{
|
||||
fprintf(stderr, "AddFromSystem(%s) = %u\n", argv[argi], error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// User-specified EventHeader event is not registered.
|
||||
// Pre-register it and try to collect it anyway.
|
||||
error = cache.PreregisterEventHeaderTracepoint(name);
|
||||
fprintf(stderr, "PreregisterEventHeaderTracepoint(%s) = %u\n", argv[argi], error);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
unsigned enabled = 0;
|
||||
for (int argi = 3; argi < argc; argi += 1)
|
||||
{
|
||||
error = session.EnableTracepoint(TracepointName(argv[argi]));
|
||||
fprintf(stderr, "EnableTracepoint(%s) = %u\n", argv[argi], error);
|
||||
enabled += error == 0;
|
||||
}
|
||||
|
||||
if (enabled == 0)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
for (unsigned i = 0;; i += 1)
|
||||
{
|
||||
printf("\nPress enter to iterate, x + enter to exit...\n");
|
||||
char ch = (char)getchar();
|
||||
if (ch == 'x' || ch == 'X')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
while (ch != '\n')
|
||||
{
|
||||
ch = (char)getchar();
|
||||
}
|
||||
|
||||
char outFileName[256];
|
||||
snprintf(outFileName, sizeof(outFileName), "%s.%u", argv[2], i);
|
||||
|
||||
// CodeQL [SM01937] This is a sample/tool. Using externally-supplied path is intended behavior.
|
||||
error = session.SavePerfDataFile(
|
||||
outFileName,
|
||||
TracepointSavePerfDataFileOptions()
|
||||
.TimestampFilter(writtenRange.Last) // For circular, filter out old events.
|
||||
.TimestampWrittenRange(&writtenRange));
|
||||
printf("SavePerfDataFile(%s) = %u\n", outFileName, error);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
42
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/CMakeLists.txt
vendored
Normal file
42
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
# tracepoint-control = libtracepoint-control, CONTROL_HEADERS
|
||||
add_library(tracepoint-control
|
||||
"TracepointCache.cpp"
|
||||
"TracepointPath.cpp"
|
||||
"TracepointSession.cpp"
|
||||
"TracepointSpec.cpp"
|
||||
"UniqueHandles.cpp")
|
||||
target_include_directories(tracepoint-control
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
target_link_libraries(tracepoint-control
|
||||
PUBLIC tracepoint-decode atomic)
|
||||
set(CONTROL_HEADERS
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/TracepointCache.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/TracepointName.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/TracepointPath.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/TracepointSession.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/TracepointSpec.h")
|
||||
set_target_properties(tracepoint-control PROPERTIES
|
||||
PUBLIC_HEADER "${CONTROL_HEADERS}")
|
||||
target_compile_features(tracepoint-control
|
||||
PRIVATE cxx_std_17)
|
||||
install(TARGETS tracepoint-control
|
||||
EXPORT tracepoint-controlTargets
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracepoint)
|
||||
install(EXPORT tracepoint-controlTargets
|
||||
FILE "tracepoint-controlTargets.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tracepoint-control")
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tracepoint-controlConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-controlConfig.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tracepoint-control"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-controlConfigVersion.cmake"
|
||||
COMPATIBILITY SameMinorVersion)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-controlConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-controlConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tracepoint-control")
|
606
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointCache.cpp
vendored
Normal file
606
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointCache.cpp
vendored
Normal file
|
@ -0,0 +1,606 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/TracepointCache.h>
|
||||
#include <tracepoint/TracepointSpec.h>
|
||||
#include <tracepoint/TracepointPath.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
//#include <linux/user_events.h>
|
||||
struct user_reg63 {
|
||||
|
||||
/* Input: Size of the user_reg structure being used */
|
||||
__u32 size;
|
||||
|
||||
/* Input: Bit in enable address to use */
|
||||
__u8 enable_bit;
|
||||
|
||||
/* Input: Enable size in bytes at address */
|
||||
__u8 enable_size;
|
||||
|
||||
/* Input: Flags for future use, set to 0 */
|
||||
__u16 flags;
|
||||
|
||||
/* Input: Address to update when enabled */
|
||||
__u64 enable_addr;
|
||||
|
||||
/* Input: Pointer to string with event name, description and flags */
|
||||
__u64 name_args;
|
||||
|
||||
/* Output: Index of the event to use when writing data */
|
||||
__u32 write_index;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/*
|
||||
* Describes an event unregister, callers must set the size, address and bit.
|
||||
* This structure is passed to the DIAG_IOCSUNREG ioctl to disable bit updates.
|
||||
*/
|
||||
struct user_unreg63 {
|
||||
/* Input: Size of the user_unreg structure being used */
|
||||
__u32 size;
|
||||
|
||||
/* Input: Bit to unregister */
|
||||
__u8 disable_bit;
|
||||
|
||||
/* Input: Reserved, set to 0 */
|
||||
__u8 __reserved;
|
||||
|
||||
/* Input: Reserved, set to 0 */
|
||||
__u16 __reserved2;
|
||||
|
||||
/* Input: Address to unregister */
|
||||
__u64 disable_addr;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define DIAG_IOC_MAGIC '*'
|
||||
#define DIAG_IOCSREG _IOWR(DIAG_IOC_MAGIC, 0, struct user_reg63*)
|
||||
#define DIAG_IOCSDEL _IOW(DIAG_IOC_MAGIC, 1, char*)
|
||||
#define DIAG_IOCSUNREG _IOW(DIAG_IOC_MAGIC, 2, struct user_unreg63*)
|
||||
|
||||
//#include <eventheader.h>
|
||||
#define EVENTHEADER_COMMAND_TYPES "u8 eventheader_flags; u8 version; u16 id; u16 tag; u8 opcode; u8 level"
|
||||
enum {
|
||||
// Maximum length of a Tracepoint name "ProviderName_Attributes", including nul termination.
|
||||
EVENTHEADER_NAME_MAX = 256,
|
||||
|
||||
// Maximum length needed for a DIAG_IOCSREG command "ProviderName_Attributes CommandTypes".
|
||||
EVENTHEADER_COMMAND_MAX = EVENTHEADER_NAME_MAX + sizeof(EVENTHEADER_COMMAND_TYPES)
|
||||
};
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace tracepoint_control;
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
static constexpr int8_t CommonTypeOffsetInit = -1;
|
||||
static constexpr uint8_t CommonTypeSizeInit = 0;
|
||||
|
||||
TracepointCache::TracepointRegistration::~TracepointRegistration()
|
||||
{
|
||||
if (WriteIndex >= 0)
|
||||
{
|
||||
user_unreg63 unreg = {};
|
||||
unreg.size = sizeof(user_unreg63);
|
||||
unreg.disable_bit = 0;
|
||||
unreg.disable_addr = (uintptr_t)&StatusWord;
|
||||
ioctl(DataFile, DIAG_IOCSUNREG, &unreg);
|
||||
}
|
||||
}
|
||||
|
||||
TracepointCache::TracepointRegistration::TracepointRegistration() noexcept
|
||||
: DataFile(-1)
|
||||
, WriteIndex(-1)
|
||||
, StatusWord(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointCache::CacheVal::~CacheVal()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointCache::CacheVal::CacheVal(
|
||||
std::vector<char>&& systemAndFormat,
|
||||
PerfEventMetadata&& metadata,
|
||||
std::unique_ptr<TracepointRegistration> registration) noexcept
|
||||
: SystemAndFormat(std::move(systemAndFormat))
|
||||
, Metadata(metadata)
|
||||
, Registration(std::move(registration))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t
|
||||
TracepointCache::NameHashOps::operator()(
|
||||
TracepointName const& a) const noexcept
|
||||
{
|
||||
std::hash<std::string_view> const hasher;
|
||||
return hasher(a.EventName) ^ hasher(a.SystemName);
|
||||
}
|
||||
|
||||
size_t
|
||||
TracepointCache::NameHashOps::operator()(
|
||||
TracepointName const& a,
|
||||
TracepointName const& b) const noexcept
|
||||
{
|
||||
return a.EventName == b.EventName && a.SystemName == b.SystemName;
|
||||
}
|
||||
|
||||
TracepointCache::~TracepointCache() noexcept
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointCache::TracepointCache() noexcept(false)
|
||||
: m_byId() // may throw bad_alloc (but probably doesn't).
|
||||
, m_byName() // may throw bad_alloc (but probably doesn't).
|
||||
, m_commonTypeOffset(CommonTypeOffsetInit)
|
||||
, m_commonTypeSize(CommonTypeSizeInit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int8_t
|
||||
TracepointCache::CommonTypeOffset() const noexcept
|
||||
{
|
||||
return m_commonTypeOffset;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
TracepointCache::CommonTypeSize() const noexcept
|
||||
{
|
||||
return m_commonTypeSize;
|
||||
}
|
||||
|
||||
PerfEventMetadata const*
|
||||
TracepointCache::FindById(uint32_t id) const noexcept
|
||||
{
|
||||
auto it = m_byId.find(id);
|
||||
return it == m_byId.end()
|
||||
? nullptr
|
||||
: &it->second.Metadata;
|
||||
}
|
||||
|
||||
PerfEventMetadata const*
|
||||
TracepointCache::FindByName(TracepointName const& name) const noexcept
|
||||
{
|
||||
auto it = m_byName.find(name);
|
||||
return it == m_byName.end()
|
||||
? nullptr
|
||||
: &it->second.Metadata;
|
||||
}
|
||||
|
||||
PerfEventMetadata const*
|
||||
TracepointCache::FindByRawData(std::string_view rawData) const noexcept
|
||||
{
|
||||
PerfEventMetadata const* metadata;
|
||||
|
||||
auto const offset = static_cast<size_t>(m_commonTypeOffset);
|
||||
auto const commonTypeSize = m_commonTypeSize;
|
||||
auto const rawDataSize = rawData.size();
|
||||
if (rawDataSize <= offset ||
|
||||
rawDataSize - offset <= commonTypeSize)
|
||||
{
|
||||
metadata = nullptr;
|
||||
}
|
||||
else if (commonTypeSize == sizeof(uint16_t))
|
||||
{
|
||||
uint16_t commonType;
|
||||
memcpy(&commonType, rawData.data() + offset, sizeof(commonType));
|
||||
metadata = FindById(commonType);
|
||||
}
|
||||
else if (commonTypeSize == sizeof(uint32_t))
|
||||
{
|
||||
uint32_t commonType;
|
||||
memcpy(&commonType, rawData.data() + offset, sizeof(commonType));
|
||||
metadata = FindById(commonType);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(commonTypeSize == 1);
|
||||
uint8_t commonType;
|
||||
memcpy(&commonType, rawData.data() + offset, sizeof(commonType));
|
||||
metadata = FindById(commonType);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::AddFromFormat(
|
||||
std::string_view systemName,
|
||||
std::string_view formatFileContents,
|
||||
bool longSize64) noexcept
|
||||
{
|
||||
int error;
|
||||
|
||||
try
|
||||
{
|
||||
std::vector<char> systemAndFormat;
|
||||
systemAndFormat.reserve(systemName.size() + 1 + formatFileContents.size()); // may throw
|
||||
systemAndFormat.assign(systemName.begin(), systemName.end());
|
||||
systemAndFormat.push_back('\n'); // For readability when debugging.
|
||||
systemAndFormat.insert(systemAndFormat.end(), formatFileContents.begin(), formatFileContents.end());
|
||||
error = Add(std::move(systemAndFormat), systemName.size(), longSize64, nullptr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::AddFromSystem(TracepointName const& name) noexcept
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!name.IsValid())
|
||||
{
|
||||
error = EINVAL;
|
||||
}
|
||||
else try
|
||||
{
|
||||
std::vector<char> systemAndFormat;
|
||||
systemAndFormat.reserve(name.SystemName.size() + 512); // may throw
|
||||
systemAndFormat.assign(name.SystemName.begin(), name.SystemName.end());
|
||||
systemAndFormat.push_back('\n'); // For readability when debugging.
|
||||
error = AppendTracingFormatFile(systemAndFormat, name.SystemName, name.EventName);
|
||||
if (error == 0)
|
||||
{
|
||||
error = Add(std::move(systemAndFormat), name.SystemName.size(), sizeof(long) == 8, nullptr);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::FindOrAddFromSystem(
|
||||
TracepointName const& name,
|
||||
_Out_ PerfEventMetadata const** ppMetadata) noexcept
|
||||
{
|
||||
int error;
|
||||
PerfEventMetadata const* metadata;
|
||||
|
||||
auto it = m_byName.find(name);
|
||||
if (it != m_byName.end())
|
||||
{
|
||||
error = 0;
|
||||
metadata = &it->second.Metadata;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = AddFromSystem(name);
|
||||
metadata = error ? nullptr : FindByName(name);
|
||||
}
|
||||
|
||||
*ppMetadata = metadata;
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::PreregisterEventHeaderTracepoint(TracepointName const& name) noexcept
|
||||
{
|
||||
if (name.SystemName != UserEventsSystemName ||
|
||||
!EventHeaderEventNameIsValid(name.EventName))
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
auto const eventNameSize = (unsigned)name.EventName.size();
|
||||
char command[EVENTHEADER_COMMAND_MAX];
|
||||
snprintf(command, sizeof(command), "%.*s %s",
|
||||
eventNameSize, name.EventName.data(),
|
||||
EVENTHEADER_COMMAND_TYPES);
|
||||
auto error = PreregisterTracepointImpl(command, eventNameSize);
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::PreregisterTracepointDefinition(TracepointSpec const& spec) noexcept
|
||||
{
|
||||
int error;
|
||||
|
||||
if (spec.SystemName != UserEventsSystemName ||
|
||||
spec.Flags.size() > 65536 ||
|
||||
spec.Fields.size() > 65536)
|
||||
{
|
||||
error = EINVAL;
|
||||
}
|
||||
else try
|
||||
{
|
||||
auto const eventNameSize = (unsigned)spec.EventName.size();
|
||||
char commandStack[EVENTHEADER_COMMAND_MAX];
|
||||
std::vector<char> commandHeap;
|
||||
char* command;
|
||||
|
||||
if (spec.Kind == TracepointSpecKind::Definition)
|
||||
{
|
||||
if (!EventNameIsValid(spec.EventName))
|
||||
{
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
size_t const commandSize =
|
||||
eventNameSize
|
||||
+ 1 + spec.Flags.size()
|
||||
+ 1 + spec.Fields.size()
|
||||
+ 1;
|
||||
if (commandSize <= sizeof(commandStack))
|
||||
{
|
||||
command = commandStack;
|
||||
}
|
||||
else
|
||||
{
|
||||
commandHeap.reserve(commandSize); // may throw
|
||||
command = commandHeap.data();
|
||||
}
|
||||
|
||||
snprintf(command, commandSize, "%.*s%s%.*s%s%.*s",
|
||||
eventNameSize, spec.EventName.data(),
|
||||
spec.Flags.empty() ? "" : ":",
|
||||
(unsigned)spec.Flags.size(), spec.Flags.data(),
|
||||
spec.Fields.empty() ? "" : " ",
|
||||
(unsigned)spec.Fields.size(), spec.Fields.data());
|
||||
}
|
||||
else if (spec.Kind == TracepointSpecKind::EventHeaderDefinition)
|
||||
{
|
||||
if (!EventHeaderEventNameIsValid(spec.EventName))
|
||||
{
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
size_t const commandSize =
|
||||
eventNameSize
|
||||
+ 1 + spec.Flags.size()
|
||||
+ sizeof(EVENTHEADER_COMMAND_TYPES)
|
||||
+ 1;
|
||||
if (commandSize <= sizeof(commandStack))
|
||||
{
|
||||
command = commandStack;
|
||||
}
|
||||
else
|
||||
{
|
||||
commandHeap.reserve(commandSize); // may throw
|
||||
command = commandHeap.data();
|
||||
}
|
||||
|
||||
snprintf(command, commandSize, "%.*s%s%.*s %s",
|
||||
eventNameSize, spec.EventName.data(),
|
||||
spec.Flags.empty() ? "" : ":",
|
||||
(unsigned)spec.Flags.size(), spec.Flags.data(),
|
||||
EVENTHEADER_COMMAND_TYPES);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = EINVAL; // Unexpected spec.Kind.
|
||||
goto Done;
|
||||
}
|
||||
|
||||
error = PreregisterTracepointImpl(command, eventNameSize);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::PreregisterTracepoint(_In_z_ char const* registerCommand) noexcept
|
||||
{
|
||||
int error;
|
||||
unsigned eventNameSize;
|
||||
for (eventNameSize = 0;; eventNameSize += 1)
|
||||
{
|
||||
auto ch = registerCommand[eventNameSize];
|
||||
if (ch == 0 || ch == ' ' || ch == ':')
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (eventNameSize > EventNameMaxSize)
|
||||
{
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
}
|
||||
|
||||
if (!EventNameIsValid({ registerCommand, eventNameSize }))
|
||||
{
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
error = PreregisterTracepointImpl(registerCommand, eventNameSize);
|
||||
|
||||
Done:
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::PreregisterTracepointImpl(_In_z_ char const* registerCommand, unsigned eventNameSize) noexcept
|
||||
{
|
||||
int error;
|
||||
auto const name = TracepointName(UserEventsSystemName, { registerCommand, eventNameSize });
|
||||
assert(EventNameIsValid(name.EventName)); // Precondition ensured by caller.
|
||||
if (m_byName.find(name) != m_byName.end())
|
||||
{
|
||||
error = EALREADY;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto registration = std::make_unique<TracepointRegistration>();
|
||||
|
||||
auto const dataFile = GetUserEventsDataFile();
|
||||
if (dataFile < 0)
|
||||
{
|
||||
error = -dataFile;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
user_reg63 reg = {};
|
||||
reg.size = sizeof(reg);
|
||||
reg.enable_bit = 0;
|
||||
reg.enable_size = sizeof(registration->StatusWord);
|
||||
reg.enable_addr = (uintptr_t)®istration->StatusWord;
|
||||
reg.name_args = (uintptr_t)registerCommand;
|
||||
|
||||
if (0 > ioctl(dataFile, DIAG_IOCSREG, ®))
|
||||
{
|
||||
error = errno;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
assert(reg.write_index <= 0x7fffffff);
|
||||
registration->DataFile = dataFile;
|
||||
registration->WriteIndex = static_cast<int>(reg.write_index);
|
||||
|
||||
std::vector<char> systemAndFormat;
|
||||
systemAndFormat.reserve(name.SystemName.size() + 512); // may throw
|
||||
systemAndFormat.assign(name.SystemName.begin(), name.SystemName.end());
|
||||
systemAndFormat.push_back('\n'); // For readability when debugging.
|
||||
error = AppendTracingFormatFile(systemAndFormat, name.SystemName, name.EventName);
|
||||
if (error == 0)
|
||||
{
|
||||
error = Add(
|
||||
std::move(systemAndFormat),
|
||||
name.SystemName.size(),
|
||||
sizeof(long) == 8,
|
||||
std::move(registration));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
TracepointCache::Add(
|
||||
std::vector<char>&& systemAndFormat,
|
||||
size_t systemNameSize,
|
||||
bool longSize64,
|
||||
std::unique_ptr<TracepointRegistration> registration) noexcept
|
||||
{
|
||||
int error;
|
||||
uint32_t id = 0;
|
||||
bool idAdded = false;
|
||||
|
||||
try
|
||||
{
|
||||
assert(systemNameSize < systemAndFormat.size());
|
||||
auto systemName = std::string_view(systemAndFormat.data(), systemNameSize);
|
||||
auto formatFile = std::string_view(
|
||||
systemAndFormat.data() + systemNameSize + 1,
|
||||
systemAndFormat.size() - systemNameSize - 1);
|
||||
|
||||
PerfEventMetadata metadata;
|
||||
if (!metadata.Parse(longSize64, systemName, formatFile))
|
||||
{
|
||||
error = EINVAL;
|
||||
}
|
||||
else if (auto name = TracepointName(metadata.SystemName(), metadata.Name());
|
||||
!name.IsValid())
|
||||
{
|
||||
error = EINVAL;
|
||||
}
|
||||
else if (
|
||||
m_byId.end() != m_byId.find(metadata.Id()) ||
|
||||
m_byName.end() != m_byName.find(name))
|
||||
{
|
||||
error = EEXIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
int8_t commonTypeOffset = CommonTypeOffsetInit;
|
||||
uint8_t commonTypeSize = CommonTypeSizeInit;
|
||||
for (unsigned i = 0; i != metadata.CommonFieldCount(); i += 1)
|
||||
{
|
||||
auto const& field = metadata.Fields()[i];
|
||||
if (field.Name() == "common_type"sv)
|
||||
{
|
||||
if (field.Offset() < 128 &&
|
||||
(field.Size() == 1 || field.Size() == 2 || field.Size() == 4) &&
|
||||
field.Array() == PerfFieldArrayNone)
|
||||
{
|
||||
commonTypeOffset = static_cast<int8_t>(field.Offset());
|
||||
commonTypeSize = static_cast<uint8_t>(field.Size());
|
||||
|
||||
if (m_commonTypeOffset == CommonTypeOffsetInit)
|
||||
{
|
||||
// First event to be parsed. Use its "common_type" field.
|
||||
assert(m_commonTypeSize == CommonTypeSizeInit);
|
||||
m_commonTypeOffset = commonTypeOffset;
|
||||
m_commonTypeSize = commonTypeSize;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (commonTypeOffset == CommonTypeOffsetInit)
|
||||
{
|
||||
// Did not find a usable "common_type" field.
|
||||
error = EINVAL;
|
||||
}
|
||||
else if (
|
||||
m_commonTypeOffset != commonTypeOffset ||
|
||||
m_commonTypeSize != commonTypeSize)
|
||||
{
|
||||
// Unexpected: found a different "common_type" field.
|
||||
error = EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = metadata.Id();
|
||||
|
||||
auto er = m_byId.try_emplace(
|
||||
id,
|
||||
std::move(systemAndFormat),
|
||||
std::move(metadata),
|
||||
std::move(registration));
|
||||
assert(er.second);
|
||||
idAdded = er.second;
|
||||
m_byName.try_emplace(name, er.first->second);
|
||||
|
||||
error = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (idAdded)
|
||||
{
|
||||
m_byId.erase(id);
|
||||
}
|
||||
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
349
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointPath.cpp
vendored
Normal file
349
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointPath.cpp
vendored
Normal file
|
@ -0,0 +1,349 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/TracepointPath.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
static constexpr unsigned TRACING_DIR_MAX = 256;
|
||||
|
||||
static int
|
||||
IsSpaceChar(char ch)
|
||||
{
|
||||
return ch == ' ' || ch == '\t';
|
||||
}
|
||||
|
||||
static int
|
||||
IsNonSpaceChar(char ch)
|
||||
{
|
||||
return ch != '\0' && !IsSpaceChar(ch);
|
||||
}
|
||||
|
||||
static int
|
||||
GetFailureErrno(void)
|
||||
{
|
||||
int err = errno;
|
||||
assert(err > 0);
|
||||
if (err <= 0)
|
||||
{
|
||||
err = ENOENT;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static _Ret_z_ char const*
|
||||
UpdateTracingDirectory(char const** pStaticTracingDir) noexcept
|
||||
{
|
||||
static pthread_mutex_t staticTracingDirMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_mutex_lock(&staticTracingDirMutex);
|
||||
|
||||
auto tracingDir = __atomic_load_n(pStaticTracingDir, __ATOMIC_RELAXED); // CONSUME semantics.
|
||||
if (tracingDir == nullptr)
|
||||
{
|
||||
static char staticTracingDirBuffer[TRACING_DIR_MAX + 1];
|
||||
|
||||
#define SYS_KERNEL_TRACING "/sys/kernel/tracing"
|
||||
|
||||
struct stat eventsStat = {};
|
||||
if (!stat(SYS_KERNEL_TRACING "/events", &eventsStat) && S_ISDIR(eventsStat.st_mode))
|
||||
{
|
||||
memcpy(staticTracingDirBuffer, SYS_KERNEL_TRACING, sizeof(SYS_KERNEL_TRACING));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const mountsFile = fopen("/proc/mounts", "r");
|
||||
if (mountsFile != nullptr)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
char line[4097];
|
||||
if (!fgets(line, sizeof(line), mountsFile))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// line is "deviceName mountPoint fileSystem otherStuff..."
|
||||
|
||||
size_t linePos = 0;
|
||||
|
||||
// deviceName
|
||||
while (IsNonSpaceChar(line[linePos]))
|
||||
{
|
||||
linePos += 1;
|
||||
}
|
||||
|
||||
// whitespace
|
||||
while (IsSpaceChar(line[linePos]))
|
||||
{
|
||||
linePos += 1;
|
||||
}
|
||||
|
||||
// mountPoint
|
||||
auto const mountPointBegin = linePos;
|
||||
while (IsNonSpaceChar(line[linePos]))
|
||||
{
|
||||
linePos += 1;
|
||||
}
|
||||
auto const mountPointEnd = linePos;
|
||||
|
||||
// whitespace
|
||||
while (IsSpaceChar(line[linePos]))
|
||||
{
|
||||
linePos += 1;
|
||||
}
|
||||
|
||||
// fileSystem
|
||||
auto const fileSystemBegin = linePos;
|
||||
while (IsNonSpaceChar(line[linePos]))
|
||||
{
|
||||
linePos += 1;
|
||||
}
|
||||
auto const fileSystemEnd = linePos;
|
||||
|
||||
if (!IsSpaceChar(line[linePos]))
|
||||
{
|
||||
// Ignore line if no whitespace after fileSystem.
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string_view const fileSystem(line + fileSystemBegin, fileSystemEnd - fileSystemBegin);
|
||||
std::string_view pathSuffix;
|
||||
bool keepLooking;
|
||||
if (fileSystem == "tracefs"sv)
|
||||
{
|
||||
// "tracefsMountPoint"
|
||||
pathSuffix = ""sv;
|
||||
keepLooking = false; // prefer "tracefs" over "debugfs".
|
||||
}
|
||||
else if (staticTracingDirBuffer[0] == 0 &&
|
||||
fileSystem == "debugfs"sv)
|
||||
{
|
||||
// "debugfsMountPoint/tracing"
|
||||
pathSuffix = "/tracing"sv;
|
||||
keepLooking = true; // prefer "tracefs" over "debugfs".
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const mountPointLen = mountPointEnd - mountPointBegin;
|
||||
auto const pathLen = mountPointLen + pathSuffix.size() + 1; // includes NUL
|
||||
if (pathLen > sizeof(staticTracingDirBuffer))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// path = mountpoint + suffix, e.g. "/sys/kernel/tracing\0"
|
||||
memcpy(staticTracingDirBuffer, line + mountPointBegin, mountPointLen);
|
||||
memcpy(staticTracingDirBuffer + mountPointLen, pathSuffix.data(), pathSuffix.size() + 1); // includes NUL
|
||||
|
||||
if (!keepLooking)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(mountsFile);
|
||||
}
|
||||
}
|
||||
|
||||
tracingDir = staticTracingDirBuffer;
|
||||
__atomic_store_n(pStaticTracingDir, tracingDir, __ATOMIC_RELEASE); // CONSUME semantics.
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&staticTracingDirMutex);
|
||||
return tracingDir;
|
||||
}
|
||||
|
||||
_Ret_z_ char const*
|
||||
tracepoint_control::GetTracingDirectory() noexcept
|
||||
{
|
||||
static char const* staticTracingDir = nullptr;
|
||||
|
||||
auto tracingDir = __atomic_load_n(&staticTracingDir, __ATOMIC_RELAXED); // CONSUME semantics.
|
||||
if (tracingDir == nullptr)
|
||||
{
|
||||
tracingDir = UpdateTracingDirectory(&staticTracingDir);
|
||||
}
|
||||
|
||||
return tracingDir;
|
||||
}
|
||||
|
||||
static _Success_(return >= 0) int
|
||||
UpdateUserEventsDataFile(int* pStaticFile) noexcept
|
||||
{
|
||||
int newFileOrError;
|
||||
|
||||
if (auto const tracingDir = tracepoint_control::GetTracingDirectory();
|
||||
tracingDir[0] == 0)
|
||||
{
|
||||
// Unable to find the "/.../tracing" directory.
|
||||
newFileOrError = -ENOTSUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
#define USER_EVENTS_DATA "/user_events_data"
|
||||
char fileName[TRACING_DIR_MAX + sizeof(USER_EVENTS_DATA)];
|
||||
auto const cchTracingDir = strlen(tracingDir);
|
||||
assert(cchTracingDir <= TRACING_DIR_MAX);
|
||||
memcpy(fileName, tracingDir, cchTracingDir);
|
||||
memcpy(fileName + cchTracingDir, USER_EVENTS_DATA, sizeof(USER_EVENTS_DATA));
|
||||
|
||||
newFileOrError = open(fileName, O_WRONLY);
|
||||
if (0 > newFileOrError)
|
||||
{
|
||||
newFileOrError = -GetFailureErrno();
|
||||
}
|
||||
}
|
||||
|
||||
int oldFileOrError = -EAGAIN;
|
||||
for (;;)
|
||||
{
|
||||
if (__atomic_compare_exchange_n(
|
||||
pStaticFile,
|
||||
&oldFileOrError,
|
||||
newFileOrError,
|
||||
0,
|
||||
__ATOMIC_RELAXED,
|
||||
__ATOMIC_RELAXED))
|
||||
{
|
||||
// The cmpxchg set *pStaticFile = newFileOrError.
|
||||
return newFileOrError;
|
||||
}
|
||||
|
||||
// The cmpxchg set oldFileOrError = *pStaticFile.
|
||||
|
||||
if (oldFileOrError >= 0 || newFileOrError < 0)
|
||||
{
|
||||
// Prefer the existing contents of pStaticFile.
|
||||
if (newFileOrError >= 0)
|
||||
{
|
||||
close(newFileOrError);
|
||||
}
|
||||
|
||||
return oldFileOrError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_Success_(return >= 0) int
|
||||
tracepoint_control::GetUserEventsDataFile() noexcept
|
||||
{
|
||||
static int staticFileOrError = -EAGAIN; // Intentionally leaked.
|
||||
int fileOrError = __atomic_load_n(&staticFileOrError, __ATOMIC_RELAXED);
|
||||
return fileOrError != -EAGAIN
|
||||
? fileOrError
|
||||
: UpdateUserEventsDataFile(&staticFileOrError);
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
tracepoint_control::AppendTracingFile(
|
||||
std::vector<char>& dest,
|
||||
_In_z_ char const* fileName) noexcept
|
||||
{
|
||||
int error;
|
||||
auto const destOldSize = dest.size();
|
||||
|
||||
if (auto const file = fopen(fileName, "r");
|
||||
file == nullptr)
|
||||
{
|
||||
error = errno;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Usually a special file, so don't try to seek or stat to get file size.
|
||||
try
|
||||
{
|
||||
auto pos = destOldSize;
|
||||
for (;;)
|
||||
{
|
||||
dest.resize(dest.size() + 512);
|
||||
|
||||
auto const readSize = fread(dest.data() + pos, 1, dest.size() - pos, file);
|
||||
pos += readSize;
|
||||
|
||||
if (pos != dest.size())
|
||||
{
|
||||
if (feof(file))
|
||||
{
|
||||
dest.resize(pos);
|
||||
error = 0;
|
||||
break;
|
||||
}
|
||||
else if (ferror(file))
|
||||
{
|
||||
dest.resize(destOldSize);
|
||||
error = EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
dest.resize(destOldSize);
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
_Success_(return == 0) int
|
||||
tracepoint_control::AppendTracingFormatFile(
|
||||
std::vector<char>& dest,
|
||||
std::string_view systemName,
|
||||
std::string_view eventName) noexcept
|
||||
{
|
||||
int error;
|
||||
|
||||
if (systemName.empty() ||
|
||||
systemName.find_first_of("/.\0"sv) != systemName.npos ||
|
||||
eventName.empty() ||
|
||||
eventName.find_first_of("/.\0"sv) != eventName.npos)
|
||||
{
|
||||
// Invalid systemName or eventName parameter.
|
||||
error = EINVAL;
|
||||
}
|
||||
else if (
|
||||
auto const tracingDir = GetTracingDirectory();
|
||||
tracingDir[0] == 0)
|
||||
{
|
||||
// Unable to find the "/.../tracing" directory.
|
||||
error = ENOTSUP;
|
||||
}
|
||||
else
|
||||
{
|
||||
char fileName[TRACING_DIR_MAX + 256];
|
||||
unsigned const pathLen = snprintf(fileName, sizeof(fileName), "%s/events/%.*s/%.*s/format",
|
||||
tracingDir,
|
||||
(unsigned)systemName.size(), systemName.data(),
|
||||
(unsigned)eventName.size(), eventName.data());
|
||||
if (pathLen >= sizeof(fileName))
|
||||
{
|
||||
// tracingDirectory + systemName + eventName too long.
|
||||
error = E2BIG;
|
||||
}
|
||||
else
|
||||
{
|
||||
error = AppendTracingFile(dest, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
2017
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointSession.cpp
vendored
Normal file
2017
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointSession.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
306
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointSpec.cpp
vendored
Normal file
306
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/TracepointSpec.cpp
vendored
Normal file
|
@ -0,0 +1,306 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/TracepointSpec.h>
|
||||
#include <tracepoint/TracepointName.h>
|
||||
#include <assert.h>
|
||||
|
||||
using namespace tracepoint_control;
|
||||
|
||||
static bool
|
||||
AsciiIsSpace(char ch)
|
||||
{
|
||||
return ch == ' ' || ('\t' <= ch && ch <= '\r');
|
||||
}
|
||||
|
||||
static size_t
|
||||
CountLeadingWhitespace(std::string_view str)
|
||||
{
|
||||
size_t pos;
|
||||
for (pos = 0; pos != str.size(); pos += 1)
|
||||
{
|
||||
if (!AsciiIsSpace(str[pos]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
TracepointSpec::TracepointSpec(std::string_view const specString) noexcept
|
||||
{
|
||||
bool identifier;
|
||||
bool hasFields = false;
|
||||
|
||||
/*
|
||||
Cases:
|
||||
1. Empty
|
||||
2. '#' ANY*
|
||||
3. ':' WS* EventName
|
||||
4. ':' WS* SystemName ':' EventName
|
||||
5. EventName (WS Fields*)?
|
||||
6. SystemName ':' EventName (':' Flags)? (WS Fields*)?
|
||||
*/
|
||||
|
||||
auto const trimmed = Trim(specString);
|
||||
Trimmed = trimmed;
|
||||
|
||||
size_t pos = 0;
|
||||
if (pos == trimmed.size())
|
||||
{
|
||||
Kind = TracepointSpecKind::Empty;
|
||||
return; // Case 1
|
||||
}
|
||||
else if (trimmed[pos] == '#')
|
||||
{
|
||||
Kind = TracepointSpecKind::Empty;
|
||||
return; // Case 2
|
||||
}
|
||||
else if (trimmed[pos] == ':')
|
||||
{
|
||||
size_t startPos;
|
||||
|
||||
// Skip ':'
|
||||
pos += 1;
|
||||
|
||||
// Skip WS*
|
||||
pos += CountLeadingWhitespace(trimmed.substr(pos));
|
||||
|
||||
// Skip Name
|
||||
for (startPos = pos;; pos += 1)
|
||||
{
|
||||
if (pos == trimmed.size())
|
||||
{
|
||||
SystemName = UserEventsSystemName;
|
||||
EventName = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
identifier = true;
|
||||
goto Done; // Case 3.
|
||||
}
|
||||
|
||||
if (AsciiIsSpace(trimmed[pos]))
|
||||
{
|
||||
SystemName = UserEventsSystemName;
|
||||
EventName = trimmed.substr(startPos, pos - startPos);
|
||||
Kind = TracepointSpecKind::ErrorIdentifierCannotHaveFields;
|
||||
return;
|
||||
}
|
||||
|
||||
if (trimmed[pos] == ':')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// End of name - ':'.
|
||||
|
||||
SystemName = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
|
||||
// Skip ':'
|
||||
pos += 1;
|
||||
|
||||
// Skip Name
|
||||
for (startPos = pos; pos != trimmed.size(); pos += 1)
|
||||
{
|
||||
if (AsciiIsSpace(trimmed[pos]))
|
||||
{
|
||||
EventName = trimmed.substr(startPos, pos - startPos);
|
||||
Kind = TracepointSpecKind::ErrorIdentifierCannotHaveFields;
|
||||
return;
|
||||
}
|
||||
|
||||
if (trimmed[pos] == ':')
|
||||
{
|
||||
EventName = trimmed.substr(startPos, pos - startPos);
|
||||
Kind = TracepointSpecKind::ErrorIdentifierCannotHaveFlags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
EventName = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
identifier = true;
|
||||
goto Done; // Case 4.
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t startPos;
|
||||
|
||||
assert(pos != trimmed.size());
|
||||
assert(!AsciiIsSpace(trimmed[pos]));
|
||||
assert(trimmed[pos] != ':');
|
||||
startPos = pos;
|
||||
pos += 1;
|
||||
|
||||
// Skip Name
|
||||
for (;; pos += 1)
|
||||
{
|
||||
if (pos == trimmed.size())
|
||||
{
|
||||
SystemName = UserEventsSystemName;
|
||||
EventName = trimmed.substr(startPos, pos - startPos);
|
||||
identifier = false;
|
||||
goto Done; // Case 5, no fields.
|
||||
}
|
||||
|
||||
if (AsciiIsSpace(trimmed[pos]))
|
||||
{
|
||||
SystemName = UserEventsSystemName;
|
||||
EventName = trimmed.substr(startPos, pos - startPos);
|
||||
goto DefinitionFields; // Case 5, fields.
|
||||
}
|
||||
|
||||
if (trimmed[pos] == ':')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// End of name - ':'.
|
||||
|
||||
SystemName = trimmed.substr(startPos, pos - startPos);
|
||||
|
||||
// Skip ':'
|
||||
pos += 1;
|
||||
|
||||
// Skip Name
|
||||
for (startPos = pos;; pos += 1)
|
||||
{
|
||||
if (pos == trimmed.size())
|
||||
{
|
||||
EventName = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
identifier = false;
|
||||
goto Done; // Case 6, no fields.
|
||||
}
|
||||
|
||||
if (AsciiIsSpace(trimmed[pos]))
|
||||
{
|
||||
EventName = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
goto DefinitionFields; // Case 6, fields.
|
||||
}
|
||||
|
||||
if (trimmed[pos] == ':')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EventName = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
|
||||
// Skip ':'
|
||||
pos += 1;
|
||||
|
||||
// Skip Name
|
||||
for (startPos = pos;; pos += 1)
|
||||
{
|
||||
if (pos == trimmed.size())
|
||||
{
|
||||
Flags = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
identifier = false;
|
||||
goto Done; // Case 6, no fields.
|
||||
}
|
||||
|
||||
if (AsciiIsSpace(trimmed[pos]))
|
||||
{
|
||||
Flags = trimmed.substr(startPos, pos - startPos); // Might be empty.
|
||||
goto DefinitionFields; // Case 6, fields.
|
||||
}
|
||||
|
||||
if (trimmed[pos] == ':')
|
||||
{
|
||||
Flags = trimmed.substr(startPos, pos - startPos);
|
||||
Kind = TracepointSpecKind::ErrorDefinitionCannotHaveColonAfterFlags;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DefinitionFields:
|
||||
|
||||
// Skip WS*
|
||||
assert(AsciiIsSpace(trimmed[pos]));
|
||||
pos += CountLeadingWhitespace(trimmed.substr(pos));
|
||||
|
||||
Fields = trimmed.substr(pos); // Might have trailing semicolon.
|
||||
while (!Fields.empty() &&
|
||||
(Fields.back() == ';' || AsciiIsSpace(Fields.back())))
|
||||
{
|
||||
Fields.remove_suffix(1);
|
||||
}
|
||||
|
||||
hasFields = true;
|
||||
identifier = false;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
if (!EventNameIsValid(EventName))
|
||||
{
|
||||
if (EventName.empty())
|
||||
{
|
||||
Kind = identifier
|
||||
? TracepointSpecKind::ErrorIdentifierEventNameEmpty
|
||||
: TracepointSpecKind::ErrorDefinitionEventNameEmpty;
|
||||
}
|
||||
else
|
||||
{
|
||||
Kind = identifier
|
||||
? TracepointSpecKind::ErrorIdentifierEventNameInvalid
|
||||
: TracepointSpecKind::ErrorDefinitionEventNameInvalid;
|
||||
}
|
||||
}
|
||||
else if (!SystemNameIsValid(SystemName))
|
||||
{
|
||||
if (SystemName.empty())
|
||||
{
|
||||
Kind = identifier
|
||||
? TracepointSpecKind::ErrorIdentifierSystemNameEmpty
|
||||
: TracepointSpecKind::ErrorDefinitionSystemNameEmpty;
|
||||
}
|
||||
else
|
||||
{
|
||||
Kind = identifier
|
||||
? TracepointSpecKind::ErrorIdentifierSystemNameInvalid
|
||||
: TracepointSpecKind::ErrorDefinitionSystemNameInvalid;
|
||||
}
|
||||
}
|
||||
else if (identifier)
|
||||
{
|
||||
Kind = TracepointSpecKind::Identifier;
|
||||
}
|
||||
else if (hasFields)
|
||||
{
|
||||
Kind = TracepointSpecKind::Definition;
|
||||
}
|
||||
else if (!EventHeaderEventNameIsValid(EventName))
|
||||
{
|
||||
Kind = TracepointSpecKind::ErrorEventHeaderDefinitionEventNameInvalid;
|
||||
}
|
||||
else
|
||||
{
|
||||
Kind = TracepointSpecKind::EventHeaderDefinition;
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view
|
||||
TracepointSpec::Trim(std::string_view const str) noexcept
|
||||
{
|
||||
size_t startPos;
|
||||
size_t endPos;
|
||||
|
||||
for (startPos = 0; startPos != str.size(); startPos += 1)
|
||||
{
|
||||
if (!AsciiIsSpace(str[startPos]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (endPos = str.size(); endPos != startPos; endPos -= 1)
|
||||
{
|
||||
if (!AsciiIsSpace(str[endPos - 1]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str.substr(startPos, endPos - startPos);
|
||||
}
|
140
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/UniqueHandles.cpp
vendored
Normal file
140
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/src/UniqueHandles.cpp
vendored
Normal file
|
@ -0,0 +1,140 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/TracepointSession.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
using namespace tracepoint_control;
|
||||
|
||||
TracepointSession::unique_fd::~unique_fd()
|
||||
{
|
||||
reset(-1);
|
||||
}
|
||||
|
||||
TracepointSession::unique_fd::unique_fd() noexcept
|
||||
: m_fd(-1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointSession::unique_fd::unique_fd(int fd) noexcept
|
||||
: m_fd(fd)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointSession::unique_fd::unique_fd(unique_fd&& other) noexcept
|
||||
: m_fd(other.m_fd)
|
||||
{
|
||||
other.m_fd = -1;
|
||||
}
|
||||
|
||||
TracepointSession::unique_fd&
|
||||
TracepointSession::unique_fd::operator=(unique_fd&& other) noexcept
|
||||
{
|
||||
int fd = other.m_fd;
|
||||
other.m_fd = -1;
|
||||
reset(fd);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TracepointSession::unique_fd::operator bool() const noexcept
|
||||
{
|
||||
return m_fd != -1;
|
||||
}
|
||||
|
||||
void
|
||||
TracepointSession::unique_fd::reset() noexcept
|
||||
{
|
||||
reset(-1);
|
||||
}
|
||||
|
||||
void
|
||||
TracepointSession::unique_fd::reset(int fd) noexcept
|
||||
{
|
||||
if (m_fd != -1)
|
||||
{
|
||||
close(m_fd);
|
||||
}
|
||||
m_fd = fd;
|
||||
}
|
||||
|
||||
int
|
||||
TracepointSession::unique_fd::get() const noexcept
|
||||
{
|
||||
return m_fd;
|
||||
}
|
||||
|
||||
TracepointSession::unique_mmap::~unique_mmap()
|
||||
{
|
||||
reset(MAP_FAILED, 0);
|
||||
}
|
||||
|
||||
TracepointSession::unique_mmap::unique_mmap() noexcept
|
||||
: m_addr(MAP_FAILED)
|
||||
, m_size(0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointSession::unique_mmap::unique_mmap(void* addr, size_t size) noexcept
|
||||
: m_addr(addr)
|
||||
, m_size(size)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TracepointSession::unique_mmap::unique_mmap(unique_mmap&& other) noexcept
|
||||
: m_addr(other.m_addr)
|
||||
, m_size(other.m_size)
|
||||
{
|
||||
other.m_addr = MAP_FAILED;
|
||||
other.m_size = 0;
|
||||
}
|
||||
|
||||
TracepointSession::unique_mmap&
|
||||
TracepointSession::unique_mmap::operator=(unique_mmap&& other) noexcept
|
||||
{
|
||||
void* addr = other.m_addr;
|
||||
size_t size = other.m_size;
|
||||
other.m_addr = MAP_FAILED;
|
||||
other.m_size = 0;
|
||||
reset(addr, size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TracepointSession::unique_mmap::operator bool() const noexcept
|
||||
{
|
||||
return m_addr != MAP_FAILED;
|
||||
}
|
||||
|
||||
void
|
||||
TracepointSession::unique_mmap::reset() noexcept
|
||||
{
|
||||
reset(MAP_FAILED, 0);
|
||||
}
|
||||
|
||||
void
|
||||
TracepointSession::unique_mmap::reset(void* addr, size_t size) noexcept
|
||||
{
|
||||
if (m_addr != MAP_FAILED)
|
||||
{
|
||||
munmap(m_addr, m_size);
|
||||
}
|
||||
m_addr = addr;
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
void*
|
||||
TracepointSession::unique_mmap::get() const noexcept
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
size_t
|
||||
TracepointSession::unique_mmap::get_size() const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
@PACKAGE_INIT@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/tracepoint-controlTargets.cmake")
|
7
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/tools/CMakeLists.txt
vendored
Normal file
7
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/tools/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
add_executable(tracepoint-collect
|
||||
tracepoint-collect.cpp)
|
||||
target_link_libraries(tracepoint-collect
|
||||
tracepoint-control tracepoint-decode)
|
||||
target_compile_features(tracepoint-collect
|
||||
PRIVATE cxx_std_17)
|
||||
install(TARGETS tracepoint-collect)
|
942
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/tools/tracepoint-collect.cpp
vendored
Normal file
942
src/native/external/LinuxTracepoints/libtracepoint-control-cpp/tools/tracepoint-collect.cpp
vendored
Normal file
|
@ -0,0 +1,942 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Simple tool for collecting tracepoints into perf.data files.
|
||||
*/
|
||||
|
||||
#include <tracepoint/TracepointSession.h>
|
||||
#include <tracepoint/TracepointSpec.h>
|
||||
#include <tracepoint/PerfDataFileWriter.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define PROGRAM_NAME "tracepoint-collect"
|
||||
#define EXIT_SIGNALS SIGTERM, SIGINT
|
||||
#define EXIT_SIGNALS_STR "SIGTERM or SIGINT"
|
||||
|
||||
static constexpr int ExitSigs[] = { EXIT_SIGNALS };
|
||||
static constexpr unsigned ExitSigsCount = sizeof(ExitSigs) / sizeof(ExitSigs[0]);
|
||||
|
||||
static char const* const UsageCommon = R"(
|
||||
Usage: )" PROGRAM_NAME R"( [options...] TracepointSpecs...
|
||||
)";
|
||||
|
||||
// Usage error: stderr += UsageCommon + UsageShort.
|
||||
static char const* const UsageShort = R"(
|
||||
Try ")" PROGRAM_NAME R"( --help" for more information.
|
||||
)";
|
||||
|
||||
// -h or --help: stdout += UsageCommon + UsageLong.
|
||||
static char const* const UsageLong = R"(
|
||||
Collects tracepoint events and saves them to a perf.data file. Collection
|
||||
runs until )" EXIT_SIGNALS_STR R"( is received.
|
||||
|
||||
Requires privileges, typically the CAP_PERFMON capability plus read access to
|
||||
/sys/kernel/tracing. Pre-registration of a tracepoint requires write access to
|
||||
/sys/kernel/tracing/user_events_data.
|
||||
|
||||
Options:
|
||||
|
||||
-b, --buffersize <size>
|
||||
Set the size of each buffer, in kilobytes. There will be
|
||||
one buffer per CPU. The default is 128, max is 2GB.
|
||||
|
||||
-c, --circular Use circular trace mode. Events will be collected in
|
||||
circular buffers (new events overwrite old) until the
|
||||
signal is received, at which point the output file will be
|
||||
created, buffer contents will be written to the file, and
|
||||
the tool will exit.
|
||||
|
||||
-C, --realtime Use realtime trace mode (default). File will be created
|
||||
immediately and events will be written to the file as they
|
||||
are received until the signal is received, at which point
|
||||
the tool will finalize the file and exit.
|
||||
|
||||
-i, --input <file> Read additional TracepointSpecs from <file>. Each line in
|
||||
the file is treated as a TracepointSpec. Empty lines and
|
||||
lines starting with '#' are ignored.
|
||||
|
||||
-o, --output <file> Set the output filename. The default is "./perf.data".
|
||||
|
||||
-w, --wakeup <size> Set the wakeup watermark size for realtime trace mode, in
|
||||
kilobytes. The default is 2. The tool will wait for a
|
||||
buffer to have at least this much data before waking to
|
||||
flush the buffer to the output file.
|
||||
|
||||
-v, --verbose Show diagnostic output.
|
||||
|
||||
-h, --help Show this help message and exit.
|
||||
|
||||
A TracepointSpec is one of the following:
|
||||
|
||||
* If the tracepoint is a normal (non-EventHeader) user_event that may not
|
||||
already exist, use the full user_event definition,
|
||||
"SystemName:EventName Fields...". If the tracepoint does not already exist,
|
||||
it will be pre-registered so that it can be added to the trace session. For
|
||||
example:
|
||||
|
||||
user_events:MyEvent u32 MyField1; struct MyStruct2 MyField2 20
|
||||
|
||||
" Fields..." is required. For an event with no fields, use " ;", e.g.
|
||||
|
||||
user_events:MySimpleEvent ;
|
||||
|
||||
See https://docs.kernel.org/trace/user_events.html#command-format for
|
||||
details on the user_events definition syntax.
|
||||
|
||||
* If the tracepoint is an EventHeader user_event that may not already exist,
|
||||
use the EventHeader identity, "SystemName:ProviderName_Suffix". If the
|
||||
tracepoint does not already exist, it will be pre-registered so that it can
|
||||
be added to the trace session. For example:
|
||||
|
||||
user_events:MyProvider_L5K1
|
||||
|
||||
* If the tracepoint is known to already be registered (e.g. a kernel event),
|
||||
use the tracepoint identity with a leading colon, ":SystemName:EventName".
|
||||
If the tracepoint does not already exist, it will not be added to the trace
|
||||
session. For example:
|
||||
|
||||
:sched:sched_switch
|
||||
|
||||
In all cases, you may omit "SystemName:" if it is "user_events:", e.g.
|
||||
|
||||
MyEvent u32 MyField1;
|
||||
MyProvider_L5K1Gmygroup
|
||||
:MyUserEventThatAlreadyExists
|
||||
|
||||
For TracepointSpecs provided on the command line, use quotation marks to
|
||||
ensure correct handling of spaces and semicolons in each TracepointSpec, e.g.
|
||||
|
||||
"user_events:MyEvent u32 MyField1; struct MyStruct2 MyField2 20"
|
||||
)";
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using namespace tracepoint_control;
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
class Tracepoint
|
||||
{
|
||||
std::vector<char> storage;
|
||||
|
||||
public:
|
||||
|
||||
TracepointSpec spec;
|
||||
|
||||
Tracepoint(Tracepoint&&) = default;
|
||||
Tracepoint& operator=(Tracepoint&&) = default;
|
||||
|
||||
explicit
|
||||
Tracepoint(std::string_view line)
|
||||
{
|
||||
auto const trimmedLine = TracepointSpec::Trim(line);
|
||||
|
||||
if (!trimmedLine.empty())
|
||||
{
|
||||
storage.assign(trimmedLine.begin(), trimmedLine.end());
|
||||
}
|
||||
|
||||
spec = TracepointSpec({ storage.data(), storage.size() });
|
||||
}
|
||||
};
|
||||
|
||||
struct Options
|
||||
{
|
||||
char const* output = "./perf.data";
|
||||
bool verbose = false;
|
||||
};
|
||||
|
||||
// fprintf(stderr, "PROGRAM_NAME: " + format, args...).
|
||||
static void
|
||||
PrintStderr(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fputs(PROGRAM_NAME ": ", stderr);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// if (condition) fprintf(stderr, "PROGRAM_NAME: " + format, args...).
|
||||
static void
|
||||
PrintStderrIf(bool condition, const char* format, ...)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fputs(PROGRAM_NAME ": ", stderr);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
PushFrontDef(Options const& o, std::vector<Tracepoint>& tracepoints, Tracepoint&& tp)
|
||||
{
|
||||
auto const& spec = tp.spec;
|
||||
auto const trimmed = spec.Trimmed;
|
||||
switch (tp.spec.Kind)
|
||||
{
|
||||
case TracepointSpecKind::Empty:
|
||||
break;
|
||||
case TracepointSpecKind::Identifier:
|
||||
PrintStderrIf(o.verbose, "verbose: identifier \"%.*s:%.*s\".\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)spec.EventName.size(), spec.EventName.data());
|
||||
tracepoints.push_back(std::move(tp));
|
||||
break;
|
||||
case TracepointSpecKind::Definition:
|
||||
if (spec.SystemName != UserEventsSystemName)
|
||||
{
|
||||
PrintStderr("error: definition system name \"%.*s\" must be 'user_events' (from \"%.*s\").\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderrIf(o.verbose, "verbose: definition \"%.*s:%.*s%s%.*s%s%.*s\"\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)spec.EventName.size(), spec.EventName.data(),
|
||||
spec.Flags.empty() ? "" : ":",
|
||||
(unsigned)spec.Flags.size(), spec.Flags.data(),
|
||||
spec.Fields.empty() ? "" : " ",
|
||||
(unsigned)spec.Fields.size(), spec.Fields.data());
|
||||
tracepoints.push_back(std::move(tp));
|
||||
}
|
||||
break;
|
||||
case TracepointSpecKind::EventHeaderDefinition:
|
||||
if (spec.SystemName != UserEventsSystemName)
|
||||
{
|
||||
PrintStderr("error: eventheader system name \"%.*s\" must be 'user_events' (from \"%.*s\").\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderrIf(o.verbose, "verbose: eventheader \"%.*s:%.*s%s%.*s\".\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)spec.EventName.size(), spec.EventName.data(),
|
||||
spec.Flags.empty() ? "" : ":",
|
||||
(unsigned)spec.Flags.size(), spec.Flags.data());
|
||||
tracepoints.push_back(std::move(tp));
|
||||
}
|
||||
break;
|
||||
case TracepointSpecKind::ErrorIdentifierCannotHaveFields:
|
||||
PrintStderr("error: identifier cannot have fields (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorIdentifierCannotHaveFlags:
|
||||
PrintStderr("error: identifier cannot have flags (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorDefinitionCannotHaveColonAfterFlags:
|
||||
PrintStderr("error: definition cannot have colon after flags (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorIdentifierEventNameEmpty:
|
||||
PrintStderr("error: identifier event name is empty (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorDefinitionEventNameEmpty:
|
||||
PrintStderr("error: definition event name is empty (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorIdentifierEventNameInvalid:
|
||||
PrintStderr("error: identifier event name \"%.*s\" is invalid (from \"%.*s\").\n",
|
||||
(unsigned)spec.EventName.size(), spec.EventName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorDefinitionEventNameInvalid:
|
||||
PrintStderr("error: definition event name \"%.*s\" is invalid (from \"%.*s\").\n",
|
||||
(unsigned)spec.EventName.size(), spec.EventName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorEventHeaderDefinitionEventNameInvalid:
|
||||
PrintStderr("error: eventheader event name \"%.*s\" is invalid (from \"%.*s\").\n",
|
||||
(unsigned)spec.EventName.size(), spec.EventName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
PrintStderr("(error) If this was meant to be the name of an existing non-eventheader event, add a leading ':'.\n");
|
||||
PrintStderr("(error) If this was meant to be the definition of a non-eventheader event, a Fields... section must be provided.\n");
|
||||
PrintStderr("(error) If a non-eventheader event has no fields, use \" ;\" for Fields..., e.g. \"MyEvent ;\".\n");
|
||||
break;
|
||||
case TracepointSpecKind::ErrorIdentifierSystemNameEmpty:
|
||||
PrintStderr("error: identifier system name is empty (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorDefinitionSystemNameEmpty:
|
||||
PrintStderr("error: definition system name is empty (from \"%.*s\").\n",
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorIdentifierSystemNameInvalid:
|
||||
PrintStderr("error: identifier system name \"%.*s\" is invalid (from \"%.*s\").\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
case TracepointSpecKind::ErrorDefinitionSystemNameInvalid:
|
||||
PrintStderr("error: definition system name \"%.*s\" is invalid (from \"%.*s\").\n",
|
||||
(unsigned)spec.SystemName.size(), spec.SystemName.data(),
|
||||
(unsigned)trimmed.size(), trimmed.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
PushFrontDefsFromFile(Options const& o, std::vector<Tracepoint>& tracepoints, char const* filename)
|
||||
{
|
||||
// CodeQL [SM01937] This is a sample/tool. Using externally-supplied path is intended behavior.
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file == nullptr)
|
||||
{
|
||||
PrintStderr("error: cannot open file \"%s\", error %u.\n",
|
||||
filename, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<char> line;
|
||||
|
||||
char buf[128];
|
||||
while (fgets(buf, sizeof(buf), file))
|
||||
{
|
||||
line.insert(line.end(), buf, buf + strlen(buf));
|
||||
if (line.back() == '\n')
|
||||
{
|
||||
PushFrontDef(o, tracepoints, Tracepoint({ line.data(), line.size() }));
|
||||
line.clear();
|
||||
}
|
||||
}
|
||||
|
||||
auto const error = errno;
|
||||
|
||||
bool const ok = 0 == ferror(file);
|
||||
fclose(file);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
fprintf(stderr, "error: failed reading file \"%s\", error %u.\n",
|
||||
filename, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flush last line.
|
||||
PushFrontDef(o, tracepoints, Tracepoint({ line.data(), line.size() }));
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void
|
||||
ArgSize(
|
||||
_In_z_ char const* flagName,
|
||||
unsigned maxValue,
|
||||
int argi,
|
||||
int argc,
|
||||
_In_reads_(argc) char* argv[],
|
||||
_Inout_ bool* usageError,
|
||||
_Inout_ unsigned* value)
|
||||
{
|
||||
if (argi >= argc)
|
||||
{
|
||||
PrintStderr("error: missing value for flag %s.\n",
|
||||
flagName);
|
||||
*usageError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const* const arg = argv[argi];
|
||||
auto argValue = strtoul(arg, nullptr, 0);
|
||||
if (argValue == 0)
|
||||
{
|
||||
PrintStderr("error: expected positive integer for flag %s \"%s\".\n",
|
||||
flagName, arg);
|
||||
*usageError = true;
|
||||
}
|
||||
else if (argValue > maxValue)
|
||||
{
|
||||
PrintStderr("error: value %lu too large (max %u) for flag %s \"%s\".\n",
|
||||
argValue, maxValue, flagName, arg);
|
||||
*usageError = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
*value = static_cast<unsigned>(argValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
InitExitSigSet(sigset_t* exitSigSet)
|
||||
{
|
||||
sigemptyset(exitSigSet);
|
||||
for (auto exitSig : ExitSigs)
|
||||
{
|
||||
sigaddset(exitSigSet, exitSig);
|
||||
}
|
||||
}
|
||||
|
||||
static int SignalHandled = 0;
|
||||
|
||||
class SignalMask
|
||||
{
|
||||
int m_initError;
|
||||
bool m_masked;
|
||||
unsigned short m_sigsInstalled;
|
||||
sigset_t m_oldSigSet;
|
||||
struct sigaction m_oldActs[ExitSigsCount];
|
||||
|
||||
public:
|
||||
|
||||
SignalMask(SignalMask const&) = delete;
|
||||
SignalMask& operator=(SignalMask const&) = delete;
|
||||
|
||||
~SignalMask()
|
||||
{
|
||||
Restore();
|
||||
}
|
||||
|
||||
SignalMask() noexcept
|
||||
: m_initError(0)
|
||||
, m_masked(false)
|
||||
, m_sigsInstalled(0)
|
||||
{
|
||||
struct sigaction newAct = {};
|
||||
newAct.sa_handler = [](int sig)
|
||||
{
|
||||
SignalHandled = sig;
|
||||
};
|
||||
InitExitSigSet(&newAct.sa_mask);
|
||||
|
||||
if (sigprocmask(SIG_BLOCK, &newAct.sa_mask, &m_oldSigSet))
|
||||
{
|
||||
m_initError = errno;
|
||||
PrintStderr("error: sigprocmask error %u.\n",
|
||||
m_initError);
|
||||
if (m_initError == 0)
|
||||
{
|
||||
m_initError = EINTR;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_masked = true;
|
||||
|
||||
for (; m_sigsInstalled != ExitSigsCount; m_sigsInstalled += 1)
|
||||
{
|
||||
if (sigaction(ExitSigs[m_sigsInstalled], &newAct, &m_oldActs[m_sigsInstalled]))
|
||||
{
|
||||
m_initError = errno;
|
||||
PrintStderr("error: sigaction error %u.\n",
|
||||
m_initError);
|
||||
if (m_initError == 0)
|
||||
{
|
||||
m_initError = EINTR;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
InitError() const noexcept
|
||||
{
|
||||
return m_initError;
|
||||
}
|
||||
|
||||
sigset_t const*
|
||||
OldSigSet() const noexcept
|
||||
{
|
||||
return &m_oldSigSet;
|
||||
}
|
||||
|
||||
void
|
||||
Restore() noexcept
|
||||
{
|
||||
for (; m_sigsInstalled != 0; m_sigsInstalled -= 1)
|
||||
{
|
||||
sigaction(ExitSigs[m_sigsInstalled - 1], &m_oldActs[m_sigsInstalled - 1], nullptr);
|
||||
}
|
||||
|
||||
if (m_masked)
|
||||
{
|
||||
m_masked = false;
|
||||
sigprocmask(SIG_SETMASK, &m_oldSigSet, nullptr);
|
||||
|
||||
if (m_initError == 0)
|
||||
{
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned
|
||||
EnableTracepoints(
|
||||
Options const& o,
|
||||
std::vector<Tracepoint> const& tracepoints,
|
||||
TracepointCache& cache,
|
||||
TracepointSession& session)
|
||||
{
|
||||
unsigned enabledCount = 0;
|
||||
for (auto const& tp : tracepoints)
|
||||
{
|
||||
int error;
|
||||
if (tp.spec.Kind == TracepointSpecKind::Identifier)
|
||||
{
|
||||
error = cache.AddFromSystem(TracepointName(tp.spec.SystemName, tp.spec.EventName));
|
||||
switch (error)
|
||||
{
|
||||
default:
|
||||
PrintStderr("warning: Cannot load format for \"%.*s:%.*s\", error %u.\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data(),
|
||||
error);
|
||||
continue;
|
||||
case 0:
|
||||
PrintStderrIf(o.verbose, "verbose: Loaded format for \"%.*s:%.*s\".\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data());
|
||||
break;
|
||||
case EEXIST:
|
||||
PrintStderrIf(o.verbose, "verbose: Format already loaded for \"%.*s:%.*s\".\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = cache.PreregisterTracepointDefinition(tp.spec);
|
||||
switch (error)
|
||||
{
|
||||
default:
|
||||
PrintStderr("warning: Cannot pre-register \"%.*s:%.*s\", error %u.\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data(),
|
||||
error);
|
||||
continue;
|
||||
case 0:
|
||||
PrintStderrIf(o.verbose, "verbose: Pre-registered \"%.*s:%.*s\".\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data());
|
||||
break;
|
||||
case EEXIST:
|
||||
PrintStderrIf(o.verbose, "verbose: Did not pre-register \"%.*s:%.*s\" (already cached).\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
error = session.EnableTracepoint(TracepointName(tp.spec.SystemName, tp.spec.EventName));
|
||||
if (error != 0)
|
||||
{
|
||||
PrintStderr("warning: Cannot enable \"%.*s:%.*s\", error %u.\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data(),
|
||||
error);
|
||||
}
|
||||
else
|
||||
{
|
||||
enabledCount += 1;
|
||||
PrintStderrIf(o.verbose, "verbose: Enabled \"%.*s:%.*s\".\n",
|
||||
(unsigned)tp.spec.SystemName.size(), tp.spec.SystemName.data(),
|
||||
(unsigned)tp.spec.EventName.size(), tp.spec.EventName.data());
|
||||
}
|
||||
}
|
||||
|
||||
return enabledCount;
|
||||
}
|
||||
|
||||
static int
|
||||
CollectCircular(Options const& o, TracepointSession& session)
|
||||
{
|
||||
int error;
|
||||
int sig = 0;
|
||||
sigset_t exitSigSet;
|
||||
InitExitSigSet(&exitSigSet);
|
||||
|
||||
// Scope for signalMask.
|
||||
PrintStderr("info: collecting until " EXIT_SIGNALS_STR ".\n");
|
||||
{
|
||||
SignalMask signalMask;
|
||||
error = signalMask.InitError();
|
||||
if (error != 0)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
sigwait(&exitSigSet, &sig);
|
||||
}
|
||||
PrintStderr("info: stopping session (signal %u).\n",
|
||||
sig);
|
||||
|
||||
error = session.SavePerfDataFile(o.output);
|
||||
if (error == 0)
|
||||
{
|
||||
PrintStderr("info: saved buffer contents to \"%s\".\n",
|
||||
o.output);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderr("error: failed saving to \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
CollectRealtime(Options const& o, TracepointSession& session)
|
||||
{
|
||||
int error;
|
||||
unsigned wakeupCount = 0;
|
||||
uint64_t eventBytes = 0;
|
||||
|
||||
PerfDataFileWriter writer;
|
||||
error = writer.Create(o.output);
|
||||
if (error != 0)
|
||||
{
|
||||
PrintStderr("error: failed creating file \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
goto Done;
|
||||
}
|
||||
|
||||
error = writer.WriteFinishedInit();
|
||||
if (error != 0)
|
||||
{
|
||||
PrintStderr("error: failed writing FinishedInit to \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
unlink(o.output); // Nothing useful in the file.
|
||||
goto Done;
|
||||
}
|
||||
|
||||
{
|
||||
auto const writerSessionStartPos = writer.FilePos();
|
||||
auto writerRoundStartPos = writerSessionStartPos;
|
||||
TracepointTimestampRange writtenRange;
|
||||
|
||||
assert(SignalHandled == 0);
|
||||
|
||||
// Scope for signalMask.
|
||||
PrintStderr("info: created \"%s\", collecting until " EXIT_SIGNALS_STR ".\n",
|
||||
o.output);
|
||||
{
|
||||
SignalMask signalMask;
|
||||
error = signalMask.InitError();
|
||||
if (error != 0)
|
||||
{
|
||||
unlink(o.output); // Nothing useful in the file.
|
||||
goto Done;
|
||||
}
|
||||
|
||||
while (SignalHandled == 0) // Not sure whether this can ever be false.
|
||||
{
|
||||
error = session.WaitForWakeup(nullptr, signalMask.OldSigSet());
|
||||
if (error != 0)
|
||||
{
|
||||
signalMask.Restore();
|
||||
if (error != EINTR)
|
||||
{
|
||||
PrintStderr("error: ppoll failed, error %u.\n",
|
||||
error);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderrIf(o.verbose, "verbose: ppoll EINTR.\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
wakeupCount += 1;
|
||||
error = session.FlushToWriter(writer, &writtenRange);
|
||||
if (error != 0)
|
||||
{
|
||||
signalMask.Restore();
|
||||
PrintStderr("error: failed flushing \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
goto Finalize;
|
||||
}
|
||||
|
||||
auto const writerRoundEndPos = writer.FilePos();
|
||||
eventBytes = writerRoundEndPos - writerSessionStartPos;
|
||||
PrintStderrIf(o.verbose, "verbose: flushed %lu bytes.\n",
|
||||
static_cast<unsigned long>(writerRoundEndPos - writerRoundStartPos));
|
||||
if (writerRoundStartPos != writerRoundEndPos)
|
||||
{
|
||||
error = writer.WriteFinishedRound();
|
||||
if (error != 0)
|
||||
{
|
||||
signalMask.Restore();
|
||||
PrintStderr("error: failed writing FinishedRound to \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
goto Finalize;
|
||||
}
|
||||
|
||||
writerRoundStartPos = writer.FilePos();
|
||||
}
|
||||
}
|
||||
}
|
||||
PrintStderr("info: stopping session (signal %u).\n",
|
||||
SignalHandled);
|
||||
|
||||
error = session.FlushToWriter(writer, &writtenRange);
|
||||
if (error != 0)
|
||||
{
|
||||
PrintStderr("error: failed flushing \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
goto Finalize;
|
||||
}
|
||||
|
||||
auto const writerSessionEndPos = writer.FilePos();
|
||||
eventBytes = writerSessionEndPos - writerSessionStartPos;
|
||||
PrintStderrIf(o.verbose, "verbose: flushed %lu bytes.\n",
|
||||
static_cast<unsigned long>(writerSessionEndPos - writerRoundStartPos));
|
||||
|
||||
error = session.SetWriterHeaders(writer, &writtenRange);
|
||||
if (error != 0)
|
||||
{
|
||||
PrintStderr("error: failed collecting system info for \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
goto Finalize;
|
||||
}
|
||||
}
|
||||
|
||||
Finalize:
|
||||
|
||||
{
|
||||
auto newError = writer.FinalizeAndClose();
|
||||
if (newError == 0)
|
||||
{
|
||||
PrintStderr("info: woke %u times, wrote 0x%lX bytes to \"%s\".\n",
|
||||
wakeupCount, static_cast<unsigned long>(eventBytes), o.output);
|
||||
}
|
||||
else if (error == 0)
|
||||
{
|
||||
error = newError;
|
||||
PrintStderr("error: failed finalizing \"%s\", error %u.\n",
|
||||
o.output, error);
|
||||
}
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int error;
|
||||
|
||||
try
|
||||
{
|
||||
std::vector<Tracepoint> tracepoints;
|
||||
Options o;
|
||||
unsigned const buffersizeMax = 0x80000000 / 1024;
|
||||
unsigned buffersize = 128u;
|
||||
unsigned const wakeupMax = 0x80000000 / 1024;
|
||||
unsigned wakeup = 2u;
|
||||
bool realtime = true;
|
||||
bool showHelp = false;
|
||||
bool usageError = false;
|
||||
|
||||
for (int argi = 1; argi < argc; argi += 1)
|
||||
{
|
||||
auto const* const arg = argv[argi];
|
||||
if (arg[0] != '-')
|
||||
{
|
||||
PushFrontDef(o, tracepoints, Tracepoint(arg));
|
||||
}
|
||||
else if (arg[1] != '-')
|
||||
{
|
||||
auto const flags = &arg[1];
|
||||
for (unsigned flagsPos = 0; flags[flagsPos] != '\0'; flagsPos += 1)
|
||||
{
|
||||
auto const flag = flags[flagsPos];
|
||||
switch (flag)
|
||||
{
|
||||
case 'b':
|
||||
argi += 1;
|
||||
ArgSize("-b", buffersizeMax, argi, argc, argv, &usageError, &buffersize);
|
||||
break;
|
||||
case 'c':
|
||||
realtime = false;
|
||||
break;
|
||||
case 'C':
|
||||
realtime = true;
|
||||
break;
|
||||
case 'i':
|
||||
argi += 1;
|
||||
if (argi < argc)
|
||||
{
|
||||
PushFrontDefsFromFile(o, tracepoints, argv[argi]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderr("error: missing filename for flag -i.\n");
|
||||
usageError = true;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
argi += 1;
|
||||
if (argi < argc)
|
||||
{
|
||||
o.output = argv[argi];
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderr("error: missing filename for flag -o.\n");
|
||||
usageError = true;
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
argi += 1;
|
||||
ArgSize("-w", wakeupMax, argi, argc, argv, &usageError, &wakeup);
|
||||
break;
|
||||
case 'v':
|
||||
o.verbose = true;
|
||||
break;
|
||||
case 'h':
|
||||
showHelp = true;
|
||||
break;
|
||||
default:
|
||||
PrintStderr("error: invalid flag -%c.\n",
|
||||
flag);
|
||||
usageError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const flag = &arg[2];
|
||||
if (0 == strcmp(flag, "buffersize"))
|
||||
{
|
||||
argi += 1;
|
||||
ArgSize("--buffersize", buffersizeMax, argi, argc, argv, &usageError, &buffersize);
|
||||
}
|
||||
else if (0 == strcmp(flag, "circular"))
|
||||
{
|
||||
realtime = false;
|
||||
}
|
||||
else if (0 == strcmp(flag, "realtime"))
|
||||
{
|
||||
realtime = true;
|
||||
}
|
||||
else if (0 == strcmp(flag, "input"))
|
||||
{
|
||||
argi += 1;
|
||||
if (argi < argc)
|
||||
{
|
||||
PushFrontDefsFromFile(o, tracepoints, argv[argi]);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderr("error: missing filename for flag --input.\n");
|
||||
usageError = true;
|
||||
}
|
||||
}
|
||||
else if (0 == strcmp(flag, "output"))
|
||||
{
|
||||
argi += 1;
|
||||
if (argi < argc)
|
||||
{
|
||||
o.output = argv[argi];
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderr("error: missing filename for flag --output.\n");
|
||||
usageError = true;
|
||||
}
|
||||
}
|
||||
else if (0 == strcmp(flag, "wakeup"))
|
||||
{
|
||||
argi += 1;
|
||||
ArgSize("--wakeup", wakeupMax, argi, argc, argv, &usageError, &wakeup);
|
||||
}
|
||||
else if (0 == strcmp(flag, "verbose"))
|
||||
{
|
||||
o.verbose = true;
|
||||
}
|
||||
else if (0 == strcmp(flag, "help"))
|
||||
{
|
||||
showHelp = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintStderr("error: invalid flag \"--%s\".\n",
|
||||
flag);
|
||||
usageError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showHelp || usageError)
|
||||
{
|
||||
fputs(UsageCommon, stdout);
|
||||
fputs(showHelp ? UsageLong : UsageShort, stdout);
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
else if (tracepoints.empty())
|
||||
{
|
||||
PrintStderr("error: no tracepoints specified, exiting.\n");
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
else if (realtime && wakeup >= buffersize)
|
||||
{
|
||||
PrintStderr("error: wakeup size %u must be less than buffersize %u.\n",
|
||||
wakeup, buffersize);
|
||||
error = EINVAL;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
auto const mode = realtime
|
||||
? TracepointSessionMode::RealTime
|
||||
: TracepointSessionMode::Circular;
|
||||
TracepointCache cache;
|
||||
TracepointSession session(
|
||||
cache,
|
||||
TracepointSessionOptions(mode, buffersize * 1024)
|
||||
.WakeupWatermark(wakeup * 1024));
|
||||
|
||||
unsigned const enabledCount = EnableTracepoints(o, tracepoints, cache, session);
|
||||
if (enabledCount == 0)
|
||||
{
|
||||
PrintStderr("error: No tracepoints enabled, exiting.\n");
|
||||
error = ENOENT;
|
||||
goto Done;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case TracepointSessionMode::Circular:
|
||||
error = CollectCircular(o, session);
|
||||
break;
|
||||
case TracepointSessionMode::RealTime:
|
||||
error = CollectRealtime(o, session);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
PrintStderr("fatal error: %s.\n",
|
||||
ex.what());
|
||||
error = ENOMEM;
|
||||
}
|
||||
|
||||
Done:
|
||||
|
||||
return error;
|
||||
}
|
28
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/CMakeLists.txt
vendored
Normal file
28
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
include(../version.cmake)
|
||||
project(tracepoint-decode-cpp
|
||||
VERSION ${LINUXTRACEPOINTS_VERSION}
|
||||
DESCRIPTION "Tracepoint decoding for C/C++"
|
||||
HOMEPAGE_URL "https://github.com/microsoft/LinuxTracepoints"
|
||||
LANGUAGES CXX)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
if(WIN32)
|
||||
add_compile_options(/W4 /WX /permissive-)
|
||||
else()
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wformat
|
||||
-Wformat-security
|
||||
-Werror=format-security
|
||||
-Wstack-protector
|
||||
-Werror=stack-protector)
|
||||
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_options(-D_FORTIFY_SOURCE=2)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(samples)
|
11
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/README.md
vendored
Normal file
11
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/README.md
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# libtracepoint-decode-cpp
|
||||
|
||||
C++ library for decoding tracepoints and perf.data files.
|
||||
Works on Linux or Windows.
|
||||
|
||||
- **[PerfDataFile.h](include/tracepoint/PerfDataFile.h):**
|
||||
Splits a `perf.data` file into events.
|
||||
- **[PerfEventInfo.h](include/tracepoint/PerfEventInfo.h):**
|
||||
Structures for sample and non-sample events.
|
||||
- **[PerfEventMetadata.h](include/tracepoint/PerfEventMetadata.h):**
|
||||
Metadata parsing for ftrace-style tracepoint decoding information.
|
139
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfByteReader.h
vendored
Normal file
139
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfByteReader.h
vendored
Normal file
|
@ -0,0 +1,139 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfByteReader_h
|
||||
#define _included_PerfByteReader_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h> // memcpy
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _In_
|
||||
#define _In_
|
||||
#endif
|
||||
#ifndef _In_reads_bytes_
|
||||
#define _In_reads_bytes_(cb)
|
||||
#endif
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Loads values from the perf event data buffer, handling misaligned
|
||||
// and byte-swapped values.
|
||||
class PerfByteReader
|
||||
{
|
||||
bool m_bigEndian;
|
||||
|
||||
public:
|
||||
|
||||
// Initializes a data reader that treats input as host-endian.
|
||||
//
|
||||
// Postcondition: this->ByteSwapNeeded() == false.
|
||||
PerfByteReader() noexcept;
|
||||
|
||||
// If bigEndian is true, initializes a data reader that assumes input is
|
||||
// big-endian. Otherwise, assumes input is little-endian.
|
||||
//
|
||||
// Postcondition: this->BigEndian() == bigEndian.
|
||||
explicit
|
||||
PerfByteReader(bool bigEndian) noexcept;
|
||||
|
||||
// Returns true if this reader is treating its input data as big-endian.
|
||||
// Returns false if this reader is treating its input data as little-endian.
|
||||
bool
|
||||
BigEndian() const noexcept;
|
||||
|
||||
// Returns BigEndian() != HOST_IS_BIG_ENDIAN.
|
||||
bool
|
||||
ByteSwapNeeded() const noexcept;
|
||||
|
||||
// Returns *pSrc as uint8_t.
|
||||
uint8_t
|
||||
ReadAsU8(_In_reads_bytes_(1) void const* pSrc) const noexcept;
|
||||
|
||||
// Reads 2 bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result as uint16_t.
|
||||
uint16_t
|
||||
ReadAsU16(_In_reads_bytes_(2) void const* pSrc) const noexcept;
|
||||
|
||||
// Reads 4 bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result as uint32_t.
|
||||
uint32_t
|
||||
ReadAsU32(_In_reads_bytes_(4) void const* pSrc) const noexcept;
|
||||
|
||||
// Reads 8 bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result as uint64_t.
|
||||
uint64_t
|
||||
ReadAsU64(_In_reads_bytes_(8) void const* pSrc) const noexcept;
|
||||
|
||||
// Requires: cbSrc is 1, 2, or 4.
|
||||
// Reads cbSrc bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result cast to uint32_t.
|
||||
uint32_t
|
||||
ReadAsDynU32(_In_reads_bytes_(cbSrc) void const* pSrc, uint8_t cbSrc) const noexcept;
|
||||
|
||||
// Requires: cbSrc is 1, 2, 4, or 8.
|
||||
// Reads cbSrc bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result cast to uint64_t.
|
||||
uint64_t
|
||||
ReadAsDynU64(_In_reads_bytes_(cbSrc) void const* pSrc, uint8_t cbSrc) const noexcept;
|
||||
|
||||
// Requires: sizeof(ValType) is 1, 2, 4, or 8.
|
||||
// Reads sizeof(ValType) bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result cast to ValType.
|
||||
// ValType should be a trivial type, e.g. uint32_t, long, or double.
|
||||
template<class ValType>
|
||||
ValType
|
||||
ReadAs(_In_reads_bytes_(sizeof(ValType)) void const* pSrc) const noexcept
|
||||
{
|
||||
if constexpr (sizeof(ValType) == sizeof(uint8_t))
|
||||
{
|
||||
ValType v;
|
||||
memcpy(&v, pSrc, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
else if constexpr (sizeof(ValType) == sizeof(uint16_t))
|
||||
{
|
||||
auto const uintVal = ReadAsU16(pSrc);
|
||||
ValType v;
|
||||
memcpy(&v, &uintVal, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
else if constexpr (sizeof(ValType) == sizeof(uint32_t))
|
||||
{
|
||||
auto const uintVal = ReadAsU32(pSrc);
|
||||
ValType v;
|
||||
memcpy(&v, &uintVal, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
else if constexpr (sizeof(ValType) == sizeof(uint64_t))
|
||||
{
|
||||
auto const uintVal = ReadAsU64(pSrc);
|
||||
ValType v;
|
||||
memcpy(&v, &uintVal, sizeof(v));
|
||||
return v;
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(ValType) == 0,
|
||||
"ReadAs supports values of size 1, 2, 4, and 8.");
|
||||
}
|
||||
}
|
||||
|
||||
// Requires: sizeof(ValType) is 1, 2, 4, or 8.
|
||||
// Reads sizeof(ValType) bytes from pSrc, performs byteswap if appropriate,
|
||||
// then returns the result cast to ValType.
|
||||
// ValType should be a trivial type, e.g. uint32_t, long, or double.
|
||||
template<class ValType>
|
||||
ValType
|
||||
Read(_In_ ValType const* pSrc) const noexcept
|
||||
{
|
||||
return ReadAs<ValType>(pSrc);
|
||||
}
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfByteReader_h
|
331
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfDataFile.h
vendored
Normal file
331
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfDataFile.h
vendored
Normal file
|
@ -0,0 +1,331 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
PerfDataFile class - Reads perf.data files.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfDataFile_h
|
||||
#define _included_PerfDataFile_h
|
||||
|
||||
#include "PerfByteReader.h"
|
||||
#include "PerfDataFileDefs.h"
|
||||
#include "PerfEventSessionInfo.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h> // FILE
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _In_
|
||||
#define _In_
|
||||
#endif
|
||||
#ifndef _In_z_
|
||||
#define _In_z_
|
||||
#endif
|
||||
#ifndef _In_reads_bytes_
|
||||
#define _In_reads_bytes_(cb)
|
||||
#endif
|
||||
#ifndef _Out_
|
||||
#define _Out_
|
||||
#endif
|
||||
#ifndef _Outptr_result_maybenull_
|
||||
#define _Outptr_result_maybenull_
|
||||
#endif
|
||||
#ifndef _Out_writes_bytes_all_
|
||||
#define _Out_writes_bytes_all_(size)
|
||||
#endif
|
||||
#ifndef _Success_
|
||||
#define _Success_(condition)
|
||||
#endif
|
||||
#ifndef _Ret_opt_
|
||||
#define _Ret_opt_
|
||||
#endif
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Forward declarations from PerfEventInfo.h:
|
||||
struct PerfSampleEventInfo;
|
||||
struct PerfNonSampleEventInfo;
|
||||
|
||||
// Forward declaration from PerfEventMetadata.h:
|
||||
class PerfEventMetadata;
|
||||
|
||||
/*
|
||||
PerfDataFile class - Reads perf.data files.
|
||||
*/
|
||||
class PerfDataFile
|
||||
{
|
||||
struct perf_file_section;
|
||||
struct perf_pipe_header;
|
||||
struct perf_file_header;
|
||||
|
||||
struct EventDesc : PerfEventDesc
|
||||
{
|
||||
std::unique_ptr<perf_event_attr> attrStorage;
|
||||
std::unique_ptr<uint64_t[]> idsStorage;
|
||||
};
|
||||
|
||||
uint64_t m_filePos;
|
||||
uint64_t m_fileLen;
|
||||
uint64_t m_dataBeginFilePos;
|
||||
uint64_t m_dataEndFilePos;
|
||||
FILE* m_file;
|
||||
std::vector<uint8_t> m_eventData;
|
||||
std::vector<char> m_headers[PERF_HEADER_LAST_FEATURE]; // Stored file-endian.
|
||||
std::vector<EventDesc> m_eventDescList; // Stored host-endian. Name points into m_headers.
|
||||
std::map<uint64_t, size_t> m_eventDescById; // Index into m_eventDescList.
|
||||
PerfEventSessionInfo m_sessionInfo;
|
||||
PerfByteReader m_byteReader;
|
||||
int8_t m_sampleIdOffset; // -1 = unset, -2 = no id.
|
||||
int8_t m_nonSampleIdOffset; // -1 = unset, -2 = no id.
|
||||
int8_t m_commonTypeOffset; // -1 = unset, -2 = not available.
|
||||
uint8_t m_commonTypeSize;
|
||||
bool m_parsedHeaderEventDesc;
|
||||
|
||||
// HEADER_TRACING_DATA
|
||||
bool m_parsedTracingData;
|
||||
uint8_t m_tracingDataLongSize;
|
||||
uint32_t m_tracingDataPageSize;
|
||||
std::string_view m_headerPage; // Points into m_headers.
|
||||
std::string_view m_headerEvent; // Points into m_headers.
|
||||
std::vector<std::string_view> m_ftraces; // Points into m_headers.
|
||||
std::map<uint32_t, PerfEventMetadata> m_metadataById; // Points into m_headers.
|
||||
std::string_view m_kallsyms; // Points into m_headers.
|
||||
std::string_view m_printk; // Points into m_headers.
|
||||
std::string_view m_cmdline; // Points into m_headers.
|
||||
|
||||
public:
|
||||
|
||||
PerfDataFile(PerfDataFile const&) = delete;
|
||||
void operator=(PerfDataFile const&) = delete;
|
||||
~PerfDataFile() noexcept;
|
||||
PerfDataFile() noexcept;
|
||||
|
||||
// Returns true if the currently-opened file is big-endian.
|
||||
bool
|
||||
FileBigEndian() const noexcept;
|
||||
|
||||
// Returns PerfByteReader(FileBigEndian()).
|
||||
PerfByteReader
|
||||
ByteReader() const noexcept;
|
||||
|
||||
// Returns the position within the input file of the event that will be
|
||||
// read by the next call to ReadEvent().
|
||||
// Returns UINT64_MAX after end-of-file or file error.
|
||||
uint64_t
|
||||
FilePos() const noexcept;
|
||||
|
||||
// Returns the position within the input file of the first event.
|
||||
uint64_t
|
||||
DataBeginFilePos() const noexcept;
|
||||
|
||||
// If the input file was recorded in pipe mode, returns UINT64_MAX.
|
||||
// Otherwise, returns the position within the input file immediately after
|
||||
// the last event.
|
||||
uint64_t
|
||||
DataEndFilePos() const noexcept;
|
||||
|
||||
// Returns the number of attribute records available from EventDesc().
|
||||
uintptr_t
|
||||
EventDescCount() const noexcept;
|
||||
|
||||
// Combined data from perf_file_header::attrs and PERF_RECORD_HEADER_ATTR.
|
||||
// Requires: eventDescIndex < EventDescCount().
|
||||
PerfEventDesc const&
|
||||
EventDesc(uintptr_t eventDescIndex) const noexcept;
|
||||
|
||||
// Combined data from perf_file_header::attrs, PERF_RECORD_HEADER_ATTR,
|
||||
// and HEADER_EVENT_DESC. Returns NULL if sampleId is not known.
|
||||
_Ret_opt_ PerfEventDesc const*
|
||||
FindEventDescById(uint64_t sampleId) const noexcept;
|
||||
|
||||
// Returns the raw data from the specified header (file-endian, use ByteReader()
|
||||
// to do byte-swapping as appropriate).
|
||||
// Returns empty if the requested header was not loaded from the file.
|
||||
std::string_view
|
||||
Header(PerfHeaderIndex headerIndex) const noexcept;
|
||||
|
||||
// Returns the LongSize parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or 0 if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
uint8_t
|
||||
TracingDataLongSize() const noexcept;
|
||||
|
||||
// Returns the PageSize parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or 0 if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
uint32_t
|
||||
TracingDataPageSize() const noexcept;
|
||||
|
||||
// Returns the header_page parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or {} if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
std::string_view
|
||||
TracingDataHeaderPage() const noexcept;
|
||||
|
||||
// Returns the header_event parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or {} if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
std::string_view
|
||||
TracingDataHeaderEvent() const noexcept;
|
||||
|
||||
// Returns the ftraces parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or NULL if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
std::string_view const*
|
||||
TracingDataFtraces() const noexcept;
|
||||
|
||||
// Returns the count of ftraces parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or 0 if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
uint32_t
|
||||
TracingDataFtraceCount() const noexcept;
|
||||
|
||||
// Returns the kallsyms parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or {} if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
std::string_view
|
||||
TracingDataKallsyms() const noexcept;
|
||||
|
||||
// Returns the printk parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or {} if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
std::string_view
|
||||
TracingDataPrintk() const noexcept;
|
||||
|
||||
// Returns the saved_cmdline parsed from a PERF_HEADER_TRACING_DATA header,
|
||||
// or {} if no PERF_HEADER_TRACING_DATA has been parsed.
|
||||
std::string_view
|
||||
TracingDataSavedCmdLine() const noexcept;
|
||||
|
||||
// Closes the input file, if any.
|
||||
void
|
||||
Close() noexcept;
|
||||
|
||||
// Closes the current input file (if any), then opens the specified
|
||||
// perf.data file using fopen and reads the file header.
|
||||
// If not a pipe-mode file, loads metadata. If a pipe-mode file, metadata
|
||||
// will be loaded as the metadata events are encountered by ReadEvent.
|
||||
// On successful return, the file will be positioned before the first event.
|
||||
_Success_(return == 0) int
|
||||
Open(_In_z_ char const* filePath) noexcept;
|
||||
|
||||
// Closes the current input file (if any), then switches stdin to binary
|
||||
// mode (Windows-only), then reads the file header from stdin. If stdin is
|
||||
// not a pipe-mode file, returns an error. Metadata will be loaded as the
|
||||
// metadata events are encountered by ReadEvent.
|
||||
// On successful return, the file will be positioned before the first event.
|
||||
_Success_(return == 0) int
|
||||
OpenStdin() noexcept;
|
||||
|
||||
// Returns the event header (host-endian) followed by the raw data from the
|
||||
// file (file-endian, use ByteReader() to do byte-swapping as appropriate).
|
||||
//
|
||||
// On success, sets *ppEventHeader to the event and returns 0.
|
||||
// The returned pointer is valid until the next call to ReadEvent.
|
||||
//
|
||||
// On end-of-file, sets *ppEventHeader to NULL and returns 0.
|
||||
//
|
||||
// On error, sets *ppEventHeader to NULL and returns errno.
|
||||
//
|
||||
// Note that for PERF_RECORD_HEADER_TRACING_DATA and PERF_RECORD_AUXTRACE,
|
||||
// there will be extra data immediately after the event. Use EventDataSize to
|
||||
// get the actual event size.
|
||||
_Success_(return == 0) int
|
||||
ReadEvent(_Outptr_result_maybenull_ perf_event_header const** ppEventHeader) noexcept;
|
||||
|
||||
// Given a pEventHeader that was returned from ReadEvent, returns the actual
|
||||
// size of the specified event.
|
||||
//
|
||||
// For most event types, this returns pEventHeader->size.
|
||||
//
|
||||
// For PERF_RECORD_HEADER_TRACING_DATA and PERF_RECORD_AUXTRACE, there is
|
||||
// extra data after the event, and this will return a size that includes
|
||||
// that extra data.
|
||||
uint32_t
|
||||
EventDataSize(perf_event_header const* pEventHeader) noexcept;
|
||||
|
||||
// Tries to get event information from the event's prefix. The prefix is
|
||||
// usually present only for sample events. If the event prefix is not
|
||||
// present, this function may return an error or it may succeed but return
|
||||
// incorrect information. In general, only use this on events where
|
||||
// pEventHeader->type == PERF_RECORD_SAMPLE.
|
||||
_Success_(return == 0) int
|
||||
GetSampleEventInfo(
|
||||
_In_ perf_event_header const* pEventHeader,
|
||||
_Out_ PerfSampleEventInfo* pInfo) const noexcept;
|
||||
|
||||
// Tries to get event information from the event's suffix. The event suffix
|
||||
// is usually present only for non-sample kernel-generated events.
|
||||
// If the event suffix is not present, this function may return an error or
|
||||
// it may succeed but return incorrect information. In general:
|
||||
// - Only use this on events where pEventHeader->type != PERF_RECORD_SAMPLE
|
||||
// and pEventHeader->type < PERF_RECORD_USER_TYPE_START.
|
||||
// - Only use this on events that come after the PERF_RECORD_FINISHED_INIT
|
||||
// event.
|
||||
_Success_(return == 0) int
|
||||
GetNonSampleEventInfo(
|
||||
_In_ perf_event_header const* pEventHeader,
|
||||
_Out_ PerfNonSampleEventInfo* pInfo) const noexcept;
|
||||
|
||||
private:
|
||||
|
||||
_Success_(return == 0) int
|
||||
LoadAttrs(perf_file_section const& attrs, uint64_t cbAttrAndIdSection64) noexcept;
|
||||
|
||||
_Success_(return == 0) int
|
||||
LoadHeaders(perf_file_section const& data, uint64_t flags) noexcept;
|
||||
|
||||
void
|
||||
ParseTracingData() noexcept;
|
||||
|
||||
void
|
||||
ParseHeaderClockid() noexcept;
|
||||
|
||||
void
|
||||
ParseHeaderClockData() noexcept;
|
||||
|
||||
void
|
||||
ParseHeaderEventDesc() noexcept;
|
||||
|
||||
_Success_(return == 0) int
|
||||
GetSampleEventId(_In_ perf_event_header const* pEventHeader, _Out_ uint64_t* pId) const noexcept;
|
||||
|
||||
_Success_(return == 0) int
|
||||
GetNonSampleEventId(_In_ perf_event_header const* pEventHeader, _Out_ uint64_t* pId) const noexcept;
|
||||
|
||||
_Success_(return == 0) int
|
||||
AddAttr(
|
||||
std::unique_ptr<perf_event_attr> pAttr,
|
||||
uint32_t cbAttrCopied,
|
||||
_In_z_ char const* pName,
|
||||
_In_reads_bytes_(cbIdsFileEndian) void const* pbIdsFileEndian,
|
||||
uintptr_t cbIdsFileEndian) noexcept(false);
|
||||
|
||||
template<class SizeType>
|
||||
_Success_(return == 0) int
|
||||
ReadPostEventData(uint16_t eventSizeFromHeader) noexcept;
|
||||
|
||||
bool
|
||||
EnsureEventDataSize(uint32_t minSize) noexcept;
|
||||
|
||||
// Note: leaves filePos at EOF.
|
||||
_Success_(return == 0) int
|
||||
UpdateFileLen() noexcept;
|
||||
|
||||
bool
|
||||
SectionValid(perf_file_section const& section) const noexcept;
|
||||
|
||||
// Returns 0 (success), EIO (fread error), or EPIPE (eof).
|
||||
_Success_(return == 0) int
|
||||
FileRead(_Out_writes_bytes_all_(cb) void* p, uintptr_t cb) noexcept;
|
||||
|
||||
_Success_(return == 0) int
|
||||
FileSeek(uint64_t filePos) noexcept;
|
||||
|
||||
// Returns 0 (success), EIO (fread error), EPIPE (eof), or others.
|
||||
_Success_(return == 0) int
|
||||
FileSeekAndRead(uint64_t filePos, _Out_writes_bytes_all_(cb) void* p, uintptr_t cb) noexcept;
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfDataFile_h
|
|
@ -0,0 +1,79 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfDataFileDefs_h
|
||||
#define _included_PerfDataFileDefs_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _Field_size_
|
||||
#define _Field_size_(size)
|
||||
#endif
|
||||
#ifndef _Field_z_
|
||||
#define _Field_z_
|
||||
#endif
|
||||
|
||||
// Forward declarations from PerfEventAbi.h or linux/uapi/linux/perf_event.h:
|
||||
struct perf_event_attr;
|
||||
struct perf_event_header;
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Forward declaration from PerfEventMetadata.h:
|
||||
class PerfEventMetadata;
|
||||
|
||||
// uint8 header index.
|
||||
// From: perf.data-file-format.txt, perf/util/header.h.
|
||||
enum PerfHeaderIndex : uint8_t {
|
||||
PERF_HEADER_RESERVED = 0, // always cleared
|
||||
PERF_HEADER_FIRST_FEATURE = 1,
|
||||
PERF_HEADER_TRACING_DATA = 1,
|
||||
PERF_HEADER_BUILD_ID,
|
||||
PERF_HEADER_HOSTNAME,
|
||||
PERF_HEADER_OSRELEASE,
|
||||
PERF_HEADER_VERSION,
|
||||
PERF_HEADER_ARCH,
|
||||
PERF_HEADER_NRCPUS,
|
||||
PERF_HEADER_CPUDESC,
|
||||
PERF_HEADER_CPUID,
|
||||
PERF_HEADER_TOTAL_MEM,
|
||||
PERF_HEADER_CMDLINE,
|
||||
PERF_HEADER_EVENT_DESC,
|
||||
PERF_HEADER_CPU_TOPOLOGY,
|
||||
PERF_HEADER_NUMA_TOPOLOGY,
|
||||
PERF_HEADER_BRANCH_STACK,
|
||||
PERF_HEADER_PMU_MAPPINGS,
|
||||
PERF_HEADER_GROUP_DESC,
|
||||
PERF_HEADER_AUXTRACE,
|
||||
PERF_HEADER_STAT,
|
||||
PERF_HEADER_CACHE,
|
||||
PERF_HEADER_SAMPLE_TIME,
|
||||
PERF_HEADER_MEM_TOPOLOGY,
|
||||
PERF_HEADER_CLOCKID,
|
||||
PERF_HEADER_DIR_FORMAT,
|
||||
PERF_HEADER_BPF_PROG_INFO,
|
||||
PERF_HEADER_BPF_BTF,
|
||||
PERF_HEADER_COMPRESSED,
|
||||
PERF_HEADER_CPU_PMU_CAPS,
|
||||
PERF_HEADER_CLOCK_DATA,
|
||||
PERF_HEADER_HYBRID_TOPOLOGY,
|
||||
PERF_HEADER_PMU_CAPS,
|
||||
PERF_HEADER_LAST_FEATURE,
|
||||
};
|
||||
|
||||
struct PerfEventDesc
|
||||
{
|
||||
perf_event_attr const* attr; // NULL for unknown id.
|
||||
_Field_z_ char const* name; // "" if no name available, e.g. if no PERF_HEADER_EVENT_DESC header.
|
||||
PerfEventMetadata const* metadata; // NULL if no metadata available.
|
||||
_Field_size_(ids_count) uint64_t const* ids; // The sample_ids that share this descriptor.
|
||||
uint32_t ids_count;
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfDataFileDefs_h
|
|
@ -0,0 +1,347 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfDataFileWriter_h
|
||||
#define _included_PerfDataFileWriter_h
|
||||
|
||||
#include "PerfDataFileDefs.h"
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _In_
|
||||
#define _In_
|
||||
#endif
|
||||
#ifndef _In_z_
|
||||
#define _In_z_
|
||||
#endif
|
||||
#ifndef _In_reads_
|
||||
#define _In_reads_(count)
|
||||
#endif
|
||||
#ifndef _In_reads_bytes_
|
||||
#define _In_reads_bytes_(cb)
|
||||
#endif
|
||||
#ifndef _Out_
|
||||
#define _Out_
|
||||
#endif
|
||||
#ifndef _Outptr_result_maybenull_
|
||||
#define _Outptr_result_maybenull_
|
||||
#endif
|
||||
#ifndef _Out_writes_bytes_all_
|
||||
#define _Out_writes_bytes_all_(size)
|
||||
#endif
|
||||
#ifndef _Field_z_
|
||||
#define _Field_z_
|
||||
#endif
|
||||
#ifndef _Field_size_bytes_
|
||||
#define _Field_size_bytes_(size)
|
||||
#endif
|
||||
#ifndef _Success_
|
||||
#define _Success_(condition)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// Forward declaration from sys/uio.h:
|
||||
struct iovec;
|
||||
|
||||
// Forward declaration from sys/utsname.h:
|
||||
struct utsname;
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Forward declaration from PerfEventSessionInfo.h:
|
||||
class PerfEventSessionInfo;
|
||||
|
||||
/*
|
||||
PerfDataFileWriter class - Writes perf.data files.
|
||||
|
||||
- Construct a writer: PerfDataFileWriter writer;
|
||||
- Open the file: writer.Create(filename);
|
||||
- This writes headers and positions the file pointer for event data.
|
||||
- Do the following (in any order):
|
||||
- Call WriteEventData to write event data to the file.
|
||||
- Call AddTracepointEventDesc() to provide event information for events
|
||||
with tracefs format information.
|
||||
- Call AddEventDesc() to provide event information for events that don't
|
||||
have tracefs format information.
|
||||
- Call SetHeader() to provide data for other headers in the file.
|
||||
- Close the file: writer.FinalizeAndClose();
|
||||
- This writes the file footers, finalizes the headers, then closes the file.
|
||||
*/
|
||||
class PerfDataFileWriter
|
||||
{
|
||||
struct perf_file_section;
|
||||
struct perf_file_header;
|
||||
struct EventDesc;
|
||||
struct TracepointInfo;
|
||||
|
||||
uint64_t m_filePos;
|
||||
int m_file;
|
||||
std::vector<EventDesc> m_eventDescs;
|
||||
std::map<uint32_t, TracepointInfo> m_tracepointInfoByCommonType;
|
||||
std::vector<char> m_headers[PERF_HEADER_LAST_FEATURE];
|
||||
|
||||
uint32_t m_tracingDataPageSize;
|
||||
uint8_t m_tracingDataLongSize;
|
||||
std::vector<char> m_tracingDataHeaderPage;
|
||||
std::vector<char> m_tracingDataHeaderEvent;
|
||||
std::vector<std::vector<char>> m_tracingDataFtraces;
|
||||
std::vector<char> m_tracingDataKallsyms;
|
||||
std::vector<char> m_tracingDataPrintk;
|
||||
std::vector<char> m_tracingDataSavedCmdline;
|
||||
|
||||
public:
|
||||
|
||||
PerfDataFileWriter(PerfDataFileWriter const&) = delete;
|
||||
void operator=(PerfDataFileWriter const&) = delete;
|
||||
|
||||
// Calls CloseNoFinalize.
|
||||
~PerfDataFileWriter() noexcept;
|
||||
|
||||
// May throw bad_alloc.
|
||||
PerfDataFileWriter() noexcept(false);
|
||||
|
||||
// Immediately closes the current output file (if any).
|
||||
// Does not finalize headers - resulting file will not be usable.
|
||||
void
|
||||
CloseNoFinalize() noexcept;
|
||||
|
||||
// Writes footer, finalizes header, and closes the output file.
|
||||
// On error, closes the output file and returns errno.
|
||||
_Success_(return == 0) int
|
||||
FinalizeAndClose() noexcept;
|
||||
|
||||
// Calls CloseNoFinalize() to close any previous output file, then creates a new
|
||||
// file using open(filePath, O_CREAT|O_WRONLY|O_TRUNC|O_CLOEXEC, mode) and
|
||||
// writes the file header. On error, closes the output file and returns errno.
|
||||
_Success_(return == 0) int
|
||||
Create(_In_z_ char const* filePath, int mode = -1) noexcept;
|
||||
|
||||
// Returns the file offset at which the next call to WriteEventData()
|
||||
// will begin writing. Returns -1 if file is closed.
|
||||
uint64_t
|
||||
FilePos() const noexcept;
|
||||
|
||||
// Adds a block of event data to the output file.
|
||||
// Data should be a sequence of perf_event_header blocks, i.e. a
|
||||
// perf_event_header, then data, then another perf_event_header, etc.
|
||||
//
|
||||
// On success, returns 0. On error, returns errno, in which case file state is
|
||||
// unspecified (may have written some but not all of the data to the file).
|
||||
//
|
||||
// Notes:
|
||||
// - The content of the data is written directly to the event data section of
|
||||
// the output file without any validation.
|
||||
// - Every perf_event_header block's size should be a multiple of 8.
|
||||
// - dataSize should almost always be the sum of hdr.size for all headers written,
|
||||
// except for PERF_RECORD_HEADER_TRACING_DATA and PERF_RECORD_AUXTRACE which may
|
||||
// have additional data in the block beyond the size indicated in the header.
|
||||
// - The trace file will be invalid if any events are written with an id
|
||||
// field that does not have a corresponding entry in the EventDesc table. You
|
||||
// need to provide that information by calling AddTracepointEventDesc(...) or
|
||||
// AddEventDesc(...).
|
||||
_Success_(return == 0) int
|
||||
WriteEventData(
|
||||
_In_reads_bytes_(dataSize) void const* data,
|
||||
size_t dataSize) noexcept;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// Advanced: Adds blocks of event data to the output file.
|
||||
// Similar to WriteEventData, but accepts multiple blocks of data and returns
|
||||
// the number of bytes written instead of errno.
|
||||
//
|
||||
// On error, returns -1. Check errno for error code.
|
||||
// On success, returns number of bytes written. In rare cases, may succeed with a
|
||||
// result less than dataSize (see writev(2) documentation).
|
||||
_Success_(return >= 0) ptrdiff_t
|
||||
WriteEventDataIovecs(
|
||||
_In_reads_(iovecsCount) struct iovec const* iovecs,
|
||||
int iovecsCount) noexcept;
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
// Adds a PERF_RECORD_FINISHED_INIT record to the output file. This should be
|
||||
// called after all "initial system state" data has been written to the file,
|
||||
// e.g. non-sample events like PERF_RECORD_MMAP, PERF_RECORD_COMM,
|
||||
// PERF_RECORD_ID_INDEX, PERF_RECORD_THREAD_MAP, PERF_RECORD_CPU_MAP.
|
||||
_Success_(return == 0) int
|
||||
WriteFinishedInit() noexcept;
|
||||
|
||||
// Adds a PERF_RECORD_FINISHED_ROUND record to the output file. This should be
|
||||
// called each time you completely flush all buffers. This indicates that no
|
||||
// events older than this point will be written to the file after this point.
|
||||
_Success_(return == 0) int
|
||||
WriteFinishedRound() noexcept;
|
||||
|
||||
// Returns the number of bytes set for the specified header.
|
||||
size_t
|
||||
GetHeaderSize(PerfHeaderIndex index) const noexcept;
|
||||
|
||||
// Returns a pointer to the data set for the specified header.
|
||||
void const*
|
||||
GetHeaderData(PerfHeaderIndex index) const noexcept;
|
||||
|
||||
// Directly sets or resets the data for the specified header.
|
||||
//
|
||||
// Note that the PerfDataFileWriter class has special support for the
|
||||
// following headers:
|
||||
//
|
||||
// - If no data has been set via SetHeader(PERF_HEADER_TRACING_DATA, ...) then
|
||||
// CloseNoFinalize() will synthesize a PERF_HEADER_TRACING_DATA header using
|
||||
// data supplied via AddTracepointEventDesc(...) and SetTracingData(...).
|
||||
// - If no data has been set via SetHeader(PERF_HEADER_EVENT_DESC, ...) then
|
||||
// CloseNoFinalize() will synthesize a PERF_HEADER_EVENT_DESC header using
|
||||
// data supplied via AddTracepointEventDesc(...) and AddEventDesc(...).
|
||||
_Success_(return == 0) int
|
||||
SetHeader(
|
||||
PerfHeaderIndex index,
|
||||
_In_reads_bytes_(dataSize) void const* data,
|
||||
size_t dataSize) noexcept;
|
||||
|
||||
// Sets or resets the data for the specified perf_header_string header.
|
||||
// Use this for headers where the header value is a perf_header_string, e.g.
|
||||
// HOSTNAME, OSRELEASE, VERSION, ARCH, CPUDESC, CPUID, CMDLINE.
|
||||
_Success_(return == 0) int
|
||||
SetStringHeader(
|
||||
PerfHeaderIndex index,
|
||||
_In_z_ char const* str) noexcept;
|
||||
|
||||
// Sets the data for the NRCPUS header.
|
||||
_Success_(return == 0) int
|
||||
SetNrCpusHeader(uint32_t available, uint32_t online) noexcept;
|
||||
|
||||
// Sets the data for the SAMPLE_TIME header.
|
||||
_Success_(return == 0) int
|
||||
SetSampleTimeHeader(uint64_t first, uint64_t last) noexcept;
|
||||
|
||||
// Sets the data for the CLOCKID header.
|
||||
_Success_(return == 0) int
|
||||
SetClockidHeader(uint32_t clockid) noexcept;
|
||||
|
||||
// Sets the data for the CLOCK_DATA header.
|
||||
_Success_(return == 0) int
|
||||
SetClockDataHeader(uint32_t clockid, uint64_t wallClockNS, uint64_t clockidTimeNS) noexcept;
|
||||
|
||||
// Sets or resets the data for headers available in the specified sessionInfo:
|
||||
// - CLOCKID: Set based on Clockid(); cleared if Clockid() == 0xFFFFFFFF.
|
||||
// - CLOCK_DATA: Set based on GetClockOffset(); cleared if !ClockOffsetKnown().
|
||||
_Success_(return == 0) int
|
||||
SetSessionInfoHeaders(PerfEventSessionInfo const& sessionInfo) noexcept;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
// Sets or resets the data for the HOSTNAME, OSRELEASE, and ARCH headers.
|
||||
_Success_(return == 0) int
|
||||
SetUtsNameHeaders(utsname const& uts) noexcept;
|
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
// Configures information to be included in the synthesized
|
||||
// PERF_HEADER_TRACING_DATA header. These settings are given default values
|
||||
// when the PerfDataFileWriter is constructed. These settings are used by
|
||||
// CloseNoFinalize() if no data was provided via
|
||||
// SetHeader(PERF_HEADER_TRACING_DATA, ...).
|
||||
//
|
||||
// For all of the parameters, a 0 or {NULL, 0} value indicates "keep the
|
||||
// existing value". To indicate "set the value to empty", use {non-null, 0}.
|
||||
//
|
||||
// - longSize: Default is sizeof(size_t).
|
||||
// - pageSize: Default is sysconf(_SC_PAGESIZE).
|
||||
// - headerPage: Default is timestamp64+commit64+overwrite8+data4080. Empty means use default.
|
||||
// - headerEvent: Default is type_len:5, time_delta:27, array:32. Empty means use default.
|
||||
// - ftraces: Default is "".
|
||||
// - kallsyms: Default is "".
|
||||
// - printk: Default is "".
|
||||
// - savedCmdLine: Default is "".
|
||||
_Success_(return == 0) int
|
||||
SetTracingData(
|
||||
uint8_t longSize,
|
||||
uint32_t pageSize,
|
||||
std::string_view headerPage,
|
||||
std::string_view headerEvent,
|
||||
_In_reads_(ftraceCount) std::string_view const* ftraces,
|
||||
uint32_t ftraceCount,
|
||||
std::string_view kallsyms,
|
||||
std::string_view printk,
|
||||
std::string_view savedCmdLine) noexcept;
|
||||
|
||||
// Adds perf_event_attr and name information for the specified event ids.
|
||||
// Use this for events that do NOT have tracefs format information, i.e.
|
||||
// when desc.metadata == NULL.
|
||||
//
|
||||
// Requires: desc.attr != NULL, desc.name != NULL.
|
||||
//
|
||||
// Returns 0 for success, errno for error.
|
||||
// Returns E2BIG if desc.name is 64KB or longer.
|
||||
//
|
||||
// Note that each id used in the trace should map to exactly one attr provided
|
||||
// by AddTracepointEventDesc or AddEventDesc, but this is not validated by
|
||||
// PerfDataFileWriter. For example, if the same id is provided in two different
|
||||
// calls to AddEventDesc, the resulting file may not decode properly.
|
||||
_Success_(return == 0) int
|
||||
AddEventDesc(PerfEventDesc const& desc) noexcept;
|
||||
|
||||
// Returns true if there has been a successful call to
|
||||
// AddTracepointEventDesc(desc) where desc.metadata->Id() == common_type.
|
||||
bool
|
||||
HasTracepointEventDesc(uint32_t common_type) const noexcept;
|
||||
|
||||
// Adds perf_event_attr, name, and metadata for the specified event ids.
|
||||
// Use this for events that DO have tracefs format information, i.e.
|
||||
// when desc.metadata != NULL.
|
||||
//
|
||||
// Requires: desc.attr != NULL, desc.name != NULL, desc.metadata != NULL.
|
||||
// Also, desc.metadata is copied by reference (shallow copy).
|
||||
//
|
||||
// Returns 0 for success, errno for error.
|
||||
// Returns E2BIG if desc.name is 64KB or longer.
|
||||
// Returns EEXIST if metadata has already been set for the common_type
|
||||
// indicated in desc.metadata->Id().
|
||||
//
|
||||
// Note that each id used in the trace should map to exactly one attr provided
|
||||
// by AddTracepointEventDesc or AddEventDesc, but this is not validated by
|
||||
// PerfDataFileWriter. For example, if the same id is provided in two different
|
||||
// calls to AddEventDesc, the resulting file may not decode properly.
|
||||
_Success_(return == 0) int
|
||||
AddTracepointEventDesc(PerfEventDesc const& desc) noexcept;
|
||||
|
||||
private:
|
||||
|
||||
bool
|
||||
ValidFilePos() const noexcept;
|
||||
|
||||
_Success_(return == 0) int
|
||||
WriteData(
|
||||
_In_reads_bytes_(dataSize) void const* data,
|
||||
size_t dataSize) noexcept;
|
||||
|
||||
void
|
||||
SynthesizeTracingData();
|
||||
|
||||
void
|
||||
SynthesizeEventDesc();
|
||||
|
||||
// Writes the perf_file_sections for m_headers,
|
||||
// then writes the data from m_headers.
|
||||
_Success_(return == 0) int
|
||||
WriteHeaders(_Out_ uint64_t* pFlags0) noexcept;
|
||||
|
||||
// Writes the attr+idSection for each attr.
|
||||
// Then writes the id data.
|
||||
_Success_(return == 0) int
|
||||
WriteAttrs(_Out_ perf_file_section* pAttrsSection) noexcept;
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfDataFileWriter_h
|
774
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfEventAbi.h
vendored
Normal file
774
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfEventAbi.h
vendored
Normal file
|
@ -0,0 +1,774 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
// Adapted from linux/uapi/linux/perf_event.h.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfEventAbi_h
|
||||
#define _included_PerfEventAbi_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _Ret_z_
|
||||
#define _Ret_z_
|
||||
#endif
|
||||
#ifndef _Pre_cap_
|
||||
#define _Pre_cap_(c)
|
||||
#endif
|
||||
|
||||
#ifndef _ltpDecl
|
||||
#ifdef _WIN32
|
||||
#define _ltpDecl __cdecl
|
||||
#else
|
||||
#define _ltpDecl
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// uint32 value for perf_event_attr::type.
|
||||
enum perf_type_id : uint32_t {
|
||||
PERF_TYPE_HARDWARE = 0,
|
||||
PERF_TYPE_SOFTWARE = 1,
|
||||
PERF_TYPE_TRACEPOINT = 2,
|
||||
PERF_TYPE_HW_CACHE = 3,
|
||||
PERF_TYPE_RAW = 4,
|
||||
PERF_TYPE_BREAKPOINT = 5,
|
||||
|
||||
PERF_TYPE_MAX, // non-ABI
|
||||
};
|
||||
|
||||
// uint32 value for perf_event_attr::size.
|
||||
enum perf_event_attr_size : uint32_t
|
||||
{
|
||||
PERF_ATTR_SIZE_VER0 = 64, // first published struct
|
||||
PERF_ATTR_SIZE_VER1 = 72, // add: config2
|
||||
PERF_ATTR_SIZE_VER2 = 80, // add: branch_sample_type
|
||||
PERF_ATTR_SIZE_VER3 = 96, // add: sample_regs_user, sample_stack_user
|
||||
PERF_ATTR_SIZE_VER4 = 104, // add: sample_regs_intr
|
||||
PERF_ATTR_SIZE_VER5 = 112, // add: aux_watermark
|
||||
PERF_ATTR_SIZE_VER6 = 120, // add: aux_sample_size
|
||||
PERF_ATTR_SIZE_VER7 = 128, // add: sig_data
|
||||
};
|
||||
|
||||
// bits that can be set in perf_event_attr::sample_type.
|
||||
enum perf_event_sample_format {
|
||||
PERF_SAMPLE_IP = 1U << 0,
|
||||
PERF_SAMPLE_TID = 1U << 1,
|
||||
PERF_SAMPLE_TIME = 1U << 2,
|
||||
PERF_SAMPLE_ADDR = 1U << 3,
|
||||
PERF_SAMPLE_READ = 1U << 4,
|
||||
PERF_SAMPLE_CALLCHAIN = 1U << 5,
|
||||
PERF_SAMPLE_ID = 1U << 6,
|
||||
PERF_SAMPLE_CPU = 1U << 7,
|
||||
PERF_SAMPLE_PERIOD = 1U << 8,
|
||||
PERF_SAMPLE_STREAM_ID = 1U << 9,
|
||||
PERF_SAMPLE_RAW = 1U << 10,
|
||||
PERF_SAMPLE_BRANCH_STACK = 1U << 11,
|
||||
PERF_SAMPLE_REGS_USER = 1U << 12,
|
||||
PERF_SAMPLE_STACK_USER = 1U << 13,
|
||||
PERF_SAMPLE_WEIGHT = 1U << 14,
|
||||
PERF_SAMPLE_DATA_SRC = 1U << 15,
|
||||
PERF_SAMPLE_IDENTIFIER = 1U << 16,
|
||||
PERF_SAMPLE_TRANSACTION = 1U << 17,
|
||||
PERF_SAMPLE_REGS_INTR = 1U << 18,
|
||||
PERF_SAMPLE_PHYS_ADDR = 1U << 19,
|
||||
PERF_SAMPLE_AUX = 1U << 20,
|
||||
PERF_SAMPLE_CGROUP = 1U << 21,
|
||||
PERF_SAMPLE_DATA_PAGE_SIZE = 1U << 22,
|
||||
PERF_SAMPLE_CODE_PAGE_SIZE = 1U << 23,
|
||||
PERF_SAMPLE_WEIGHT_STRUCT = 1U << 24,
|
||||
|
||||
PERF_SAMPLE_MAX = 1U << 25, // non-ABI
|
||||
PERF_SAMPLE_WEIGHT_TYPE = PERF_SAMPLE_WEIGHT | PERF_SAMPLE_WEIGHT_STRUCT,
|
||||
};
|
||||
|
||||
// bits that can be set in perf_event_attr::read_format.
|
||||
enum perf_event_read_format {
|
||||
PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0,
|
||||
PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1,
|
||||
PERF_FORMAT_ID = 1U << 2,
|
||||
PERF_FORMAT_GROUP = 1U << 3,
|
||||
PERF_FORMAT_LOST = 1U << 4,
|
||||
|
||||
PERF_FORMAT_MAX = 1U << 5, // non-ABI
|
||||
};
|
||||
|
||||
// Event's collection parameters.
|
||||
struct perf_event_attr {
|
||||
perf_type_id type; // Major type: hardware/software/tracepoint/etc.
|
||||
perf_event_attr_size size; // Size of the attr structure, for fwd/bwd compat.
|
||||
uint64_t config; // Type-specific configuration information.
|
||||
|
||||
union {
|
||||
uint64_t sample_period;
|
||||
uint64_t sample_freq;
|
||||
};
|
||||
|
||||
uint64_t sample_type; // perf_event_sample_format
|
||||
uint64_t read_format; // perf_event_read_format
|
||||
|
||||
uint64_t disabled : 1; // off by default
|
||||
uint64_t inherit : 1; // children inherit it
|
||||
uint64_t pinned : 1; // must always be on PMU
|
||||
uint64_t exclusive : 1; // only group on PMU
|
||||
uint64_t exclude_user : 1; // don't count user
|
||||
uint64_t exclude_kernel : 1; // ditto kernel
|
||||
uint64_t exclude_hv : 1; // ditto hypervisor
|
||||
uint64_t exclude_idle : 1; // don't count when idle
|
||||
uint64_t mmap : 1; // include mmap data
|
||||
uint64_t comm : 1; // include comm data
|
||||
uint64_t freq : 1; // use freq, not period
|
||||
uint64_t inherit_stat : 1; // per task counts
|
||||
uint64_t enable_on_exec : 1; // next exec enables
|
||||
uint64_t task : 1; // trace fork/exit
|
||||
uint64_t watermark : 1; // wakeup_watermark
|
||||
|
||||
// skid constraint:
|
||||
// 0 - SAMPLE_IP can have arbitrary skid
|
||||
// 1 - SAMPLE_IP must have constant skid
|
||||
// 2 - SAMPLE_IP requested to have 0 skid
|
||||
// 3 - SAMPLE_IP must have 0 skid
|
||||
// See also PERF_RECORD_MISC_EXACT_IP
|
||||
uint64_t precise_ip : 2;
|
||||
uint64_t mmap_data : 1; // non-exec mmap data
|
||||
uint64_t sample_id_all : 1; // sample_type all events
|
||||
|
||||
uint64_t exclude_host : 1; // don't count in host
|
||||
uint64_t exclude_guest : 1; // don't count in guest
|
||||
|
||||
uint64_t exclude_callchain_kernel : 1; // exclude kernel callchains
|
||||
uint64_t exclude_callchain_user : 1; // exclude user callchains
|
||||
uint64_t mmap2 : 1; // include mmap with inode data
|
||||
uint64_t comm_exec : 1; // flag comm events that are due to an exec
|
||||
uint64_t use_clockid : 1; // use @clockid for time fields
|
||||
uint64_t context_switch : 1; // context switch data
|
||||
uint64_t write_backward : 1; // Write ring buffer from end to beginning
|
||||
uint64_t namespaces : 1; // include namespaces data
|
||||
uint64_t ksymbol : 1; // include ksymbol events
|
||||
uint64_t bpf_event : 1; // include bpf events
|
||||
uint64_t aux_output : 1; // generate AUX records instead of events
|
||||
uint64_t cgroup : 1; // include cgroup events
|
||||
uint64_t text_poke : 1; // include text poke events
|
||||
uint64_t build_id : 1; // use build id in mmap2 events
|
||||
uint64_t inherit_thread : 1; // children only inherit if cloned with CLONE_THREAD
|
||||
uint64_t remove_on_exec : 1; // event is removed from task on exec
|
||||
uint64_t sigtrap : 1; // send synchronous SIGTRAP on event
|
||||
uint64_t reserved1 : 26;
|
||||
|
||||
union {
|
||||
uint32_t wakeup_events; // wakeup every n events
|
||||
uint32_t wakeup_watermark; // bytes before wakeup
|
||||
};
|
||||
|
||||
uint32_t bp_type;
|
||||
union {
|
||||
uint64_t bp_addr;
|
||||
uint64_t kprobe_func; // for perf_kprobe
|
||||
uint64_t uprobe_path; // for perf_uprobe
|
||||
uint64_t config1; // extension of config
|
||||
};
|
||||
union {
|
||||
uint64_t bp_len;
|
||||
uint64_t kprobe_addr; // when kprobe_func == NULL
|
||||
uint64_t probe_offset; // for perf_[k,u]probe
|
||||
uint64_t config2; // extension of config1
|
||||
};
|
||||
uint64_t branch_sample_type; // enum perf_branch_sample_type
|
||||
|
||||
// Defines set of user regs to dump on samples.
|
||||
// See asm/perf_regs.h for details.
|
||||
uint64_t sample_regs_user;
|
||||
|
||||
// Defines size of the user stack to dump on samples.
|
||||
uint32_t sample_stack_user;
|
||||
|
||||
int32_t clockid;
|
||||
|
||||
// Defines set of regs to dump for each sample state captured on:
|
||||
// - precise = 0: PMU interrupt
|
||||
// - precise > 0: sampled instruction
|
||||
// See asm/perf_regs.h for details.
|
||||
uint64_t sample_regs_intr;
|
||||
|
||||
// Wakeup watermark for AUX area
|
||||
uint32_t aux_watermark;
|
||||
uint16_t sample_max_stack;
|
||||
uint16_t reserved2;
|
||||
uint32_t aux_sample_size;
|
||||
uint32_t reserved3;
|
||||
|
||||
// User provided data if sigtrap=1, passed back to user via
|
||||
// siginfo_t::si_perf_data, e.g. to permit user to identify the event.
|
||||
// Note, siginfo_t::si_perf_data is long-sized, and sig_data will be
|
||||
// truncated accordingly on 32 bit architectures.
|
||||
uint64_t sig_data;
|
||||
|
||||
// Reverse the endian order of all fields in this struct.
|
||||
void ByteSwap() noexcept;
|
||||
};
|
||||
static_assert(sizeof(perf_event_attr) == PERF_ATTR_SIZE_VER7, "Bad perf_event_attr");
|
||||
|
||||
// uint32 value for perf_event_header::type.
|
||||
enum perf_event_type : uint32_t {
|
||||
|
||||
/*
|
||||
* If perf_event_attr.sample_id_all is set then all event types will
|
||||
* have the sample_type selected fields related to where/when
|
||||
* (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU,
|
||||
* IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed
|
||||
* just after the perf_event_header and the fields already present for
|
||||
* the existing fields, i.e. at the end of the payload. That way a newer
|
||||
* perf.data file will be supported by older perf tools, with these new
|
||||
* optional fields being ignored.
|
||||
*
|
||||
* struct sample_id {
|
||||
* { u32 pid, tid; } && PERF_SAMPLE_TID
|
||||
* { u64 time; } && PERF_SAMPLE_TIME
|
||||
* { u64 id; } && PERF_SAMPLE_ID
|
||||
* { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
|
||||
* { u32 cpu, res; } && PERF_SAMPLE_CPU
|
||||
* { u64 id; } && PERF_SAMPLE_IDENTIFIER
|
||||
* } && perf_event_attr::sample_id_all
|
||||
*
|
||||
* Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The
|
||||
* advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed
|
||||
* relative to header.size.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The MMAP events record the PROT_EXEC mappings so that we can
|
||||
* correlate userspace IPs to code. They have the following structure:
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
*
|
||||
* u32 pid, tid;
|
||||
* u64 addr;
|
||||
* u64 len;
|
||||
* u64 pgoff;
|
||||
* char filename[];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_MMAP = 1,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u64 id;
|
||||
* u64 lost;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_LOST = 2,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
*
|
||||
* u32 pid, tid;
|
||||
* char comm[];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_COMM = 3,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u32 pid, ppid;
|
||||
* u32 tid, ptid;
|
||||
* u64 time;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_EXIT = 4,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u64 time;
|
||||
* u64 id;
|
||||
* u64 stream_id;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_THROTTLE = 5,
|
||||
PERF_RECORD_UNTHROTTLE = 6,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u32 pid, ppid;
|
||||
* u32 tid, ptid;
|
||||
* u64 time;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_FORK = 7,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u32 pid, tid;
|
||||
*
|
||||
* struct read_format values;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_READ = 8,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
*
|
||||
* #
|
||||
* # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID.
|
||||
* # The advantage of PERF_SAMPLE_IDENTIFIER is that its position
|
||||
* # is fixed relative to header.
|
||||
* #
|
||||
*
|
||||
* { u64 id; } && PERF_SAMPLE_IDENTIFIER
|
||||
* { u64 ip; } && PERF_SAMPLE_IP
|
||||
* { u32 pid, tid; } && PERF_SAMPLE_TID
|
||||
* { u64 time; } && PERF_SAMPLE_TIME
|
||||
* { u64 addr; } && PERF_SAMPLE_ADDR
|
||||
* { u64 id; } && PERF_SAMPLE_ID
|
||||
* { u64 stream_id;} && PERF_SAMPLE_STREAM_ID
|
||||
* { u32 cpu, res; } && PERF_SAMPLE_CPU
|
||||
* { u64 period; } && PERF_SAMPLE_PERIOD
|
||||
*
|
||||
* { struct read_format values; } && PERF_SAMPLE_READ
|
||||
*
|
||||
* { u64 nr,
|
||||
* u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN
|
||||
*
|
||||
* #
|
||||
* # The RAW record below is opaque data wrt the ABI
|
||||
* #
|
||||
* # That is, the ABI doesn't make any promises wrt to
|
||||
* # the stability of its content, it may vary depending
|
||||
* # on event, hardware, kernel version and phase of
|
||||
* # the moon.
|
||||
* #
|
||||
* # In other words, PERF_SAMPLE_RAW contents are not an ABI.
|
||||
* #
|
||||
*
|
||||
* { u32 size;
|
||||
* char data[size];}&& PERF_SAMPLE_RAW
|
||||
*
|
||||
* { u64 nr;
|
||||
* { u64 hw_idx; } && PERF_SAMPLE_BRANCH_HW_INDEX
|
||||
* { u64 from, to, flags } lbr[nr];
|
||||
* } && PERF_SAMPLE_BRANCH_STACK
|
||||
*
|
||||
* { u64 abi; # enum perf_sample_regs_abi
|
||||
* u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER
|
||||
*
|
||||
* { u64 size;
|
||||
* char data[size];
|
||||
* u64 dyn_size; } && PERF_SAMPLE_STACK_USER
|
||||
*
|
||||
* { union perf_sample_weight
|
||||
* {
|
||||
* u64 full; && PERF_SAMPLE_WEIGHT
|
||||
* #if defined(__LITTLE_ENDIAN_BITFIELD)
|
||||
* struct {
|
||||
* u32 var1_dw;
|
||||
* u16 var2_w;
|
||||
* u16 var3_w;
|
||||
* } && PERF_SAMPLE_WEIGHT_STRUCT
|
||||
* #elif defined(__BIG_ENDIAN_BITFIELD)
|
||||
* struct {
|
||||
* u16 var3_w;
|
||||
* u16 var2_w;
|
||||
* u32 var1_dw;
|
||||
* } && PERF_SAMPLE_WEIGHT_STRUCT
|
||||
* #endif
|
||||
* }
|
||||
* }
|
||||
* { u64 data_src; } && PERF_SAMPLE_DATA_SRC
|
||||
* { u64 transaction; } && PERF_SAMPLE_TRANSACTION
|
||||
* { u64 abi; # enum perf_sample_regs_abi
|
||||
* u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
|
||||
* { u64 phys_addr;} && PERF_SAMPLE_PHYS_ADDR
|
||||
* { u64 size;
|
||||
* char data[size]; } && PERF_SAMPLE_AUX
|
||||
* { u64 data_page_size;} && PERF_SAMPLE_DATA_PAGE_SIZE
|
||||
* { u64 code_page_size;} && PERF_SAMPLE_CODE_PAGE_SIZE
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_SAMPLE = 9,
|
||||
|
||||
/*
|
||||
* The MMAP2 records are an augmented version of MMAP, they add
|
||||
* maj, min, ino numbers to be used to uniquely identify each mapping
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
*
|
||||
* u32 pid, tid;
|
||||
* u64 addr;
|
||||
* u64 len;
|
||||
* u64 pgoff;
|
||||
* union {
|
||||
* struct {
|
||||
* u32 maj;
|
||||
* u32 min;
|
||||
* u64 ino;
|
||||
* u64 ino_generation;
|
||||
* };
|
||||
* struct {
|
||||
* u8 build_id_size;
|
||||
* u8 __reserved_1;
|
||||
* u16 __reserved_2;
|
||||
* u8 build_id[20];
|
||||
* };
|
||||
* };
|
||||
* u32 prot, flags;
|
||||
* char filename[];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_MMAP2 = 10,
|
||||
|
||||
/*
|
||||
* Records that new data landed in the AUX buffer part.
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
*
|
||||
* u64 aux_offset;
|
||||
* u64 aux_size;
|
||||
* u64 flags;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_AUX = 11,
|
||||
|
||||
/*
|
||||
* Indicates that instruction trace has started
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u32 pid;
|
||||
* u32 tid;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_ITRACE_START = 12,
|
||||
|
||||
/*
|
||||
* Records the dropped/lost sample number.
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
*
|
||||
* u64 lost;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_LOST_SAMPLES = 13,
|
||||
|
||||
/*
|
||||
* Records a context switch in or out (flagged by
|
||||
* PERF_RECORD_MISC_SWITCH_OUT). See also
|
||||
* PERF_RECORD_SWITCH_CPU_WIDE.
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_SWITCH = 14,
|
||||
|
||||
/*
|
||||
* CPU-wide version of PERF_RECORD_SWITCH with next_prev_pid and
|
||||
* next_prev_tid that are the next (switching out) or previous
|
||||
* (switching in) pid/tid.
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u32 next_prev_pid;
|
||||
* u32 next_prev_tid;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_SWITCH_CPU_WIDE = 15,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u32 pid;
|
||||
* u32 tid;
|
||||
* u64 nr_namespaces;
|
||||
* { u64 dev, inode; } [nr_namespaces];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_NAMESPACES = 16,
|
||||
|
||||
/*
|
||||
* Record ksymbol register/unregister events:
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u64 addr;
|
||||
* u32 len;
|
||||
* u16 ksym_type;
|
||||
* u16 flags;
|
||||
* char name[];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_KSYMBOL = 17,
|
||||
|
||||
/*
|
||||
* Record bpf events:
|
||||
* enum perf_bpf_event_type {
|
||||
* PERF_BPF_EVENT_UNKNOWN = 0,
|
||||
* PERF_BPF_EVENT_PROG_LOAD = 1,
|
||||
* PERF_BPF_EVENT_PROG_UNLOAD = 2,
|
||||
* };
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u16 type;
|
||||
* u16 flags;
|
||||
* u32 id;
|
||||
* u8 tag[BPF_TAG_SIZE];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_BPF_EVENT = 18,
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u64 id;
|
||||
* char path[];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_CGROUP = 19,
|
||||
|
||||
/*
|
||||
* Records changes to kernel text i.e. self-modified code. 'old_len' is
|
||||
* the number of old bytes, 'new_len' is the number of new bytes. Either
|
||||
* 'old_len' or 'new_len' may be zero to indicate, for example, the
|
||||
* addition or removal of a trampoline. 'bytes' contains the old bytes
|
||||
* followed immediately by the new bytes.
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u64 addr;
|
||||
* u16 old_len;
|
||||
* u16 new_len;
|
||||
* u8 bytes[];
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_TEXT_POKE = 20,
|
||||
|
||||
/*
|
||||
* Data written to the AUX area by hardware due to aux_output, may need
|
||||
* to be matched to the event by an architecture-specific hardware ID.
|
||||
* This records the hardware ID, but requires sample_id to provide the
|
||||
* event ID. e.g. Intel PT uses this record to disambiguate PEBS-via-PT
|
||||
* records from multiple events.
|
||||
*
|
||||
* struct {
|
||||
* struct perf_event_header header;
|
||||
* u64 hw_id;
|
||||
* struct sample_id sample_id;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_AUX_OUTPUT_HW_ID = 21,
|
||||
|
||||
PERF_RECORD_MAX, // non-ABI
|
||||
|
||||
PERF_RECORD_USER_TYPE_START = 64,
|
||||
|
||||
/*
|
||||
* struct attr_event {
|
||||
* struct perf_event_header header;
|
||||
* struct perf_event_attr attr;
|
||||
* uint64_t id[];
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_HEADER_ATTR = 64,
|
||||
|
||||
/* deprecated
|
||||
*
|
||||
* #define MAX_EVENT_NAME 64
|
||||
*
|
||||
* struct perf_trace_event_type {
|
||||
* uint64_t event_id;
|
||||
* char name[MAX_EVENT_NAME];
|
||||
* };
|
||||
*
|
||||
* struct event_type_event {
|
||||
* struct perf_event_header header;
|
||||
* struct perf_trace_event_type event_type;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_HEADER_EVENT_TYPE = 65,
|
||||
|
||||
/* Describe me
|
||||
*
|
||||
* struct tracing_data_event {
|
||||
* struct perf_event_header header;
|
||||
* uint32_t size;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_HEADER_TRACING_DATA = 66,
|
||||
|
||||
/* Define a ELF build ID for a referenced executable. */
|
||||
PERF_RECORD_HEADER_BUILD_ID = 67,
|
||||
|
||||
/* No event reordering over this header. No payload. */
|
||||
PERF_RECORD_FINISHED_ROUND = 68,
|
||||
|
||||
/*
|
||||
* Map event ids to CPUs and TIDs.
|
||||
*
|
||||
* struct id_index_entry {
|
||||
* uint64_t id;
|
||||
* uint64_t idx;
|
||||
* uint64_t cpu;
|
||||
* uint64_t tid;
|
||||
* };
|
||||
*
|
||||
* struct id_index_event {
|
||||
* struct perf_event_header header;
|
||||
* uint64_t nr;
|
||||
* struct id_index_entry entries[nr];
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_ID_INDEX = 69,
|
||||
|
||||
/*
|
||||
* Auxtrace type specific information. Describe me
|
||||
*
|
||||
* struct auxtrace_info_event {
|
||||
* struct perf_event_header header;
|
||||
* uint32_t type;
|
||||
* uint32_t reserved__; // For alignment
|
||||
* uint64_t priv[];
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_AUXTRACE_INFO = 70,
|
||||
|
||||
/*
|
||||
* Defines auxtrace data. Followed by the actual data. The contents of
|
||||
* the auxtrace data is dependent on the event and the CPU. For example
|
||||
* for Intel Processor Trace it contains Processor Trace data generated
|
||||
* by the CPU.
|
||||
*
|
||||
* struct auxtrace_event {
|
||||
* struct perf_event_header header;
|
||||
* uint64_t size;
|
||||
* uint64_t offset;
|
||||
* uint64_t reference;
|
||||
* uint32_t idx;
|
||||
* uint32_t tid;
|
||||
* uint32_t cpu;
|
||||
* uint32_t reserved__; // For alignment
|
||||
* };
|
||||
*
|
||||
* struct aux_event {
|
||||
* struct perf_event_header header;
|
||||
* uint64_t aux_offset;
|
||||
* uint64_t aux_size;
|
||||
* uint64_t flags;
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_AUXTRACE = 71,
|
||||
|
||||
/*
|
||||
* Describes an error in hardware tracing
|
||||
*
|
||||
* enum auxtrace_error_type {
|
||||
* PERF_AUXTRACE_ERROR_ITRACE = 1,
|
||||
* PERF_AUXTRACE_ERROR_MAX
|
||||
* };
|
||||
*
|
||||
* #define MAX_AUXTRACE_ERROR_MSG 64
|
||||
*
|
||||
* struct auxtrace_error_event {
|
||||
* struct perf_event_header header;
|
||||
* uint32_t type;
|
||||
* uint32_t code;
|
||||
* uint32_t cpu;
|
||||
* uint32_t pid;
|
||||
* uint32_t tid;
|
||||
* uint32_t reserved__; // For alignment
|
||||
* uint64_t ip;
|
||||
* char msg[MAX_AUXTRACE_ERROR_MSG];
|
||||
* };
|
||||
*/
|
||||
PERF_RECORD_AUXTRACE_ERROR = 72,
|
||||
|
||||
PERF_RECORD_THREAD_MAP = 73,
|
||||
PERF_RECORD_CPU_MAP = 74,
|
||||
PERF_RECORD_STAT_CONFIG = 75,
|
||||
PERF_RECORD_STAT = 76,
|
||||
PERF_RECORD_STAT_ROUND = 77,
|
||||
PERF_RECORD_EVENT_UPDATE = 78,
|
||||
PERF_RECORD_TIME_CONV = 79,
|
||||
|
||||
/*
|
||||
* Describes a header feature. These are records used in pipe-mode that
|
||||
* contain information that otherwise would be in perf.data file's header.
|
||||
*/
|
||||
PERF_RECORD_HEADER_FEATURE = 80,
|
||||
|
||||
/*
|
||||
* struct compressed_event {
|
||||
* struct perf_event_header header;
|
||||
* char data[];
|
||||
* };
|
||||
|
||||
The header is followed by compressed data frame that can be decompressed
|
||||
into array of perf trace records. The size of the entire compressed event
|
||||
record including the header is limited by the max value of header.size.
|
||||
*/
|
||||
PERF_RECORD_COMPRESSED = 81,
|
||||
|
||||
/*
|
||||
Marks the end of records for the system, pre-existing threads in system wide
|
||||
sessions, etc. Those are the ones prefixed PERF_RECORD_USER_*.
|
||||
|
||||
This is used, for instance, to 'perf inject' events after init and before
|
||||
regular events, those emitted by the kernel, to support combining guest and
|
||||
host records.
|
||||
*/
|
||||
PERF_RECORD_FINISHED_INIT = 82,
|
||||
};
|
||||
|
||||
// Information at the start of each event.
|
||||
struct perf_event_header {
|
||||
perf_event_type type;
|
||||
uint16_t misc;
|
||||
uint16_t size;
|
||||
|
||||
// Reverse the endian order of all fields in this struct.
|
||||
void ByteSwap() noexcept;
|
||||
};
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Returns a string for the PERF_TYPE_* enum value, e.g. "HARDWARE".
|
||||
// If enum is not recognized, formats decimal value into and returns scratch.
|
||||
_Ret_z_ char const* _ltpDecl
|
||||
PerfEnumToString(perf_type_id value, _Pre_cap_(11) char* scratch) noexcept;
|
||||
|
||||
// Returns a string for the PERF_RECORD_* enum value, e.g. "SAMPLE".
|
||||
// If enum is not recognized, formats decimal value into and returns scratch.
|
||||
_Ret_z_ char const* _ltpDecl
|
||||
PerfEnumToString(perf_event_type value, _Pre_cap_(11) char* scratch) noexcept;
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfEventAbi_h
|
109
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfEventInfo.h
vendored
Normal file
109
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfEventInfo.h
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfEventInfo_h
|
||||
#define _included_PerfEventInfo_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _Field_size_bytes_
|
||||
#define _Field_size_bytes_(size)
|
||||
#endif
|
||||
#ifndef _Ret_z_
|
||||
#define _Ret_z_
|
||||
#endif
|
||||
#ifndef _Ret_opt_
|
||||
#define _Ret_opt_
|
||||
#endif
|
||||
|
||||
// Forward declarations from PerfEventAbi.h or linux/uapi/linux/perf_event.h:
|
||||
struct perf_event_attr;
|
||||
struct perf_event_header;
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Forward declaration from PerfDataFileDefs.h:
|
||||
struct PerfEventDesc;
|
||||
|
||||
// Forward declaration from PerfEventSessionInfo.h:
|
||||
class PerfEventSessionInfo;
|
||||
|
||||
// Forward declaration from PerfEventMetadata.h:
|
||||
class PerfEventMetadata;
|
||||
|
||||
struct PerfSampleEventInfo
|
||||
{
|
||||
PerfEventDesc const* event_desc; // Always valid if GetSampleEventInfo() succeeded.
|
||||
PerfEventSessionInfo const* session_info;//Always valid if GetSampleEventInfo() succeeded.
|
||||
perf_event_header const* header; // Always valid if GetSampleEventInfo() succeeded. Points into event.
|
||||
uint64_t id; // Valid if SampleType() & (PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_ID).
|
||||
uint32_t pid, tid; // Valid if SampleType() & PERF_SAMPLE_TID.
|
||||
uint64_t time; // Valid if SampleType() & PERF_SAMPLE_TIME.
|
||||
uint64_t stream_id; // Valid if SampleType() & PERF_SAMPLE_STREAM_ID.
|
||||
uint32_t cpu, cpu_reserved; // Valid if SampleType() & PERF_SAMPLE_CPU.
|
||||
uint64_t ip; // Valid if SampleType() & PERF_SAMPLE_IP.
|
||||
uint64_t addr; // Valid if SampleType() & PERF_SAMPLE_ADDR.
|
||||
uint64_t period; // Valid if SampleType() & PERF_SAMPLE_PERIOD.
|
||||
uint64_t const* read_values; // Valid if SampleType() & PERF_SAMPLE_READ. Points into event.
|
||||
uint64_t const* callchain; // Valid if SampleType() & PERF_SAMPLE_CALLCHAIN. Points into event.
|
||||
_Field_size_bytes_(raw_data_size) void const* raw_data; // Valid if SampleType() & PERF_SAMPLE_RAW. Points into event.
|
||||
uintptr_t raw_data_size; // Valid if SampleType() & PERF_SAMPLE_RAW. Size of raw_data.
|
||||
|
||||
// Requires: GetSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->attr->sample_type.
|
||||
uint64_t
|
||||
SampleType() const noexcept;
|
||||
|
||||
// Requires: GetSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->attr.
|
||||
perf_event_attr const&
|
||||
Attr() const noexcept;
|
||||
|
||||
// Requires: GetSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->name.
|
||||
// May be "", e.g. if no PERF_HEADER_EVENT_DESC header. In that case,
|
||||
// caller should check for a name in Metadata().
|
||||
_Ret_z_ char const*
|
||||
Name() const noexcept;
|
||||
|
||||
// Requires: GetSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->metadata (may be NULL).
|
||||
// Valid if SampleType() & PERF_SAMPLE_RAW.
|
||||
_Ret_opt_ PerfEventMetadata const*
|
||||
Metadata() const noexcept;
|
||||
};
|
||||
|
||||
struct PerfNonSampleEventInfo
|
||||
{
|
||||
PerfEventDesc const* event_desc; // Always valid if GetNonSampleEventInfo() succeeded.
|
||||
PerfEventSessionInfo const* session_info;//Always valid if GetNonSampleEventInfo() succeeded.
|
||||
perf_event_header const* header; // Always valid if GetNonSampleEventInfo() succeeded. Points into event.
|
||||
uint64_t id; // Valid if SampleType() & (PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_ID).
|
||||
uint32_t pid, tid; // Valid if SampleType() & PERF_SAMPLE_TID.
|
||||
uint64_t time; // Valid if SampleType() & PERF_SAMPLE_TIME.
|
||||
uint64_t stream_id; // Valid if SampleType() & PERF_SAMPLE_STREAM_ID.
|
||||
uint32_t cpu, cpu_reserved; // Valid if SampleType() & PERF_SAMPLE_CPU.
|
||||
|
||||
// Requires: GetNonSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->attr->sample_type.
|
||||
uint64_t
|
||||
SampleType() const noexcept;
|
||||
|
||||
// Requires: GetNonSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->attr.
|
||||
perf_event_attr const&
|
||||
Attr() const noexcept;
|
||||
|
||||
// Requires: GetNonSampleEventInfo() succeeded.
|
||||
// Returns: event_desc->name.
|
||||
_Ret_z_ char const*
|
||||
Name() const noexcept;
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfEventInfo_h
|
242
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfEventMetadata.h
vendored
Normal file
242
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/include/tracepoint/PerfEventMetadata.h
vendored
Normal file
|
@ -0,0 +1,242 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfEventMetadata_h
|
||||
#define _included_PerfEventMetadata_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _In_reads_bytes_
|
||||
#define _In_reads_bytes_(cb)
|
||||
#endif
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
enum PerfFieldElementSize : uint8_t
|
||||
{
|
||||
PerfFieldElementSize8 = 0, // sizeof(uint8_t) == 1 << PerfFieldElementSize8
|
||||
PerfFieldElementSize16 = 1, // sizeof(uint16_t) == 1 << PerfFieldElementSize16
|
||||
PerfFieldElementSize32 = 2, // sizeof(uint32_t) == 1 << PerfFieldElementSize32
|
||||
PerfFieldElementSize64 = 3, // sizeof(uint64_t) == 1 << PerfFieldElementSize64
|
||||
};
|
||||
|
||||
enum PerfFieldFormat : uint8_t
|
||||
{
|
||||
PerfFieldFormatNone, // Type unknown (treat as binary blob)
|
||||
PerfFieldFormatUnsigned,// u8, u16, u32, u64, etc.
|
||||
PerfFieldFormatSigned, // s8, s16, s32, s64, etc.
|
||||
PerfFieldFormatHex, // unsigned long, pointers
|
||||
PerfFieldFormatString, // char, char[]
|
||||
};
|
||||
|
||||
enum PerfFieldArray : uint8_t
|
||||
{
|
||||
PerfFieldArrayNone, // e.g. "char val"
|
||||
PerfFieldArrayFixed, // e.g. "char val[12]"
|
||||
PerfFieldArrayDynamic, // e.g. "__data_loc char val[]", value = (len << 16) | offset.
|
||||
PerfFieldArrayRelDyn, // e.g. "__rel_loc char val[]", value = (len << 16) | relativeOffset.
|
||||
};
|
||||
|
||||
class PerfFieldMetadata
|
||||
{
|
||||
static constexpr std::string_view noname = std::string_view("noname", 6);
|
||||
|
||||
std::string_view m_name; // deduced from field, e.g. "my_field".
|
||||
std::string_view m_field; // value of "field:" property, e.g. "char my_field[8]".
|
||||
uint16_t m_offset; // value of "offset:" property.
|
||||
uint16_t m_size; // value of "size:" property.
|
||||
uint16_t m_fixedArrayCount; // deduced from field, size.
|
||||
PerfFieldElementSize m_elementSize; // deduced from field, size.
|
||||
PerfFieldFormat m_format; // deduced from field, size, signed.
|
||||
PerfFieldArray m_array; // deduced from field, size.
|
||||
|
||||
public:
|
||||
|
||||
// Parses a line of the "format:" section of an event's "format" file. The
|
||||
// formatLine string will generally look like
|
||||
// "[whitespace?]field:[declaration]; offset:[number]; size:[number]; ...".
|
||||
//
|
||||
// If "field:" is non-empty, "offset:" is a valid unsigned integer, and
|
||||
// "size:" is a valid unsigned integer, this returns
|
||||
// PerfFieldMetadata(field, offset, size, isSigned). Otherwise, this
|
||||
// returns PerfFieldMetadata().
|
||||
//
|
||||
// Stored strings will point into formatLine, so the formatLine string must
|
||||
// outlive this object.
|
||||
static PerfFieldMetadata
|
||||
Parse(
|
||||
bool longSize64, // true if sizeof(long) == 8, false if sizeof(long) == 4.
|
||||
std::string_view formatLine) noexcept;
|
||||
|
||||
// Same as PerfFieldMetadata(false, {}, 0, 0)
|
||||
constexpr
|
||||
PerfFieldMetadata() noexcept
|
||||
: m_name(noname)
|
||||
, m_field()
|
||||
, m_offset()
|
||||
, m_size()
|
||||
, m_fixedArrayCount()
|
||||
, m_elementSize()
|
||||
, m_format()
|
||||
, m_array() {}
|
||||
|
||||
// Initializes Field, Offset, and Size properties exactly as specified.
|
||||
// Deduces the other properties. The isSigned parameter should be -1 if the
|
||||
// "signed:" property is not present in the format line.
|
||||
PerfFieldMetadata(
|
||||
bool longSize64, // true if sizeof(long) == 8, false if sizeof(long) == 4.
|
||||
std::string_view field,
|
||||
uint16_t offset,
|
||||
uint16_t size,
|
||||
int8_t isSigned = -1) noexcept;
|
||||
|
||||
// Returns the field name, e.g. "my_field". Never empty. (Deduced from
|
||||
// "field:".)
|
||||
constexpr std::string_view
|
||||
Name() const noexcept { return m_name; }
|
||||
|
||||
// Returns the field declaration, e.g. "char my_field[8]".
|
||||
// (Parsed directly from "field:".)
|
||||
constexpr std::string_view
|
||||
Field() const noexcept { return m_field; }
|
||||
|
||||
// Returns the byte offset of the start of the field data from the start of
|
||||
// the event raw data. (Parsed directly from "offset:".)
|
||||
constexpr uint16_t
|
||||
Offset() const noexcept { return m_offset; }
|
||||
|
||||
// Returns the byte size of the field data. (Parsed directly from "size:".)
|
||||
constexpr uint16_t
|
||||
Size() const noexcept { return m_size; }
|
||||
|
||||
// Returns the number of elements in this field. Meaningful only when
|
||||
// Array() == Fixed. (Deduced from "field:" and "size:".)
|
||||
constexpr uint16_t
|
||||
FixedArrayCount() const noexcept { return m_fixedArrayCount; }
|
||||
|
||||
// Returns the size of each element in this field. (Deduced from "field:"
|
||||
// and "size:".)
|
||||
constexpr PerfFieldElementSize
|
||||
ElementSize() const noexcept { return m_elementSize; }
|
||||
|
||||
// Returns the format of the field. (Deduced from "field:" and "signed:".)
|
||||
constexpr PerfFieldFormat
|
||||
Format() const noexcept { return m_format; }
|
||||
|
||||
// Returns whether this is an array, and if so, how the array length should
|
||||
// be determined. (Deduced from "field:" and "size:".)
|
||||
constexpr PerfFieldArray
|
||||
Array() const noexcept { return m_array; }
|
||||
|
||||
// Given the event's raw data (e.g. PerfSampleEventInfo::raw_data), return
|
||||
// this field's raw data. Returns empty for error (e.g. out of bounds).
|
||||
//
|
||||
// Does not do any byte-swapping. This method uses fileBigEndian to resolve
|
||||
// data_loc and rel_loc references, not to fix up the field data.
|
||||
//
|
||||
// Note that in some cases, the size returned by GetFieldBytes may be
|
||||
// different from the value returned by Size():
|
||||
//
|
||||
// - If eventRawDataSize < Offset() + Size(), returns {}.
|
||||
// - If Size() == 0, returns all data from offset to the end of the event,
|
||||
// i.e. it returns eventRawDataSize - Offset() bytes.
|
||||
// - If Array() is Dynamic or RelDyn, the returned size depends on the
|
||||
// event contents.
|
||||
std::string_view
|
||||
GetFieldBytes(
|
||||
_In_reads_bytes_(eventRawDataSize) void const* eventRawData,
|
||||
uintptr_t eventRawDataSize,
|
||||
bool fileBigEndian) const noexcept;
|
||||
};
|
||||
|
||||
enum class PerfEventKind : uint8_t
|
||||
{
|
||||
Normal, // No special handling detected.
|
||||
EventHeader, // First user field is named "eventheader_flags".
|
||||
};
|
||||
|
||||
class PerfEventMetadata
|
||||
{
|
||||
std::string_view m_systemName;
|
||||
std::string_view m_formatFileContents;
|
||||
std::string_view m_name;
|
||||
std::string_view m_printFmt;
|
||||
std::vector<PerfFieldMetadata> m_fields;
|
||||
uint32_t m_id; // From common_type; not the same as the perf_event_attr::id or PerfSampleEventInfo::id.
|
||||
uint16_t m_commonFieldCount; // fields[common_field_count] is the first user field.
|
||||
uint16_t m_commonFieldsSize; // Offset of the end of the last common field
|
||||
PerfEventKind m_kind;
|
||||
|
||||
public:
|
||||
|
||||
~PerfEventMetadata();
|
||||
PerfEventMetadata() noexcept;
|
||||
|
||||
// Returns the value of the systemName parameter, e.g. "user_events".
|
||||
constexpr std::string_view
|
||||
SystemName() const noexcept { return m_systemName; }
|
||||
|
||||
// Returns the value of the formatFileContents parameter, e.g.
|
||||
// "name: my_event\nID: 1234\nformat:...".
|
||||
constexpr std::string_view
|
||||
FormatFileContents() const noexcept { return m_formatFileContents; }
|
||||
|
||||
// Returns the value of the "name:" property, e.g. "my_event".
|
||||
constexpr std::string_view
|
||||
Name() const noexcept { return m_name; }
|
||||
|
||||
// Returns the value of the "print fmt:" property.
|
||||
constexpr std::string_view
|
||||
PrintFmt() const noexcept { return m_printFmt; }
|
||||
|
||||
// Returns the fields from the "format:" property.
|
||||
constexpr std::vector<PerfFieldMetadata> const&
|
||||
Fields() const noexcept { return m_fields; }
|
||||
|
||||
// Returns the value of the "ID:" property. Note that this value gets
|
||||
// matched against the "common_type" field of an event, not the id field
|
||||
// of perf_event_attr or PerfSampleEventInfo.
|
||||
constexpr uint32_t
|
||||
Id() const noexcept { return m_id; }
|
||||
|
||||
// Returns the number of "common_*" fields at the start of the event.
|
||||
// User fields start at this index. At present, there are 4 common fields:
|
||||
// common_type, common_flags, common_preempt_count, common_pid.
|
||||
constexpr uint16_t
|
||||
CommonFieldCount() const noexcept { return m_commonFieldCount; }
|
||||
|
||||
// Returns the offset of the end of the last "common_*" field.
|
||||
// This is the start of the first user field.
|
||||
constexpr uint16_t
|
||||
CommonFieldsSize() const noexcept { return m_commonFieldsSize; }
|
||||
|
||||
// Returns the detected event decoding system - Normal or EventHeader.
|
||||
constexpr PerfEventKind
|
||||
Kind() const noexcept { return m_kind; }
|
||||
|
||||
// Sets all properties of this object to {} values.
|
||||
void
|
||||
Clear() noexcept;
|
||||
|
||||
// Parses an event's "format" file and sets the fields of this object based
|
||||
// on the results. Returns true if "ID:" is a valid unsigned integer and
|
||||
// "name:" is non-empty, returns true. Throws bad_alloc for out-of-memory.
|
||||
//
|
||||
// Stored strings will point into systemName and formatFileContents, so
|
||||
// those strings must outlive this object.
|
||||
bool
|
||||
Parse(
|
||||
bool longSize64, // true if sizeof(long) == 8, false if sizeof(long) == 4.
|
||||
std::string_view systemName,
|
||||
std::string_view formatFileContents) noexcept(false); // May throw bad_alloc.
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfEventMetadata_h
|
|
@ -0,0 +1,91 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#pragma once
|
||||
#ifndef _included_PerfEventSessionInfo_h
|
||||
#define _included_PerfEventSessionInfo_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <sal.h>
|
||||
#endif
|
||||
#ifndef _Out_
|
||||
#define _Out_
|
||||
#endif
|
||||
|
||||
namespace tracepoint_decode
|
||||
{
|
||||
// Semantics equivalent to struct timespec from <time.h>.
|
||||
struct PerfEventTimeSpec
|
||||
{
|
||||
int64_t tv_sec; // Seconds since 1970.
|
||||
uint32_t tv_nsec; // Nanoseconds.
|
||||
};
|
||||
|
||||
class PerfEventSessionInfo
|
||||
{
|
||||
int64_t m_clockOffsetSec;
|
||||
uint32_t m_clockOffsetNsec;
|
||||
uint32_t m_clockId;
|
||||
bool m_clockOffsetKnown;
|
||||
|
||||
public:
|
||||
|
||||
constexpr
|
||||
PerfEventSessionInfo() noexcept
|
||||
: m_clockOffsetSec(0)
|
||||
, m_clockOffsetNsec(0)
|
||||
, m_clockId(0xFFFFFFFF)
|
||||
, m_clockOffsetKnown(false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// From HEADER_CLOCKID. If unknown, use SetClockid(0xFFFFFFFF).
|
||||
void
|
||||
SetClockid(uint32_t clockid) noexcept;
|
||||
|
||||
// From HEADER_CLOCK_DATA. If unknown, use SetClockData(0xFFFFFFFF, 0, 0).
|
||||
void
|
||||
SetClockData(uint32_t clockid, uint64_t wallClockNS, uint64_t clockidTimeNS) noexcept;
|
||||
|
||||
// Gets offset values suitable for use in HEADER_CLOCK_DATA.
|
||||
// Note: The returned NS values may be normalized relative to the values provided
|
||||
// to SetClockData, but the difference between them will be the same as the
|
||||
// difference between the values provided to SetClockData.
|
||||
void
|
||||
GetClockData(
|
||||
_Out_ uint64_t* wallClockNS,
|
||||
_Out_ uint64_t* clockidTimeNS) const noexcept;
|
||||
|
||||
// Returns the clockid of the session timestamp, e.g. CLOCK_MONOTONIC.
|
||||
// Returns 0xFFFFFFFF if the session timestamp clockid is unknown.
|
||||
constexpr uint32_t
|
||||
Clockid() const noexcept
|
||||
{
|
||||
return m_clockId;
|
||||
}
|
||||
|
||||
// Returns the CLOCK_REALTIME value that corresponds to an event timestamp of 0
|
||||
// for this session. Returns 1970 if the session timestamp offset is unknown.
|
||||
PerfEventTimeSpec
|
||||
ClockOffset() const noexcept;
|
||||
|
||||
// Returns true if session clock offset is known.
|
||||
constexpr bool
|
||||
ClockOffsetKnown() const noexcept
|
||||
{
|
||||
return m_clockOffsetKnown;
|
||||
}
|
||||
|
||||
// Converts time from session timestamp to real-time (time since 1970):
|
||||
// TimeToRealTime = ClockOffset() + time.
|
||||
// If session clock offset is unknown, assume 1970.
|
||||
PerfEventTimeSpec
|
||||
TimeToRealTime(uint64_t time) const noexcept;
|
||||
};
|
||||
}
|
||||
// namespace tracepoint_decode
|
||||
|
||||
#endif // _included_PerfEventSessionInfo_h
|
6
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/samples/CMakeLists.txt
vendored
Normal file
6
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/samples/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
add_executable(perf-file-rewrite
|
||||
perf-file-rewrite.cpp)
|
||||
target_link_libraries(perf-file-rewrite
|
||||
tracepoint-decode)
|
||||
target_compile_features(perf-file-rewrite
|
||||
PRIVATE cxx_std_17)
|
347
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/samples/perf-file-rewrite.cpp
vendored
Normal file
347
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/samples/perf-file-rewrite.cpp
vendored
Normal file
|
@ -0,0 +1,347 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
Sample tool that demonstrates reading a perf.data file with PerfDataFile and
|
||||
writing a perf.data file with PerfDataFileWriter.
|
||||
|
||||
This is not intended to be useful (except perhaps for testing purposes). It is
|
||||
intended to show how PerfDataFile can be used to take the perf.data file
|
||||
apart and how PerfDataFileWriter can put it back together.
|
||||
|
||||
Note that the output file is not expected to be exactly the same as the input:
|
||||
|
||||
- Output is always a normal-mode file even if input was a pipe-mode file.
|
||||
- Output file may store headers in a different order.
|
||||
- Output file may use more/less padding.
|
||||
- If the input file is semantically inconsistent, the output file may not
|
||||
precisely match the input (the inconsistent data might be lost). For
|
||||
example, there are usually two (or more) copies of each attr, one in a
|
||||
v1 format and another in a v2 format. The rewrite process will typically
|
||||
ignore the v1 copy of the data if a v2 copy is available, so if the v1 copy
|
||||
is semantically different from the v2 copy, that detail might be lost during
|
||||
rewrite.
|
||||
*/
|
||||
|
||||
#include <tracepoint/PerfDataFile.h>
|
||||
#include <tracepoint/PerfDataFileWriter.h>
|
||||
#include <tracepoint/PerfEventAbi.h>
|
||||
#include <tracepoint/PerfEventInfo.h>
|
||||
#include <tracepoint/PerfEventMetadata.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define strerror_r(errnum, buf, buflen) (strerror_s(buf, buflen, errnum), buf)
|
||||
#define UNLINK(filename) _unlink(filename)
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#define UNLINK(filename) unlink(filename)
|
||||
#endif // _WIN32
|
||||
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
static void
|
||||
WriteErrorMessage(char const* filename, int error, char const* context)
|
||||
{
|
||||
if (error == ENOMEM)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
char errorBuf[80];
|
||||
fprintf(stderr, "%s: error %u : %s (%s).\n",
|
||||
filename,
|
||||
error,
|
||||
context,
|
||||
strerror_r(error, errorBuf, sizeof(errorBuf)));
|
||||
}
|
||||
|
||||
static void
|
||||
WriteWarningMessage(char const* filename, int error, char const* context)
|
||||
{
|
||||
if (error == ENOMEM)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
char errorBuf[80];
|
||||
fprintf(stderr, "%s: warning %u : %s (%s).\n",
|
||||
filename,
|
||||
error,
|
||||
context,
|
||||
strerror_r(error, errorBuf, sizeof(errorBuf)));
|
||||
}
|
||||
|
||||
static void
|
||||
MergeEventDesc(
|
||||
PerfDataFileWriter& output,
|
||||
char const* outputPath,
|
||||
std::unordered_set<uint64_t>& sampleIdsUsed,
|
||||
std::vector<uint64_t>& sampleIdsBuffer,
|
||||
PerfEventDesc const& desc)
|
||||
{
|
||||
sampleIdsBuffer.clear();
|
||||
for (uint32_t iId = 0; iId != desc.ids_count; iId += 1)
|
||||
{
|
||||
auto const id = desc.ids[iId];
|
||||
if (sampleIdsUsed.insert(desc.ids[iId]).second)
|
||||
{
|
||||
sampleIdsBuffer.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sampleIdsBuffer.empty())
|
||||
{
|
||||
PerfEventDesc newDesc = desc;
|
||||
newDesc.ids = sampleIdsBuffer.data();
|
||||
newDesc.ids_count = static_cast<uint32_t>(sampleIdsBuffer.size());
|
||||
auto err = output.AddEventDesc(newDesc);
|
||||
if (err != 0)
|
||||
{
|
||||
WriteWarningMessage(outputPath, err, "output.AddEventDesc failed, metadata incomplete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
bool mainSuccessful = false;
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [perf.data] ... (will generate *.rewrite)\n",
|
||||
argv[0]);
|
||||
}
|
||||
else try
|
||||
{
|
||||
PerfDataFile input;
|
||||
PerfDataFileWriter output;
|
||||
std::string outputPathBuffer;
|
||||
std::vector<uint64_t> sampleIdsBuffer;
|
||||
std::unordered_set<uint64_t> sampleIdsUsed;
|
||||
|
||||
for (int argi = 1; argi < argc; argi += 1)
|
||||
{
|
||||
int err;
|
||||
auto const inputPath = argv[argi];
|
||||
outputPathBuffer = inputPath;
|
||||
outputPathBuffer += ".rewrite";
|
||||
auto const outputPath = outputPathBuffer.c_str();
|
||||
|
||||
// CodeQL [SM01937] This is a sample/tool. Using externally-supplied path is intended behavior.
|
||||
err = input.Open(inputPath);
|
||||
if (err != 0)
|
||||
{
|
||||
WriteErrorMessage(inputPath, err, "input.Open failed, skipping file");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (input.ByteReader().ByteSwapNeeded())
|
||||
{
|
||||
// PerfDataFileWriter only supports creating host-endian files, so we can't
|
||||
// easily rewrite a byte-swapped input file.
|
||||
err = ENOTSUP;
|
||||
WriteErrorMessage(inputPath, err, "input is byte-swapped, skipping file");
|
||||
continue;
|
||||
}
|
||||
|
||||
// CodeQL [SM01937] This is a sample/tool. Using externally-supplied path is intended behavior.
|
||||
err = output.Create(outputPath);
|
||||
if (err != 0)
|
||||
{
|
||||
WriteErrorMessage(outputPath, err, "output.Create failed, skipping file");
|
||||
continue;
|
||||
}
|
||||
|
||||
sampleIdsUsed.clear();
|
||||
for (;;)
|
||||
{
|
||||
perf_event_header const* pHeader;
|
||||
err = input.ReadEvent(&pHeader);
|
||||
if (!pHeader)
|
||||
{
|
||||
if (err != 0)
|
||||
{
|
||||
WriteWarningMessage(inputPath, err, "input.Read failed, ignoring rest of input");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t eventDataSize;
|
||||
switch (pHeader->type)
|
||||
{
|
||||
default:
|
||||
eventDataSize = pHeader->size;
|
||||
break;
|
||||
|
||||
case PERF_RECORD_AUXTRACE:
|
||||
// Special-case. Event content size != pHeader->size.
|
||||
eventDataSize = input.EventDataSize(pHeader);
|
||||
break;
|
||||
|
||||
case PERF_RECORD_HEADER_ATTR:
|
||||
// Pseudo-event, conflicts with AddEventDesc.
|
||||
// PerfDataFile automatically merges data from this event into its own
|
||||
// EventDesc table. We'll use AddEventDesc to generate the output file's
|
||||
// attr headers based on the merged EventDesc table.
|
||||
continue;
|
||||
|
||||
case PERF_RECORD_HEADER_EVENT_TYPE:
|
||||
// Pseudo-event, conflicts with AddEventDesc.
|
||||
// PerfDataFile could automatically merge data from this event into its
|
||||
// own EventDesc table, but that is not implemented because this event
|
||||
// type is deprecated. Instead, we'll just ignore this event type.
|
||||
continue;
|
||||
|
||||
case PERF_RECORD_HEADER_TRACING_DATA:
|
||||
// Pseudo-event, conflicts with SetTracingData.
|
||||
// PerfDataFile automatically merges data from this event into its own
|
||||
// metadata table. We'll use SetTracingData to generate the output file's
|
||||
// metadata based on the metadata referenced by the input file's events.
|
||||
continue;
|
||||
|
||||
case PERF_RECORD_HEADER_BUILD_ID:
|
||||
case PERF_RECORD_HEADER_FEATURE:
|
||||
// Pseudo-events, conflict with SetHeader.
|
||||
// PerfDataFile automatically merges data from these events into its own
|
||||
// header table. We'll use SetHeader to generate the output file's headers
|
||||
// based on the merged header table.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pHeader->type == PERF_RECORD_SAMPLE)
|
||||
{
|
||||
// Populate the output file's metadata from the event's metadata.
|
||||
PerfSampleEventInfo info;
|
||||
err = input.GetSampleEventInfo(pHeader, &info);
|
||||
if (err != 0)
|
||||
{
|
||||
WriteWarningMessage(inputPath, err, "input.GetSampleEventInfo failed, metadata may be incomplete");
|
||||
}
|
||||
else if (info.event_desc->metadata)
|
||||
{
|
||||
auto const& desc = *info.event_desc;
|
||||
err = output.AddTracepointEventDesc(desc);
|
||||
if (err == 0)
|
||||
{
|
||||
// We don't need to AddEventDesc for the IDs covered by this event_desc.
|
||||
for (auto i = 0u; i != desc.ids_count; i += 1)
|
||||
{
|
||||
sampleIdsUsed.insert(desc.ids[i]);
|
||||
}
|
||||
}
|
||||
else if (err == EEXIST)
|
||||
{
|
||||
// Already added metadata for this event.
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteWarningMessage(outputPath, err, "output.AddTracepointEventDesc failed, metadata may be incomplete");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = output.WriteEventData(pHeader, eventDataSize);
|
||||
if (err != 0)
|
||||
{
|
||||
WriteErrorMessage(outputPath, err, "output.Write failed");
|
||||
goto CloseAndUnlinkOutput;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the output file's EventDesc table from the input file's table.
|
||||
// Some of this was already done by AddTracepointEventDesc.
|
||||
// In addition, the input file's table usually has duplicate entries - one entry with
|
||||
// names and one entry without names. Therefore, MergeEventDesc will skip ids that are
|
||||
// already populated, and we merge all descriptors with names before merging any
|
||||
// descriptors that don't have names.
|
||||
for (size_t iDesc = 0; iDesc != input.EventDescCount(); iDesc += 1)
|
||||
{
|
||||
// First, merge data from descriptors that have names.
|
||||
auto const& desc = input.EventDesc(iDesc);
|
||||
if (desc.name[0] != '\0')
|
||||
{
|
||||
MergeEventDesc(output, outputPath, sampleIdsUsed, sampleIdsBuffer, desc);
|
||||
}
|
||||
}
|
||||
for (size_t iDesc = 0; iDesc != input.EventDescCount(); iDesc += 1)
|
||||
{
|
||||
// Second, fill gaps (if any) using descriptors that don't have names.
|
||||
auto const& desc = input.EventDesc(iDesc);
|
||||
if (desc.name[0] == '\0')
|
||||
{
|
||||
MergeEventDesc(output, outputPath, sampleIdsUsed, sampleIdsBuffer, desc);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the output file's headers.
|
||||
for (auto i = PERF_HEADER_FIRST_FEATURE; i != PERF_HEADER_LAST_FEATURE; i = static_cast<PerfHeaderIndex>(i + 1))
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case PERF_HEADER_TRACING_DATA:
|
||||
case PERF_HEADER_EVENT_DESC:
|
||||
// Let the output file auto-populate these based on AddEventDesc and AddTracingData.
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto header = input.Header(i);
|
||||
if (!header.empty())
|
||||
{
|
||||
// Copy the input file's merged header into the output file.
|
||||
err = output.SetHeader(i, header.data(), static_cast<unsigned>(header.size()));
|
||||
if (err != 0)
|
||||
{
|
||||
WriteErrorMessage(outputPath, err, "output.SetHeader failed, closing");
|
||||
goto CloseAndUnlinkOutput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = output.SetTracingData(
|
||||
input.TracingDataLongSize(),
|
||||
input.TracingDataPageSize(),
|
||||
input.TracingDataHeaderPage(),
|
||||
input.TracingDataHeaderEvent(),
|
||||
input.TracingDataFtraces(),
|
||||
input.TracingDataFtraceCount(),
|
||||
input.TracingDataKallsyms(),
|
||||
input.TracingDataPrintk(),
|
||||
input.TracingDataSavedCmdLine());
|
||||
if (err != 0)
|
||||
{
|
||||
WriteErrorMessage(outputPath, err, "output.SetTracingData failed");
|
||||
goto CloseAndUnlinkOutput;
|
||||
}
|
||||
|
||||
err = output.FinalizeAndClose();
|
||||
if (err != 0)
|
||||
{
|
||||
WriteErrorMessage(outputPath, err, "output.FinalizeAndClose failed");
|
||||
goto CloseAndUnlinkOutput;
|
||||
}
|
||||
|
||||
fprintf(stdout, "\"%s\" --> \"%s\"\n", inputPath, outputPath);
|
||||
mainSuccessful = true; // One or more files completed.
|
||||
continue;
|
||||
|
||||
CloseAndUnlinkOutput:
|
||||
|
||||
output.CloseNoFinalize();
|
||||
UNLINK(outputPath);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
{
|
||||
fprintf(stderr, "\nException: %s\n", ex.what());
|
||||
mainSuccessful = false;
|
||||
}
|
||||
|
||||
return mainSuccessful ? 0 : 1;
|
||||
}
|
45
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/CMakeLists.txt
vendored
Normal file
45
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
# tracepoint-decode = libtracepoint-decode, DECODE_HEADERS
|
||||
add_library(tracepoint-decode
|
||||
PerfByteReader.cpp
|
||||
PerfDataFile.cpp
|
||||
PerfDataFileWriter.cpp
|
||||
PerfEventAbi.cpp
|
||||
PerfEventInfo.cpp
|
||||
PerfEventMetadata.cpp
|
||||
PerfEventSessionInfo.cpp)
|
||||
target_include_directories(tracepoint-decode
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/>"
|
||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
|
||||
set(DECODE_HEADERS
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfByteReader.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfDataFile.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfDataFileDefs.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfDataFileWriter.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfEventAbi.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfEventInfo.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfEventMetadata.h"
|
||||
"${PROJECT_SOURCE_DIR}/include/tracepoint/PerfEventSessionInfo.h")
|
||||
set_target_properties(tracepoint-decode PROPERTIES
|
||||
PUBLIC_HEADER "${DECODE_HEADERS}")
|
||||
target_compile_features(tracepoint-decode
|
||||
PRIVATE cxx_std_17)
|
||||
install(TARGETS tracepoint-decode
|
||||
EXPORT tracepoint-decodeTargets
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/tracepoint)
|
||||
install(EXPORT tracepoint-decodeTargets
|
||||
FILE "tracepoint-decodeTargets.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tracepoint-decode")
|
||||
configure_package_config_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tracepoint-decodeConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-decodeConfig.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tracepoint-decode"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-decodeConfigVersion.cmake"
|
||||
COMPATIBILITY SameMinorVersion)
|
||||
install(FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-decodeConfig.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/tracepoint-decodeConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tracepoint-decode")
|
121
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfByteReader.cpp
vendored
Normal file
121
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfByteReader.cpp
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/PerfByteReader.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <stdlib.h>
|
||||
#define bswap_16(n) _byteswap_ushort(n)
|
||||
#define bswap_32(n) _byteswap_ulong(n)
|
||||
#define bswap_64(n) _byteswap_uint64(n)
|
||||
static bool constexpr HostIsBigEndian = false;
|
||||
#else // _WIN32
|
||||
#include <byteswap.h>
|
||||
#include <endian.h>
|
||||
static bool constexpr HostIsBigEndian = __BYTE_ORDER == __BIG_ENDIAN;
|
||||
#endif // _WIN32
|
||||
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
PerfByteReader::PerfByteReader() noexcept
|
||||
: m_bigEndian(HostIsBigEndian) {}
|
||||
|
||||
PerfByteReader::PerfByteReader(bool bigEndian) noexcept
|
||||
: m_bigEndian(bigEndian) {}
|
||||
|
||||
bool
|
||||
PerfByteReader::BigEndian() const noexcept
|
||||
{
|
||||
return m_bigEndian;
|
||||
}
|
||||
|
||||
bool
|
||||
PerfByteReader::ByteSwapNeeded() const noexcept
|
||||
{
|
||||
return HostIsBigEndian != m_bigEndian;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
PerfByteReader::ReadAsU8(_In_reads_bytes_(1) void const* pSrc) const noexcept
|
||||
{
|
||||
return *static_cast<uint8_t const*>(pSrc);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
PerfByteReader::ReadAsU16(_In_reads_bytes_(2) void const* pSrc) const noexcept
|
||||
{
|
||||
uint16_t fileBits;
|
||||
memcpy(&fileBits, pSrc, sizeof(fileBits));
|
||||
return HostIsBigEndian == m_bigEndian ? fileBits : bswap_16(fileBits);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PerfByteReader::ReadAsU32(_In_reads_bytes_(4) void const* pSrc) const noexcept
|
||||
{
|
||||
uint32_t fileBits;
|
||||
memcpy(&fileBits, pSrc, sizeof(fileBits));
|
||||
return HostIsBigEndian == m_bigEndian ? fileBits : bswap_32(fileBits);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
PerfByteReader::ReadAsU64(_In_reads_bytes_(8) void const* pSrc) const noexcept
|
||||
{
|
||||
uint64_t fileBits;
|
||||
memcpy(&fileBits, pSrc, sizeof(fileBits));
|
||||
return HostIsBigEndian == m_bigEndian ? fileBits : bswap_64(fileBits);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
PerfByteReader::ReadAsDynU32(
|
||||
_In_reads_bytes_(cbSrc) void const* pSrc,
|
||||
uint8_t cbSrc) const noexcept
|
||||
{
|
||||
uint32_t result;
|
||||
switch (cbSrc)
|
||||
{
|
||||
default:
|
||||
assert(false);
|
||||
result = 0;
|
||||
break;
|
||||
case 1:
|
||||
result = *static_cast<uint8_t const*>(pSrc);
|
||||
break;
|
||||
case 2:
|
||||
result = ReadAsU16(pSrc);
|
||||
break;
|
||||
case 4:
|
||||
result = ReadAsU32(pSrc);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
PerfByteReader::ReadAsDynU64(
|
||||
_In_reads_bytes_(cbSrc) void const* pSrc,
|
||||
uint8_t cbSrc) const noexcept
|
||||
{
|
||||
uint64_t result;
|
||||
switch (cbSrc)
|
||||
{
|
||||
default:
|
||||
assert(false);
|
||||
result = 0;
|
||||
break;
|
||||
case 1:
|
||||
result = *static_cast<uint8_t const*>(pSrc);
|
||||
break;
|
||||
case 2:
|
||||
result = ReadAsU16(pSrc);
|
||||
break;
|
||||
case 4:
|
||||
result = ReadAsU32(pSrc);
|
||||
break;
|
||||
case 8:
|
||||
result = ReadAsU64(pSrc);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
1803
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfDataFile.cpp
vendored
Normal file
1803
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfDataFile.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
1013
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfDataFileWriter.cpp
vendored
Normal file
1013
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfDataFileWriter.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
184
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfEventAbi.cpp
vendored
Normal file
184
src/native/external/LinuxTracepoints/libtracepoint-decode-cpp/src/PerfEventAbi.cpp
vendored
Normal file
|
@ -0,0 +1,184 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <tracepoint/PerfEventAbi.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define bswap_16(n) _byteswap_ushort(n)
|
||||
#define bswap_32(n) _byteswap_ulong(n)
|
||||
#define bswap_64(n) _byteswap_uint64(n)
|
||||
#else // _WIN32
|
||||
#include <byteswap.h>
|
||||
#endif // _WIN32
|
||||
|
||||
using namespace tracepoint_decode;
|
||||
|
||||
template<class T, unsigned N>
|
||||
static constexpr unsigned
|
||||
ArrayCount(T(&)[N]) noexcept
|
||||
{
|
||||
return N;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void
|
||||
Bswap(T& value) noexcept
|
||||
{
|
||||
if constexpr (sizeof(value) == sizeof(uint16_t))
|
||||
{
|
||||
value = static_cast<T>(bswap_16(value));
|
||||
}
|
||||
else if constexpr (sizeof(value) == sizeof(uint32_t))
|
||||
{
|
||||
value = static_cast<T>(bswap_32(value));
|
||||
}
|
||||
else if constexpr (sizeof(value) == sizeof(uint64_t))
|
||||
{
|
||||
value = static_cast<T>(bswap_64(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
static_assert(sizeof(T) == 0, "Bad Bswap");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
perf_event_attr::ByteSwap() noexcept
|
||||
{
|
||||
Bswap(type);
|
||||
Bswap(size);
|
||||
Bswap(config);
|
||||
Bswap(sample_period);
|
||||
Bswap(sample_type);
|
||||
Bswap(read_format);
|
||||
|
||||
// Bitfield hack: Reverse bits within each byte, don't reorder bytes.
|
||||
unsigned constexpr offsetof_bitfield = offsetof(perf_event_attr, read_format) + sizeof(read_format);
|
||||
static_assert(offsetof_bitfield + sizeof(uint64_t) == offsetof(perf_event_attr, wakeup_events));
|
||||
for (uint8_t* pb = reinterpret_cast<uint8_t*>(this) + offsetof_bitfield;
|
||||
pb != reinterpret_cast<uint8_t*>(this) + offsetof_bitfield + sizeof(uint64_t);
|
||||
pb += 1)
|
||||
{
|
||||
uint8_t b = *pb;
|
||||
b = ((b & 0xF0) >> 4) | ((b & 0x0F) << 4);
|
||||
b = ((b & 0xCC) >> 2) | ((b & 0x33) << 2);
|
||||
b = ((b & 0xAA) >> 1) | ((b & 0x55) << 1);
|
||||
*pb = b;
|
||||
}
|
||||
|
||||
Bswap(wakeup_events);
|
||||
Bswap(bp_type);
|
||||
Bswap(bp_addr);
|
||||
Bswap(bp_len);
|
||||
Bswap(branch_sample_type);
|
||||
Bswap(sample_regs_user);
|
||||
Bswap(sample_stack_user);
|
||||
Bswap(aux_watermark);
|
||||
Bswap(sample_max_stack);
|
||||
Bswap(aux_sample_size);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
perf_event_header::ByteSwap() noexcept
|
||||
{
|
||||
Bswap(type);
|
||||
Bswap(misc);
|
||||
Bswap(size);
|
||||
}
|
||||
|
||||
_Ret_z_
|
||||
static char const*
|
||||
EnumToString(
|
||||
char const* const names[],
|
||||
unsigned nameCount,
|
||||
uint32_t value,
|
||||
_Pre_cap_(11) char* scratch) noexcept
|
||||
{
|
||||
char const* str;
|
||||
if (value < nameCount)
|
||||
{
|
||||
str = names[value];
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(scratch, 11, "%u", value);
|
||||
str = scratch;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
_Ret_z_ char const* _ltpDecl
|
||||
PerfEnumToString(perf_type_id value, _Pre_cap_(11) char* scratch) noexcept
|
||||
{
|
||||
static char const* const names[] = {
|
||||
"HARDWARE",
|
||||
"SOFTWARE",
|
||||
"TRACEPOINT",
|
||||
"HW_CACHE",
|
||||
"RAW",
|
||||
"BREAKPOINT",
|
||||
};
|
||||
static_assert(ArrayCount(names) == PERF_TYPE_MAX);
|
||||
return EnumToString(names, ArrayCount(names), value, scratch);
|
||||
}
|
||||
|
||||
_Ret_z_ char const* _ltpDecl
|
||||
PerfEnumToString(perf_event_type value, _Pre_cap_(11) char* scratch) noexcept
|
||||
{
|
||||
static char const* const names[] = {
|
||||
"0",
|
||||
"MMAP",
|
||||
"LOST",
|
||||
"COMM",
|
||||
"EXIT",
|
||||
"THROTTLE",
|
||||
"UNTHROTTLE",
|
||||
"FORK",
|
||||
"READ",
|
||||
"SAMPLE",
|
||||
"MMAP2",
|
||||
"AUX",
|
||||
"ITRACE_START",
|
||||
"LOST_SAMPLES",
|
||||
"SWITCH",
|
||||
"SWITCH_CPU_WIDE",
|
||||
"NAMESPACES",
|
||||
"KSYMBOL",
|
||||
"BPF_EVENT",
|
||||
"CGROUP",
|
||||
"TEXT_POKE",
|
||||
"AUX_OUTPUT_HW_ID",
|
||||
};
|
||||
static_assert(ArrayCount(names) == PERF_RECORD_MAX);
|
||||
|
||||
static char const* const moreNames[] = {
|
||||
"HEADER_ATTR",
|
||||
"HEADER_EVENT_TYPE",
|
||||
"HEADER_TRACING_DATA",
|
||||
"HEADER_BUILD_ID",
|
||||
"FINISHED_ROUND",
|
||||
"ID_INDEX",
|
||||
"AUXTRACE_INFO",
|
||||
"AUXTRACE",
|
||||
"AUXTRACE_ERROR",
|
||||
"THREAD_MAP",
|
||||
"CPU_MAP",
|
||||
"STAT_CONFIG",
|
||||
"STAT",
|
||||
"STAT_ROUND",
|
||||
"EVENT_UPDATE",
|
||||
"TIME_CONV",
|
||||
"HEADER_FEATURE",
|
||||
"COMPRESSED",
|
||||
"FINISHED_INIT",
|
||||
};
|
||||
static_assert(ArrayCount(moreNames) == PERF_RECORD_FINISHED_INIT - PERF_RECORD_HEADER_ATTR + 1);
|
||||
|
||||
return PERF_RECORD_HEADER_ATTR <= value && value <= PERF_RECORD_FINISHED_INIT
|
||||
? moreNames[value - PERF_RECORD_HEADER_ATTR]
|
||||
: EnumToString(names, ArrayCount(names), value, scratch);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue