diff options
53 files changed, 2003 insertions, 1048 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index af69a2a206..0d42deb9c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ endif (WIN32) set(CLR_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(VM_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/vm) set(GENERATED_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/src/inc) +set(GENERATED_EVENTING_DIR ${CMAKE_CURRENT_BINARY_DIR}/eventing) set(VERSION_FILE_PATH "${CMAKE_BINARY_DIR}/version.cpp") set(CORECLR_SET_RPATH ON) @@ -28,7 +28,7 @@ set __ThisScriptDir="%~dp0" if defined VisualStudioVersion ( if not defined __VSVersion echo %__MsgPrefix%Detected Visual Studio %VisualStudioVersion% developer command ^prompt environment goto :Run -) +) echo %__MsgPrefix%Searching ^for Visual Studio 2017 or 2015 installation set _VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" @@ -294,6 +294,16 @@ if %__EnforcePgo%==1 ( ) ) +REM Determine if this is a cross-arch build + +if /i "%__BuildArch%"=="arm64" ( + set __DoCrossArchBuild=1 + ) + +if /i "%__BuildArch%"=="arm" ( + set __DoCrossArchBuild=1 + ) + :: Set the remaining variables based upon the determined build configuration set "__BinDir=%__RootBinDir%\Product\%__BuildOS%.%__BuildArch%.%__BuildType%" set "__IntermediatesDir=%__RootBinDir%\obj\%__BuildOS%.%__BuildArch%.%__BuildType%" @@ -382,6 +392,38 @@ for /f "tokens=*" %%s in ('%DotNetCli% msbuild "%OptDataProjectFilePath%" /t:Dum REM ========================================================================================= REM === +REM === Generate source files for eventing +REM === +REM ========================================================================================= + +REM Find python and set it to the variable PYTHON +echo import sys; print sys.executable | (python2.7 || python2 || py -2 || python) > %TEMP%\pythonlocation.txt 2> NUL +set /p PYTHON=<%TEMP%\pythonlocation.txt +if NOT DEFINED PYTHON ( + echo %__MsgPrefix%Error: Could not find a python 2.7 installation + exit /b 1 +) + +if /i "%__DoCrossArchBuild%"=="1" ( + set __IntermediatesIncDir=%__CrossCompIntermediatesDir%\src\inc + set __IntermediatesEventingDir=%__CrossCompIntermediatesDir%\eventing +) else ( + set __IntermediatesIncDir=%__IntermediatesDir%\src\inc + set __IntermediatesEventingDir=%__IntermediatesDir%\eventing +) + +echo Laying out dynamically generated files consumed by the build system +echo Laying out dynamically generated Event test files and etmdummy stub functions +%PYTHON% -B -Wall %__SourceDir%\scripts\genEventing.py --inc %__IntermediatesIncDir% --dummy %__IntermediatesIncDir%\etmdummy.h --man %__SourceDir%\vm\ClrEtwAll.man --nonextern || exit /b 1 + +echo Laying out dynamically generated EventPipe Implementation +%PYTHON% -B -Wall %__SourceDir%\scripts\genEventPipe.py --man %__SourceDir%\vm\ClrEtwAll.man --intermediate %__IntermediatesEventingDir%\eventpipe --nonextern || exit /b 1 + +echo Laying out ETW event logging interface +%PYTHON% -B -Wall %__SourceDir%\scripts\genEtwProvider.py --man %__SourceDir%\vm\ClrEtwAll.man --intermediate %__IntermediatesIncDir% --exc %__SourceDir%\vm\ClrEtwAllMeta.lst || exit /b 1 + +REM ========================================================================================= +REM === REM === Build the CLR VM REM === REM ========================================================================================= @@ -476,14 +518,6 @@ REM === Build Cross-Architecture Native Components (if applicable) REM === REM ========================================================================================= -if /i "%__BuildArch%"=="arm64" ( - set __DoCrossArchBuild=1 - ) - -if /i "%__BuildArch%"=="arm" ( - set __DoCrossArchBuild=1 - ) - if /i "%__DoCrossArchBuild%"=="1" ( REM Scope environment changes start { setlocal @@ -194,28 +194,9 @@ generate_event_logging_sources() fi # Event Logging Infrastructure - __GeneratedIntermediate="$__IntermediatesDir/Generated" - __GeneratedIntermediateEventProvider="$__GeneratedIntermediate/eventprovider_new" - __GeneratedIntermediateEventPipe="$__GeneratedIntermediate/eventpipe_new" - - if [[ -d "$__GeneratedIntermediateEventProvider" ]]; then - rm -rf "$__GeneratedIntermediateEventProvider" - fi - - if [[ -d "$__GeneratedIntermediateEventPipe" ]]; then - rm -rf "$__GeneratedIntermediateEventPipe" - fi - - if [[ ! -d "$__GeneratedIntermediate/eventprovider" ]]; then - mkdir -p "$__GeneratedIntermediate/eventprovider" - fi - - if [[ ! -d "$__GeneratedIntermediate/eventpipe" ]]; then - mkdir -p "$__GeneratedIntermediate/eventpipe" - fi - - mkdir -p "$__GeneratedIntermediateEventProvider" - mkdir -p "$__GeneratedIntermediateEventPipe" + __GeneratedIntermediate="$__IntermediatesDir/eventing" + __GeneratedIntermediateEventProvider="$__GeneratedIntermediate/eventprovider" + __GeneratedIntermediateEventPipe="$__GeneratedIntermediate/eventpipe" __PythonWarningFlags="-Wall" if [[ $__IgnoreWarnings == 0 ]]; then @@ -225,54 +206,38 @@ generate_event_logging_sources() if [[ $__SkipCoreCLR == 0 || $__ConfigureOnly == 1 ]]; then echo "Laying out dynamically generated files consumed by the build system " - echo "Laying out dynamically generated Event Logging Test files" - $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genXplatEventing.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --exc "$__ProjectRoot/src/vm/ClrEtwAllMeta.lst" --testdir "$__GeneratedIntermediateEventProvider/tests" + echo "Laying out dynamically generated Event test files, etmdummy stub functions, and external linkages" + $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genEventing.py" --inc $__IntermediatesDir/src/inc --dummy $__IntermediatesDir/src/inc/etmdummy.h --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --testdir "$__GeneratedIntermediateEventProvider/tests" if [[ $? != 0 ]]; then exit fi - case $__BuildOS in - Linux|FreeBSD) - echo "Laying out dynamically generated EventPipe Implementation" - $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genEventPipe.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__GeneratedIntermediateEventPipe" --exc "$__ProjectRoot/src/vm/ClrEtwAllMeta.lst" - if [[ $? != 0 ]]; then - exit - fi - ;; - *) - ;; - esac + echo "Laying out dynamically generated EventPipe Implementation" + $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genEventPipe.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__GeneratedIntermediateEventPipe" #determine the logging system case $__BuildOS in Linux|FreeBSD) echo "Laying out dynamically generated Event Logging Implementation of Lttng" - $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genXplatLttng.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__GeneratedIntermediateEventProvider" + $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genLttngProvider.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__GeneratedIntermediateEventProvider" if [[ $? != 0 ]]; then exit fi ;; *) + echo "Laying out dummy event logging provider" + $PYTHON -B $__PythonWarningFlags "$__ProjectRoot/src/scripts/genDummyProvider.py" --man "$__ProjectRoot/src/vm/ClrEtwAll.man" --intermediate "$__GeneratedIntermediateEventProvider" + if [[ $? != 0 ]]; then + exit + fi ;; esac - fi - - echo "Cleaning the temp folder of dynamically generated Event Logging files" - $PYTHON -B $__PythonWarningFlags -c "import sys;sys.path.insert(0,\"$__ProjectRoot/src/scripts\"); from Utilities import *;UpdateDirectory(\"$__GeneratedIntermediate/eventprovider\",\"$__GeneratedIntermediateEventProvider\")" - if [[ $? != 0 ]]; then - exit - fi - rm -rf "$__GeneratedIntermediateEventProvider" - - echo "Cleaning the temp folder of dynamically generated EventPipe files" - $PYTHON -B $__PythonWarningFlags -c "import sys;sys.path.insert(0,\"$__ProjectRoot/src/scripts\"); from Utilities import *;UpdateDirectory(\"$__GeneratedIntermediate/eventpipe\",\"$__GeneratedIntermediateEventPipe\")" - if [[ $? != 0 ]]; then - exit + if [[ $__CrossBuild == 1 ]]; then + cp -r $__GeneratedIntermediate $__CrossCompIntermediatesDir + fi fi - - rm -rf "$__GeneratedIntermediateEventPipe" } build_native() diff --git a/clr.coreclr.props b/clr.coreclr.props index 691365c76c..98df021084 100644 --- a/clr.coreclr.props +++ b/clr.coreclr.props @@ -3,6 +3,8 @@ <FeatureEventTrace>true</FeatureEventTrace> <FeatureICastable>true</FeatureICastable> <FeatureManagedEtwChannels>true</FeatureManagedEtwChannels> + <FeatureManagedEtw>true</FeatureManagedEtw> + <FeaturePerfTracing>true</FeaturePerfTracing> <ProfilingSupportedBuild>true</ProfilingSupportedBuild> </PropertyGroup> @@ -21,7 +23,6 @@ <PropertyGroup Condition="'$(TargetsWindows)' == 'true'"> <FeatureArrayStubAsIL Condition="'$(TargetArch)' != 'i386'">true</FeatureArrayStubAsIL> <FeatureMulticastStubAsIL Condition="'$(TargetArch)' != 'i386'">true</FeatureMulticastStubAsIL> - <FeatureManagedEtw>true</FeatureManagedEtw> <FeatureStubsAsIL Condition="'$(TargetArch)' == 'arm64'">true</FeatureStubsAsIL> <FeatureUseLcid>true</FeatureUseLcid> <FeatureCominterop>true</FeatureCominterop> @@ -32,9 +33,4 @@ <FeatureAppX>true</FeatureAppX> <FeatureWin32Registry>true</FeatureWin32Registry> </PropertyGroup> - - <PropertyGroup Condition="'$(TargetsLinux)' == 'true'"> - <FeatureManagedEtw>true</FeatureManagedEtw> - <FeaturePerfTracing>true</FeaturePerfTracing> - </PropertyGroup> -</Project> +</Project>
\ No newline at end of file diff --git a/clr.defines.targets b/clr.defines.targets index b9f159eb0c..9189f6f203 100644 --- a/clr.defines.targets +++ b/clr.defines.targets @@ -20,6 +20,7 @@ <DefineConstants Condition="'$(FeatureManagedEtwChannels)' == 'true'">$(DefineConstants);FEATURE_MANAGED_ETW_CHANNELS</DefineConstants> <DefineConstants Condition="'$(FeaturePal)' == 'true'">$(DefineConstants);FEATURE_PAL</DefineConstants> <DefineConstants Condition="'$(FeaturePerfTracing)' == 'true'">$(DefineConstants);FEATURE_PERFTRACING</DefineConstants> + <DefineConstants Condition="'$(FeatureEventTrace)' == 'true'">$(DefineConstants);FEATURE_EVENT_TRACE</DefineConstants> <DefineConstants Condition="'$(FeatureXplatEventSource)' == 'true'">$(DefineConstants);FEATURE_EVENTSOURCE_XPLAT</DefineConstants> <DefineConstants Condition="'$(FeatureUseLcid)' == 'true'">$(DefineConstants);FEATURE_USE_LCID</DefineConstants> <DefineConstants Condition="'$(FeatureWin32Registry)' == 'true'">$(DefineConstants);FEATURE_WIN32_REGISTRY</DefineConstants> diff --git a/clrdefinitions.cmake b/clrdefinitions.cmake index 5e12ca1e05..4216e8ed20 100644 --- a/clrdefinitions.cmake +++ b/clrdefinitions.cmake @@ -125,6 +125,7 @@ if(FEATURE_DBGIPC) endif(FEATURE_DBGIPC) if(FEATURE_EVENT_TRACE) add_definitions(-DFEATURE_EVENT_TRACE=1) + add_definitions(-DFEATURE_PERFTRACING=1) endif(FEATURE_EVENT_TRACE) if(FEATURE_GDBJIT) add_definitions(-DFEATURE_GDBJIT) @@ -138,9 +139,6 @@ endif(FEATURE_GDBJIT_LANGID_CS) if(FEATURE_GDBJIT_SYMTAB) add_definitions(-DFEATURE_GDBJIT_SYMTAB) endif(FEATURE_GDBJIT_SYMTAB) -if(CLR_CMAKE_PLATFORM_LINUX) - add_definitions(-DFEATURE_PERFTRACING) -endif(CLR_CMAKE_PLATFORM_LINUX) if(CLR_CMAKE_PLATFORM_UNIX) add_definitions(-DFEATURE_EVENTSOURCE_XPLAT=1) endif(CLR_CMAKE_PLATFORM_UNIX) diff --git a/clrfeatures.cmake b/clrfeatures.cmake index b4d7bad2dd..367777a501 100644 --- a/clrfeatures.cmake +++ b/clrfeatures.cmake @@ -3,23 +3,13 @@ if(CLR_CMAKE_TARGET_TIZEN_LINUX) endif() if(NOT DEFINED FEATURE_EVENT_TRACE) - if (WIN32) - set(FEATURE_EVENT_TRACE 1) - endif() - - if(CLR_CMAKE_PLATFORM_LINUX) - if(CLR_CMAKE_TARGET_TIZEN_LINUX) - set(FEATURE_EVENT_TRACE 1) - elseif(CLR_CMAKE_TARGET_ARCH_AMD64) - set(FEATURE_EVENT_TRACE 1) - elseif(CLR_CMAKE_TARGET_ARCH_ARM) - set(FEATURE_EVENT_TRACE 1) - elseif(CLR_CMAKE_TARGET_ARCH_ARM64) - set(FEATURE_EVENT_TRACE 1) - endif() - endif(CLR_CMAKE_PLATFORM_LINUX) + set(FEATURE_EVENT_TRACE 1) endif(NOT DEFINED FEATURE_EVENT_TRACE) +if(NOT DEFINED FEATURE_PERFTRACING AND FEATURE_EVENT_TRACE) + set(FEATURE_PERFTRACING 1) +endif(NOT DEFINED FEATURE_PERFTRACING AND FEATURE_EVENT_TRACE) + if(NOT DEFINED FEATURE_DBGIPC) if(CLR_CMAKE_PLATFORM_UNIX AND (NOT CLR_CMAKE_PLATFORM_ANDROID)) set(FEATURE_DBGIPC 1) diff --git a/dependencies.props b/dependencies.props index 3957180f5d..7ea5352e31 100644 --- a/dependencies.props +++ b/dependencies.props @@ -38,7 +38,7 @@ <XunitPackageVersion>2.2.0-beta2-build3300</XunitPackageVersion> <XunitConsoleNetcorePackageVersion>1.0.2-prerelease-00177</XunitConsoleNetcorePackageVersion> <XunitPerformanceApiPackageVersion>1.0.0-beta-build0012</XunitPerformanceApiPackageVersion> - <MicrosoftDiagnosticsTracingTraceEventPackageVersion>1.0.3-alpha-experimental</MicrosoftDiagnosticsTracingTraceEventPackageVersion> + <MicrosoftDiagnosticsTracingTraceEventPackageVersion>2.0.2</MicrosoftDiagnosticsTracingTraceEventPackageVersion> <VCRuntimeVersion>1.2.0</VCRuntimeVersion> </PropertyGroup> diff --git a/functions.cmake b/functions.cmake index 15d0cd929c..c2286839dd 100644 --- a/functions.cmake +++ b/functions.cmake @@ -44,11 +44,11 @@ endfunction(get_include_directories) # Build a list of include directories for consumption by the assembler function(get_include_directories_asm IncludeDirectories) get_directory_property(dirs INCLUDE_DIRECTORIES) - + if (CLR_CMAKE_PLATFORM_ARCH_ARM AND WIN32) list(APPEND INC_DIRECTORIES "-I ") endif() - + foreach(dir IN LISTS dirs) if (CLR_CMAKE_PLATFORM_ARCH_ARM AND WIN32) list(APPEND INC_DIRECTORIES ${dir};) @@ -141,7 +141,7 @@ function(strip_symbols targetName outputFilename) add_custom_command( TARGET ${targetName} POST_BUILD - VERBATIM + VERBATIM COMMAND ${DSYMUTIL} --flat --minimize ${strip_source_file} COMMAND ${STRIP} -S ${strip_source_file} COMMENT Stripping symbols from ${strip_source_file} into file ${strip_destination_file} @@ -152,7 +152,7 @@ function(strip_symbols targetName outputFilename) add_custom_command( TARGET ${targetName} POST_BUILD - VERBATIM + VERBATIM COMMAND ${OBJCOPY} --only-keep-debug ${strip_source_file} ${strip_destination_file} COMMAND ${OBJCOPY} --strip-debug ${strip_source_file} COMMAND ${OBJCOPY} --add-gnu-debuglink=${strip_destination_file} ${strip_source_file} @@ -166,30 +166,30 @@ function(strip_symbols targetName outputFilename) endfunction() function(install_clr targetName) - list(FIND CLR_CROSS_COMPONENTS_LIST ${targetName} INDEX) - if (NOT DEFINED CLR_CROSS_COMPONENTS_LIST OR NOT ${INDEX} EQUAL -1) - strip_symbols(${targetName} strip_destination_file) - # On the older version of cmake (2.8.12) used on Ubuntu 14.04 the TARGET_FILE - # generator expression doesn't work correctly returning the wrong path and on - # the newer cmake versions the LOCATION property isn't supported anymore. - if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0) - set(install_source_file $<TARGET_FILE:${targetName}>) - else() - get_property(install_source_file TARGET ${targetName} PROPERTY LOCATION) - endif() - - install(PROGRAMS ${install_source_file} DESTINATION .) - if(WIN32) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${targetName}.pdb DESTINATION PDB) - else() - install(FILES ${strip_destination_file} DESTINATION .) - endif() + list(FIND CLR_CROSS_COMPONENTS_LIST ${targetName} INDEX) + if (NOT DEFINED CLR_CROSS_COMPONENTS_LIST OR NOT ${INDEX} EQUAL -1) + strip_symbols(${targetName} strip_destination_file) + # On the older version of cmake (2.8.12) used on Ubuntu 14.04 the TARGET_FILE + # generator expression doesn't work correctly returning the wrong path and on + # the newer cmake versions the LOCATION property isn't supported anymore. + if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0) + set(install_source_file $<TARGET_FILE:${targetName}>) + else() + get_property(install_source_file TARGET ${targetName} PROPERTY LOCATION) + endif() + + install(PROGRAMS ${install_source_file} DESTINATION .) + if(WIN32) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${targetName}.pdb DESTINATION PDB) + else() + install(FILES ${strip_destination_file} DESTINATION .) + endif() if(CLR_CMAKE_PGO_INSTRUMENT) if(WIN32) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/${targetName}.pgd DESTINATION PGD OPTIONAL) endif() endif() - endif() + endif() endfunction() # Disable PAX mprotect that would prevent JIT and other codegen in coreclr from working. @@ -217,11 +217,11 @@ function(_add_executable) else() add_executable(${ARGV}) endif(NOT WIN32) - list(FIND CLR_CROSS_COMPONENTS_LIST ${ARGV0} INDEX) - if (DEFINED CLR_CROSS_COMPONENTS_LIST AND ${INDEX} EQUAL -1) - set_target_properties(${ARGV0} PROPERTIES EXCLUDE_FROM_ALL 1) + list(FIND CLR_CROSS_COMPONENTS_LIST ${ARGV0} INDEX) + if (DEFINED CLR_CROSS_COMPONENTS_LIST AND ${INDEX} EQUAL -1) + set_target_properties(${ARGV0} PROPERTIES EXCLUDE_FROM_ALL 1) endif() -endfunction() +endfunction() function(_add_library) if(NOT WIN32) @@ -229,10 +229,10 @@ function(_add_library) else() add_library(${ARGV}) endif(NOT WIN32) - list(FIND CLR_CROSS_COMPONENTS_LIST ${ARGV0} INDEX) - if (DEFINED CLR_CROSS_COMPONENTS_LIST AND ${INDEX} EQUAL -1) - set_target_properties(${ARGV0} PROPERTIES EXCLUDE_FROM_ALL 1) - endif() + list(FIND CLR_CROSS_COMPONENTS_LIST ${ARGV0} INDEX) + if (DEFINED CLR_CROSS_COMPONENTS_LIST AND ${INDEX} EQUAL -1) + set_target_properties(${ARGV0} PROPERTIES EXCLUDE_FROM_ALL 1) + endif() endfunction() function(_install) @@ -263,8 +263,8 @@ function(verify_dependencies targetName errorMessage) TARGET ${targetName} POST_BUILD VERBATIM - COMMAND ${CMAKE_SOURCE_DIR}/verify-so.sh - $<TARGET_FILE:${targetName}> + COMMAND ${CMAKE_SOURCE_DIR}/verify-so.sh + $<TARGET_FILE:${targetName}> ${errorMessage} COMMENT "Verifying ${targetName} dependencies" ) @@ -273,10 +273,8 @@ endfunction() function(add_library_clr) _add_library(${ARGV}) - add_dependencies(${ARGV0} GeneratedEventingFiles) endfunction() function(add_executable_clr) _add_executable(${ARGV}) - add_dependencies(${ARGV0} GeneratedEventingFiles) endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c999b184d..0412226dfc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,70 +10,10 @@ include_directories("classlibnative/cryptography") include_directories("classlibnative/inc") include_directories("${GENERATED_INCLUDE_DIR}") -# The Following Logic is used to wire up Build dependencies for Generated files in Event Logging -# ClrEtwAll.man - Event Schema -# ClrEtwAllMeta.lst - MetaData list [provided to ensure Windows Desktop is not broken] -# genXplatEventing.py - has the core logic for parsing Event Schema -# genWinEtw.py - Uses genXplatEventing to generate Windows Specific ETW Files -# clretwallmain.h and etmdummy.h - Provides the Event Logging Functionality to the VM -# clrxplatevents.h - Used by clretwallmain.h on Non Windows platform -# ClrEtwAll.h - Used by clretwallmain.h on Windows -# ClrEtwAll.rc - Used by src/dlls/clretwrc/clretrw.rc on Windows - -set (ScriptGeneratedEventFiles - ${GENERATED_INCLUDE_DIR}/clretwallmain.h - ${GENERATED_INCLUDE_DIR}/etmdummy.h -) -set (GeneratedEventFiles) +if(WIN32 AND FEATURE_EVENT_TRACE) + include_directories("${GENERATED_INCLUDE_DIR}/etw") +endif(WIN32 AND FEATURE_EVENT_TRACE) -if(WIN32) - set (GenEventFilesScript "${CLR_DIR}/src/scripts/genWinEtw.py") - set (GenEventArgs --eventheader "${GENERATED_INCLUDE_DIR}/ClrEtwAll.h" --macroheader "${GENERATED_INCLUDE_DIR}/clretwallmain.h") - - list (APPEND ScriptGeneratedEventFiles - ${GENERATED_INCLUDE_DIR}/ClrEtwAll.h - ) - - list (APPEND GeneratedEventFiles - ${GENERATED_INCLUDE_DIR}/ClrEtwAll.rc - ) - - add_custom_command( - COMMENT "Generating ETW resource Files" - COMMAND ${MC} -h ${GENERATED_INCLUDE_DIR} -r ${GENERATED_INCLUDE_DIR} -b -co -um -p FireEtw "${VM_DIR}/ClrEtwAll.man" - OUTPUT ${GENERATED_INCLUDE_DIR}/ClrEtwAll.h - DEPENDS "${VM_DIR}/ClrEtwAll.man" - ) -else() - set (GenEventFilesScript "${CLR_DIR}/src/scripts/genXplatEventing.py") - set (GenEventArgs --inc "${GENERATED_INCLUDE_DIR}") - - list (APPEND ScriptGeneratedEventFiles - ${GENERATED_INCLUDE_DIR}/clrxplatevents.h - ) -endif(WIN32) - -if(CLR_CMAKE_WARNINGS_ARE_ERRORS) - set(PYTHON_WARNING_FLAGS -Wall -Werror) -else() - set(PYTHON_WARNING_FLAGS -Wall) -endif(CLR_CMAKE_WARNINGS_ARE_ERRORS) - -add_custom_command( - COMMENT "Generating Eventing Files" - COMMAND ${PYTHON} -B ${PYTHON_WARNING_FLAGS} ${GenEventFilesScript} ${GenEventArgs} --man "${VM_DIR}/ClrEtwAll.man" --exc "${VM_DIR}/ClrEtwAllMeta.lst" --dummy "${GENERATED_INCLUDE_DIR}/etmdummy.h" - OUTPUT ${ScriptGeneratedEventFiles} - DEPENDS ${GenEventFilesScript} "${VM_DIR}/ClrEtwAll.man" "${VM_DIR}/ClrEtwAllMeta.lst" "${CLR_DIR}/src/scripts/genXplatEventing.py" -) - -list (APPEND GeneratedEventFiles - ${ScriptGeneratedEventFiles} -) - -add_custom_target( - GeneratedEventingFiles - DEPENDS ${GeneratedEventFiles} -) if(CLR_CMAKE_PLATFORM_UNIX) if(CLR_CMAKE_PLATFORM_LINUX) diff --git a/src/dlls/mscoree/coreclr/CMakeLists.txt b/src/dlls/mscoree/coreclr/CMakeLists.txt index 8796cc16a5..8043f7733a 100644 --- a/src/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/dlls/mscoree/coreclr/CMakeLists.txt @@ -4,8 +4,8 @@ if (WIN32) list(APPEND CLR_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/coreclr.def) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /ENTRY:CoreDllMain") - - # Incremental linking results in the linker inserting extra padding and routing function calls via thunks that can break the + + # Incremental linking results in the linker inserting extra padding and routing function calls via thunks that can break the # invariants (e.g. size of region between Jit_PatchedCodeLast-Jit_PatchCodeStart needs to fit in a page). set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENTAL:NO") @@ -14,7 +14,7 @@ if (WIN32) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DELAYLOAD:api-ms-win-core-winrt-roparameterizediid-l1-1-0.dll") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DELAYLOAD:api-ms-win-ro-typeresolution-l1-1-0.dll") - + # No library groups for Win32 set(START_LIBRARY_GROUP) set(END_LIBRARY_GROUP) @@ -30,14 +30,14 @@ else() # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic -Xlinker -Bsymbolic-functions") - # The following linked options can be inserted into the linker libraries list to + # The following linked options can be inserted into the linker libraries list to # ensure proper resolving of circular references between a subset of the libraries. set(START_LIBRARY_GROUP -Wl,--start-group) set(END_LIBRARY_GROUP -Wl,--end-group) # These options are used to force every object to be included even if it's unused. set(START_WHOLE_ARCHIVE -Wl,--whole-archive) - set(END_WHOLE_ARCHIVE -Wl,--no-whole-archive) + set(END_WHOLE_ARCHIVE -Wl,--no-whole-archive) set(EXPORTS_LINKER_OPTION -Wl,--version-script=${EXPORTS_FILE}) endif(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL NetBSD) @@ -74,7 +74,7 @@ if(FEATURE_MERGE_JIT_AND_ENGINE) endif(FEATURE_MERGE_JIT_AND_ENGINE) # IMPORTANT! Please do not rearrange the order of the libraries. The linker on Linux is -# order dependent and changing the order can result in undefined symbols in the shared +# order dependent and changing the order can result in undefined symbols in the shared # library. set(CORECLR_LIBRARIES utilcode @@ -119,28 +119,34 @@ if(WIN32) ) else() list(APPEND CORECLR_LIBRARIES - ${START_WHOLE_ARCHIVE} # force all PAL objects to be included so all exports are available + ${START_WHOLE_ARCHIVE} # force all PAL objects to be included so all exports are available coreclrpal - tracepointprovider - ${END_WHOLE_ARCHIVE} + ${END_WHOLE_ARCHIVE} mscorrc_debug palrt ) endif(WIN32) -if(CLR_CMAKE_PLATFORM_UNIX AND FEATURE_EVENT_TRACE) - list(APPEND CORECLR_LIBRARIES - eventprovider - ) -endif(CLR_CMAKE_PLATFORM_UNIX AND FEATURE_EVENT_TRACE) - -if(CLR_CMAKE_PLATFORM_LINUX) +if(FEATURE_PERFTRACING) list(APPEND CORECLR_LIBRARIES eventpipe - ) -endif(CLR_CMAKE_PLATFORM_LINUX) - -target_link_libraries(coreclr ${CORECLR_LIBRARIES}) + ) +endif(FEATURE_PERFTRACING) + +if(FEATURE_EVENT_TRACE) + if(CLR_CMAKE_PLATFORM_UNIX) + list(APPEND CORECLR_LIBRARIES + eventprovider # On Windows this library contains only macros + ) + endif(CLR_CMAKE_PLATFORM_UNIX) + if(CLR_CMAKE_PLATFORM_LINUX) + list(APPEND CORECLR_LIBRARIES + tracepointprovider + ) + endif(CLR_CMAKE_PLATFORM_LINUX) +endif(FEATURE_EVENT_TRACE) + +target_link_libraries(coreclr ${CORECLR_LIBRARIES}) if(WIN32) # Add dac table & debug resource to coreclr diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj index fcb499bbcc..4c36439e85 100644 --- a/src/mscorlib/System.Private.CoreLib.csproj +++ b/src/mscorlib/System.Private.CoreLib.csproj @@ -623,7 +623,7 @@ <Target Name="CDefineChecker" BeforeTargets="Build" Condition="'$(CheckCDefines)'=='true'"> <!-- Compiler Definition Verification --> <PropertyGroup> - <CMakeDefinitionSaveFile>$(IntermediateOutputPath)\cmake.definitions</CMakeDefinitionSaveFile> + <CMakeDefinitionSaveFile>$(IntermediateOutputPath)..\cmake.definitions</CMakeDefinitionSaveFile> </PropertyGroup> <Exec Command="python $(MSBuildThisFileDirectory)..\scripts\check-definitions.py "$(CMakeDefinitionSaveFile)" "$(DefineConstants)" "$(IgnoreDefineConstants)" " /> </Target> diff --git a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs index 539c60b55f..ac15202f93 100644 --- a/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs +++ b/src/mscorlib/src/System/Diagnostics/Eventing/EventPipe.cs @@ -15,12 +15,12 @@ namespace System.Diagnostics.Tracing [MarshalAs(UnmanagedType.LPWStr)] private string m_providerName; private UInt64 m_keywords; - private uint m_loggingLevel; + private UInt32 m_loggingLevel; internal EventPipeProviderConfiguration( string providerName, UInt64 keywords, - uint loggingLevel) + UInt32 loggingLevel) { if(string.IsNullOrEmpty(providerName)) { @@ -45,7 +45,7 @@ namespace System.Diagnostics.Tracing get { return m_keywords; } } - internal uint LoggingLevel + internal UInt32 LoggingLevel { get { return m_loggingLevel; } } @@ -54,13 +54,13 @@ namespace System.Diagnostics.Tracing internal sealed class EventPipeConfiguration { private string m_outputFile; - private uint m_circularBufferSizeInMB; + private UInt32 m_circularBufferSizeInMB; private List<EventPipeProviderConfiguration> m_providers; private TimeSpan m_minTimeBetweenSamples = TimeSpan.FromMilliseconds(1); internal EventPipeConfiguration( string outputFile, - uint circularBufferSizeInMB) + UInt32 circularBufferSizeInMB) { if(string.IsNullOrEmpty(outputFile)) { @@ -80,7 +80,7 @@ namespace System.Diagnostics.Tracing get { return m_outputFile; } } - internal uint CircularBufferSizeInMB + internal UInt32 CircularBufferSizeInMB { get { return m_circularBufferSizeInMB; } } @@ -90,13 +90,13 @@ namespace System.Diagnostics.Tracing get { return m_providers.ToArray(); } } - internal long ProfilerSamplingRateInNanoseconds + internal Int64 ProfilerSamplingRateInNanoseconds { // 100 nanoseconds == 1 tick. get { return m_minTimeBetweenSamples.Ticks * 100; } } - internal void EnableProvider(string providerName, UInt64 keywords, uint loggingLevel) + internal void EnableProvider(string providerName, UInt64 keywords, UInt32 loggingLevel) { m_providers.Add(new EventPipeProviderConfiguration( providerName, @@ -124,6 +124,11 @@ namespace System.Diagnostics.Tracing throw new ArgumentNullException(nameof(configuration)); } + if(configuration.Providers == null) + { + throw new ArgumentNullException(nameof(configuration.Providers)); + } + EventPipeProviderConfiguration[] providers = configuration.Providers; EventPipeInternal.Enable( @@ -146,7 +151,7 @@ namespace System.Diagnostics.Tracing // These PInvokes are used by the configuration APIs to interact with EventPipe. // [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern void Enable(string outputFile, uint circularBufferSizeInMB, long profilerSamplingRateInNanoseconds, EventPipeProviderConfiguration[] providers, int numProviders); + internal static extern void Enable(string outputFile, UInt32 circularBufferSizeInMB, Int64 profilerSamplingRateInNanoseconds, EventPipeProviderConfiguration[] providers, Int32 numProviders); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] internal static extern void Disable(); @@ -158,15 +163,15 @@ namespace System.Diagnostics.Tracing internal static extern IntPtr CreateProvider(string providerName, UnsafeNativeMethods.ManifestEtw.EtwEnableCallback callbackFunc); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, Int64 keywords, uint eventVersion, uint level, void *pMetadata, uint metadataLength); + internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, UInt32 eventID, Int64 keywords, UInt32 eventVersion, UInt32 level, void *pMetadata, UInt32 metadataLength); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] internal static extern void DeleteProvider(IntPtr provHandle); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern unsafe void WriteEvent(IntPtr eventHandle, uint eventID, void* pData, uint length, Guid* activityId, Guid* relatedActivityId); + internal static extern unsafe void WriteEvent(IntPtr eventHandle, UInt32 eventID, void* pData, UInt32 length, Guid* activityId, Guid* relatedActivityId); [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] - internal static extern unsafe void WriteEventData(IntPtr eventHandle, uint eventID, EventProvider.EventData** pEventData, uint dataCount, Guid* activityId, Guid* relatedActivityId); + internal static extern unsafe void WriteEventData(IntPtr eventHandle, UInt32 eventID, EventProvider.EventData** pEventData, UInt32 dataCount, Guid* activityId, Guid* relatedActivityId); } } diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt index 2ade61b3d6..feb434cd3e 100644 --- a/src/pal/src/CMakeLists.txt +++ b/src/pal/src/CMakeLists.txt @@ -239,10 +239,14 @@ add_library(coreclrpal ${PLATFORM_SOURCES} ) -add_library(tracepointprovider - STATIC - misc/tracepointprovider.cpp -) +# This builds in functionality to load LTTng tracepoints at runtime +# Needed when using LTTng to support event tracing on Linux +if(CLR_CMAKE_PLATFORM_LINUX) + add_library(tracepointprovider + STATIC + misc/tracepointprovider.cpp + ) +endif(CLR_CMAKE_PLATFORM_LINUX) if(CMAKE_SYSTEM_NAME STREQUAL Darwin) find_library(COREFOUNDATION CoreFoundation) @@ -376,7 +380,7 @@ endif(CMAKE_SYSTEM_NAME STREQUAL NetBSD) add_subdirectory(examples) if(FEATURE_EVENT_TRACE) - add_subdirectory($ENV{__IntermediatesDir}/Generated/eventprovider ${CMAKE_CURRENT_BINARY_DIR}/eventprovider) + add_subdirectory(${GENERATED_EVENTING_DIR}/eventprovider ${CMAKE_CURRENT_BINARY_DIR}/eventprovider) endif(FEATURE_EVENT_TRACE) # Install the static PAL library for VS diff --git a/src/pal/tests/palsuite/CMakeLists.txt b/src/pal/tests/palsuite/CMakeLists.txt index 0ea8969bab..6f36025d1a 100644 --- a/src/pal/tests/palsuite/CMakeLists.txt +++ b/src/pal/tests/palsuite/CMakeLists.txt @@ -31,4 +31,7 @@ add_subdirectory(miscellaneous) add_subdirectory(pal_specific) add_subdirectory(samples) add_subdirectory(threading) -add_subdirectory($ENV{__IntermediatesDir}/Generated/eventprovider/tests ${CMAKE_CURRENT_BINARY_DIR}/eventprovider ) + +if(FEATURE_EVENT_TRACE) + add_subdirectory(${GENERATED_EVENTING_DIR}/eventprovider/tests ${CMAKE_CURRENT_BINARY_DIR}/eventprovider) +endif(FEATURE_EVENT_TRACE) diff --git a/src/scripts/Utilities.py b/src/scripts/Utilities.py deleted file mode 100644 index c1ceec8e9f..0000000000 --- a/src/scripts/Utilities.py +++ /dev/null @@ -1,49 +0,0 @@ -from filecmp import dircmp -import shutil -import os - -def walk_recursively_and_update(dcmp): - #for different Files Copy from right to left - for name in dcmp.diff_files: - srcpath = dcmp.right + "/" + name - destpath = dcmp.left + "/" + name - print("Updating %s" % (destpath)) - if os.path.isfile(srcpath): - shutil.copyfile(srcpath, destpath) - else : - raise Exception("path: " + srcpath + "is neither a file or folder") - - #copy right only files - for name in dcmp.right_only: - srcpath = dcmp.right + "/" + name - destpath = dcmp.left + "/" + name - print("Updating %s" % (destpath)) - if os.path.isfile(srcpath): - shutil.copyfile(srcpath, destpath) - elif os.path.isdir(srcpath): - shutil.copytree(srcpath, destpath) - else : - raise Exception("path: " + srcpath + "is neither a file or folder") - - #delete left only files - for name in dcmp.left_only: - path = dcmp.left + "/" + name - print("Deleting %s" % (path)) - if os.path.isfile(path): - os.remove(path) - elif os.path.isdir(path): - shutil.rmtree(path) - else : - raise Exception("path: " + path + "is neither a file or folder") - - #call recursively - for sub_dcmp in dcmp.subdirs.values(): - walk_recursively_and_update(sub_dcmp) - -def UpdateDirectory(destpath,srcpath): - - print("Updating %s with %s" % (destpath,srcpath)) - if not os.path.exists(destpath): - os.makedirs(destpath) - dcmp = dircmp(destpath,srcpath) - walk_recursively_and_update(dcmp) diff --git a/src/scripts/check-definitions.py b/src/scripts/check-definitions.py index 59b309a3e6..4f1026d4ef 100644 --- a/src/scripts/check-definitions.py +++ b/src/scripts/check-definitions.py @@ -33,18 +33,17 @@ debug = 0 # For the native part, return the sorted definition array. def loadDefinitionFile(filename): result = [] + try: - f = open(filename, 'r') - except: + with open(filename, 'r') as f: + for line in f: + line = line.strip() + if line: + result.append(line) + except IOError: + # If cmake was not used, this script won't work, and that's ok sys.exit(0) - # if cmake was not used (because of skipnative or systems that do not use cmake), this script won't work. - - for line in f: - theLine = line.rstrip("\r\n").strip() - if (len(theLine) > 0): - result.append(theLine) - f.close() result = sorted(result) return result @@ -108,9 +107,10 @@ def getDiff(arrNative, arrManaged): def printPotentiallyCritical(arrDefinitions, referencedFilename, arrIgnore): - f = open(referencedFilename, 'r') - content = f.read() - f.close() + content = None + with open(referencedFilename, 'r') as f: + content = f.read() + for keyword in arrDefinitions: skip = 0 diff --git a/src/scripts/genDummyProvider.py b/src/scripts/genDummyProvider.py new file mode 100644 index 0000000000..0704554263 --- /dev/null +++ b/src/scripts/genDummyProvider.py @@ -0,0 +1,211 @@ +## +## Licensed to the .NET Foundation under one or more agreements. +## The .NET Foundation licenses this file to you under the MIT license. +## See the LICENSE file in the project root for more information. +## +## This script exists to create a dummy implementaion of the eventprovider +## interface from a manifest file +## +## The intended use if for platforms which support event pipe +## but do not have a an eventing platform to recieve report events + +import os +from genEventing import * +from utilities import open_for_update + +stdprolog_cpp=""" +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************** + +DO NOT MODIFY. AUTOGENERATED FILE. +This file is generated using the logic from <root>/src/scripts/genDummyProvider.py + +******************************************************************/ +""" +stdprolog_cmake=""" +# +# +#****************************************************************** + +#DO NOT MODIFY. AUTOGENERATED FILE. +#This file is generated using the logic from <root>/src/scripts/genDummyProvider.py + +#****************************************************************** +""" + +def trimProvName(name): + name = name.replace("Windows-",'') + name = name.replace("Microsoft-",'') + name = name.replace('-','_') + return name + +def escapeProvFilename(name): + name = name.replace('_','') + name = name.lower() + return name + +def generateDummyProvider(providerName, eventNodes, allTemplates, extern): + impl = [] + for eventNode in eventNodes: + eventName = eventNode.getAttribute('symbol') + templateName = eventNode.getAttribute('template') + + #generate EventXplatEnabled + if extern: impl.append('extern "C" ') + impl.append("BOOL EventXplatEnabled%s(){ return FALSE; }\n\n" % (eventName,)) + + #generate FireEtw functions + fnptype = [] + linefnptype = [] + if extern: fnptype.append('extern "C" ') + fnptype.append("ULONG FireEtXplat") + fnptype.append(eventName) + fnptype.append("(\n") + + + if templateName: + template = allTemplates[templateName] + else: + template = None + + if template: + fnSig = template.signature + for paramName in fnSig.paramlist: + fnparam = fnSig.getParam(paramName) + wintypeName = fnparam.winType + typewName = palDataTypeMapping[wintypeName] + winCount = fnparam.count + countw = palDataTypeMapping[winCount] + + if paramName in template.structs: + linefnptype.append("%sint %s_ElementSize,\n" % (lindent, paramName)) + + linefnptype.append(lindent) + linefnptype.append(typewName) + if countw != " ": + linefnptype.append(countw) + + linefnptype.append(" ") + linefnptype.append(fnparam.name) + linefnptype.append(",\n") + + if len(linefnptype) > 0 : + del linefnptype[-1] + + fnptype.extend(linefnptype) + fnptype.append(")\n{\n") + impl.extend(fnptype) + + #start of fn body + impl.append(" return ERROR_SUCCESS;\n") + impl.append("}\n\n") + + return ''.join(impl) + +def generateDummyFiles(etwmanifest, out_dirname, extern): + tree = DOM.parse(etwmanifest) + + #keep these relative + dummy_directory = "dummy" + dummyevntprovPre = os.path.join(dummy_directory, "eventprov") + + if not os.path.exists(out_dirname): + os.makedirs(out_dirname) + + if not os.path.exists(os.path.join(out_dirname, dummy_directory)): + os.makedirs(os.path.join(out_dirname, dummy_directory)) + + # Cmake + with open_for_update(os.path.join(out_dirname, "CMakeLists.txt")) as cmake: + cmake.write(stdprolog_cmake + "\n") + cmake.write("\ncmake_minimum_required(VERSION 2.8.12.2)\n") + if extern: cmake.write("\nproject(eventprovider)\n") + cmake.write(""" + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +if(FEATURE_PAL) + add_definitions(-DPAL_STDCPP_COMPAT=1) + include_directories(${COREPAL_SOURCE_DIR}/inc/rt) +endif(FEATURE_PAL) +include_directories(dummy) + +""") + if extern: cmake.write("add_library") + else: cmake.write("add_library_clr") + cmake.write("""(eventprovider + STATIC\n""") + + for providerNode in tree.getElementsByTagName('provider'): + providerName = trimProvName(providerNode.getAttribute('name')) + providerName_File = escapeProvFilename(providerName) + + cmake.write(' "%s%s.cpp"\n' % (dummyevntprovPre, providerName_File)) + + cmake.write(")") + if extern: cmake.write(""" + +# Install the static eventprovider library +install(TARGETS eventprovider DESTINATION lib) +""") + + # Dummy Instrumentation + for providerNode in tree.getElementsByTagName('provider'): + providerName = trimProvName(providerNode.getAttribute('name')) + providerName_File = escapeProvFilename(providerName) + + dummyevntprov = os.path.join(out_dirname, dummyevntprovPre + providerName_File + ".cpp") + + with open_for_update(dummyevntprov) as impl: + impl.write(stdprolog_cpp + "\n") + + impl.write(""" +#ifdef PLATFORM_UNIX +#include "pal_mstypes.h" +#include "pal_error.h" +#include "pal.h" +#define PAL_free free +#define PAL_realloc realloc +#include "pal/stackstring.hpp" +#endif + + +""") + + templateNodes = providerNode.getElementsByTagName('template') + eventNodes = providerNode.getElementsByTagName('event') + + allTemplates = parseTemplateNodes(templateNodes) + + #create the implementation of eventing functions : dummyeventprov*.cp + impl.write(generateDummyProvider(providerName, eventNodes, allTemplates, extern) + "\n") + +def main(argv): + + #parse the command line + parser = argparse.ArgumentParser(description="Generates the Code required to instrument LTTtng logging mechanism") + + required = parser.add_argument_group('required arguments') + required.add_argument('--man', type=str, required=True, + help='full path to manifest containig the description of events') + required.add_argument('--intermediate', type=str, required=True, + help='full path to eventprovider intermediate directory') + required.add_argument('--nonextern', action='store_true', + help='if specified, will generate files to be compiled into the CLR rather than externaly' ) + args, unknown = parser.parse_known_args(argv) + if unknown: + print('Unknown argument(s): ', ', '.join(unknown)) + return 1 + + sClrEtwAllMan = args.man + intermediate = args.intermediate + extern = not args.nonextern + + generateDummyFiles(sClrEtwAllMan, intermediate, extern) + +if __name__ == '__main__': + return_code = main(sys.argv[1:]) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genEtwProvider.py b/src/scripts/genEtwProvider.py new file mode 100644 index 0000000000..fc9d43800f --- /dev/null +++ b/src/scripts/genEtwProvider.py @@ -0,0 +1,312 @@ +## +## Licensed to the .NET Foundation under one or more agreements. +## The .NET Foundation licenses this file to you under the MIT license. +## See the LICENSE file in the project root for more information. +## +## This script generates the interface to ETW using MC.exe + +import os +from os import path +import shutil +import re +import sys +import argparse +import subprocess +import xml.dom.minidom as DOM +from genEventing import parseTemplateNodes +from utilities import open_for_update + +macroheader_filename = "etwmacros.h" +mcheader_filename = "ClrEtwAll.h" +clrxplat_filename = "clrxplatevents.h" +etw_dirname = "etw" +replacements = [ + (r"EventEnabled", "EventXplatEnabled"), + (r"\bPVOID\b", "void*") +] + +stdprolog_cpp=""" +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************** + +DO NOT MODIFY. AUTOGENERATED FILE. +This file is generated using the logic from <root>/src/scripts/genEtwProvider.py + +******************************************************************/ +""" +stdprolog_cmake=""" +# +# +#****************************************************************** + +#DO NOT MODIFY. AUTOGENERATED FILE. +#This file is generated using the logic from <root>/src/scripts/genEtwProvider.py + +#****************************************************************** +""" + +def genProviderInterface(manifest, intermediate): + provider_dirname = os.path.join(intermediate, etw_dirname) + + if not os.path.exists(provider_dirname): + os.makedirs(provider_dirname) + + cmd = ['mc.exe', '-h', provider_dirname, '-r', provider_dirname, '-b', '-co', '-um', '-p', 'FireEtXplat', manifest] + subprocess.check_call(cmd) + + header_text = None + with open(path.join(provider_dirname, mcheader_filename), 'r') as mcheader_file: + header_text = mcheader_file.read() + + for pattern, replacement in replacements: + header_text = re.sub(pattern, replacement, header_text) + + with open_for_update(path.join(provider_dirname, mcheader_filename)) as mcheader_file: + mcheader_file.write(header_text) + +def genCmake(intermediate): + # Top level Cmake + + with open_for_update(os.path.join(intermediate, "CMakeLists.txt")) as cmake_file: + cmake_file.write(stdprolog_cmake) + cmake_file.write(""" +project(eventprovider) + +cmake_minimum_required(VERSION 2.8.12.2) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include_directories({0}) + +add_library_clr(eventprovider + STATIC + "{0}/{1}" + "{0}/{2}" +) + +#set_target_properties(eventprovider PROPERTIES LINKER_LANGUAGE Hxx) +""".format(etw_dirname, macroheader_filename, "ClrEtwAll.cpp")) + +def genXplatHeader(intermediate): + with open_for_update(path.join(intermediate, clrxplat_filename)) as header_file: + header_file.write(""" +#ifndef _CLR_XPLAT_EVENTS_H_ +#define _CLR_XPLAT_EVENTS_H_ + +#include "{0}/{1}" +#include "{0}/{2}" + +#endif //_CLR_XPLAT_EVENTS_H_ +""".format(etw_dirname, macroheader_filename, mcheader_filename)) + + +class EventExclusions: + def __init__(self): + self.nostack = set() + self.explicitstack = set() + self.noclrinstance = set() + +def parseExclusionList(exclusion_filename): + with open(exclusion_filename,'r') as ExclusionFile: + exclusionInfo = EventExclusions() + + for line in ExclusionFile: + line = line.strip() + + #remove comments + if not line or line.startswith('#'): + continue + + tokens = line.split(':') + #entries starting with nomac are ignored + if "nomac" in tokens: + continue + + if len(tokens) > 5: + raise Exception("Invalid Entry " + line + "in "+ exclusion_filename) + + eventProvider = tokens[2] + eventTask = tokens[1] + eventSymbol = tokens[4] + + if eventProvider == '': + eventProvider = "*" + if eventTask == '': + eventTask = "*" + if eventSymbol == '': + eventSymbol = "*" + entry = eventProvider + ":" + eventTask + ":" + eventSymbol + + if tokens[0].lower() == "nostack": + exclusionInfo.nostack.add(entry) + if tokens[0].lower() == "stack": + exclusionInfo.explicitstack.add(entry) + if tokens[0].lower() == "noclrinstanceid": + exclusionInfo.noclrinstance.add(entry) + + return exclusionInfo + +def getStackWalkBit(eventProvider, taskName, eventSymbol, stackSet): + for entry in stackSet: + tokens = entry.split(':') + + if len(tokens) != 3: + raise Exception("Error, possible error in the script which introduced the enrty "+ entry) + + eventCond = tokens[0] == eventProvider or tokens[0] == "*" + taskCond = tokens[1] == taskName or tokens[1] == "*" + symbolCond = tokens[2] == eventSymbol or tokens[2] == "*" + + if eventCond and taskCond and symbolCond: + return False + return True + +#Add the miscelaneous checks here +def checkConsistency(manifest, exclusion_filename): + tree = DOM.parse(manifest) + exclusionInfo = parseExclusionList(exclusion_filename) + for providerNode in tree.getElementsByTagName('provider'): + + stackSupportSpecified = {} + eventNodes = providerNode.getElementsByTagName('event') + templateNodes = providerNode.getElementsByTagName('template') + eventProvider = providerNode.getAttribute('name') + allTemplates = parseTemplateNodes(templateNodes) + + for eventNode in eventNodes: + taskName = eventNode.getAttribute('task') + eventSymbol = eventNode.getAttribute('symbol') + eventTemplate = eventNode.getAttribute('template') + eventValue = int(eventNode.getAttribute('value')) + clrInstanceBit = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.noclrinstance) + sLookupFieldName = "ClrInstanceID" + sLookupFieldType = "win:UInt16" + + if clrInstanceBit and allTemplates.get(eventTemplate): + # check for the event template and look for a field named ClrInstanceId of type win:UInt16 + fnParam = allTemplates[eventTemplate].getFnParam(sLookupFieldName) + + if not(fnParam and fnParam.winType == sLookupFieldType): + raise Exception(exclusion_filename + ":No " + sLookupFieldName + " field of type " + sLookupFieldType + " for event symbol " + eventSymbol) + + # If some versions of an event are on the nostack/stack lists, + # and some versions are not on either the nostack or stack list, + # then developer likely forgot to specify one of the versions + + eventStackBitFromNoStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack) + eventStackBitFromExplicitStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack) + sStackSpecificityError = exclusion_filename + ": Error processing event :" + eventSymbol + "(ID" + str(eventValue) + "): This file must contain either ALL versions of this event or NO versions of this event. Currently some, but not all, versions of this event are present\n" + + if not stackSupportSpecified.get(eventValue): + # Haven't checked this event before. Remember whether a preference is stated + if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): + stackSupportSpecified[eventValue] = True + else: + stackSupportSpecified[eventValue] = False + else: + # We've checked this event before. + if stackSupportSpecified[eventValue]: + # When we last checked, a preference was previously specified, so it better be specified here + if eventStackBitFromNoStackList and eventStackBitFromExplicitStackList: + raise Exception(sStackSpecificityError) + else: + # When we last checked, a preference was not previously specified, so it better not be specified here + if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): + raise Exception(sStackSpecificityError) + +def genEtwMacroHeader(manifest, exclusion_filename, intermediate): + provider_dirname = os.path.join(intermediate, etw_dirname) + + if not os.path.exists(provider_dirname): + os.makedirs(provider_dirname) + + tree = DOM.parse(manifest) + numOfProviders = len(tree.getElementsByTagName('provider')) + nMaxEventBytesPerProvider = 64 + + exclusionInfo = parseExclusionList(exclusion_filename) + + with open_for_update(os.path.join(provider_dirname, macroheader_filename)) as header_file: + header_file.write(stdprolog_cpp + "\n") + + header_file.write("#define NO_OF_ETW_PROVIDERS " + str(numOfProviders) + "\n") + header_file.write("#define MAX_BYTES_PER_ETW_PROVIDER " + str(nMaxEventBytesPerProvider) + "\n") + header_file.write("EXTERN_C __declspec(selectany) const BYTE etwStackSupportedEvents[NO_OF_ETW_PROVIDERS][MAX_BYTES_PER_ETW_PROVIDER] = \n{\n") + + for providerNode in tree.getElementsByTagName('provider'): + stackSupportedEvents = [0]*nMaxEventBytesPerProvider + eventNodes = providerNode.getElementsByTagName('event') + eventProvider = providerNode.getAttribute('name') + + for eventNode in eventNodes: + taskName = eventNode.getAttribute('task') + eventSymbol = eventNode.getAttribute('symbol') + eventTemplate = eventNode.getAttribute('template') + eventTemplate = eventNode.getAttribute('template') + eventValue = int(eventNode.getAttribute('value')) + eventIndex = eventValue // 8 + eventBitPositionInIndex = eventValue % 8 + + eventStackBitFromNoStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack)) + eventStackBitFromExplicitStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack)) + + # Shift those bits into position. For the explicit stack list, swap 0 and 1, so the eventValue* variables + # have 1 in the position iff we should issue a stack for the event. + eventValueUsingNoStackListByPosition = (eventStackBitFromNoStackList << eventBitPositionInIndex) + eventValueUsingExplicitStackListByPosition = ((1 - eventStackBitFromExplicitStackList) << eventBitPositionInIndex) + + # Commit the values to the in-memory array that we'll dump into the header file + stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingNoStackListByPosition; + if eventStackBitFromExplicitStackList == 0: + stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingExplicitStackListByPosition + + # print the bit array + line = [] + line.append("\t{") + for elem in stackSupportedEvents: + line.append(str(elem)) + line.append(", ") + + del line[-1] + line.append("},") + header_file.write(''.join(line) + "\n") + header_file.write("};\n") + +def genFiles(manifest, intermediate, exclusion_filename): + if not os.path.exists(intermediate): + os.makedirs(intermediate) + + genProviderInterface(manifest, intermediate) + genEtwMacroHeader(manifest, exclusion_filename, intermediate) + genXplatHeader(intermediate) + + +def main(argv): + #parse the command line + parser = argparse.ArgumentParser(description="Generates the Code required to instrument ETW logging mechanism") + + required = parser.add_argument_group('required arguments') + required.add_argument('--man', type=str, required=True, + help='full path to manifest containig the description of events') + required.add_argument('--exc', type=str, required=True, + help='full path to exclusion list') + required.add_argument('--intermediate', type=str, required=True, + help='full path to eventprovider intermediate directory') + args, unknown = parser.parse_known_args(argv) + if unknown: + print('Unknown argument(s): ', ', '.join(unknown)) + return 1 + + manifest = args.man + exclusion_filename = args.exc + intermediate = args.intermediate + + checkConsistency(manifest, exclusion_filename) + genFiles(manifest, intermediate, exclusion_filename) + +if __name__ == '__main__': + return_code = main(sys.argv[1:]) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genEventPipe.py b/src/scripts/genEventPipe.py index 8a970794c0..96755ea459 100644 --- a/src/scripts/genEventPipe.py +++ b/src/scripts/genEventPipe.py @@ -1,10 +1,11 @@ from __future__ import print_function -from genXplatEventing import * -from genXplatLttng import * +from genEventing import * +from genLttngProvider import * import os import xml.dom.minidom as DOM +from utilities import open_for_update -stdprolog = """// Licensed to the .NET Foundation under one or more agreements. +stdprolog_cpp = """// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. @@ -14,6 +15,7 @@ DO NOT MODIFY. AUTOGENERATED FILE. This file is generated using the logic from <root>/src/scripts/genEventPipe.py ******************************************************************/ + """ stdprolog_cmake = """# @@ -24,11 +26,54 @@ stdprolog_cmake = """# #This file is generated using the logic from <root>/src/scripts/genEventPipe.py #****************************************************************** + """ +eventpipe_dirname = "eventpipe" + +def generateMethodSignatureEnabled(eventName): + return "BOOL EventPipeEventEnabled%s()" % (eventName,) + +def generateMethodSignatureWrite(eventName, template, extern): + sig_pieces = [] + + if extern: sig_pieces.append('extern "C" ') + sig_pieces.append("ULONG EventPipeWriteEvent") + 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 = palDataTypeMapping[wintypeName] + winCount = fnparam.count + countw = palDataTypeMapping[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") + + if len(sig_pieces) > 0: + del sig_pieces[-1] + + sig_pieces.append(")") + return ''.join(sig_pieces) def generateClrEventPipeWriteEventsImpl( - providerName, eventNodes, allTemplates, exclusionListFile): + providerName, eventNodes, allTemplates, extern): providerPrettyName = providerName.replace("Windows-", '') providerPrettyName = providerPrettyName.replace("Microsoft-", '') providerPrettyName = providerPrettyName.replace('-', '_') @@ -47,54 +92,24 @@ def generateClrEventPipeWriteEventsImpl( templateName = eventNode.getAttribute('template') # generate EventPipeEventEnabled function - eventEnabledImpl = """bool EventPipeEventEnabled%s() + eventEnabledImpl = generateMethodSignatureEnabled(eventName) + """ { return EventPipeEvent%s->IsEnabled(); } -""" % (eventName, eventName) +""" % eventName WriteEventImpl.append(eventEnabledImpl) # generate EventPipeWriteEvent function fnptype = [] - linefnptype = [] - fnptype.append("extern \"C\" ULONG EventPipeWriteEvent") - fnptype.append(eventName) - fnptype.append("(\n") if templateName: template = allTemplates[templateName] else: template = None - if template: - fnSig = template.signature - for paramName in fnSig.paramlist: - fnparam = fnSig.getParam(paramName) - wintypeName = fnparam.winType - typewName = palDataTypeMapping[wintypeName] - winCount = fnparam.count - countw = palDataTypeMapping[winCount] - - if paramName in template.structs: - linefnptype.append( - "%sint %s_ElementSize,\n" % - (lindent, paramName)) - - linefnptype.append(lindent) - linefnptype.append(typewName) - if countw != " ": - linefnptype.append(countw) - - linefnptype.append(" ") - linefnptype.append(fnparam.name) - linefnptype.append(",\n") - - if len(linefnptype) > 0: - del linefnptype[-1] - - fnptype.extend(linefnptype) - fnptype.append(")\n{\n") + fnptype.append(generateMethodSignatureWrite(eventName, template, extern)) + fnptype.append("\n{\n") checking = """ if (!EventPipeEventEnabled%s()) return ERROR_SUCCESS; """ % (eventName) @@ -115,8 +130,9 @@ def generateClrEventPipeWriteEventsImpl( WriteEventImpl.append("\n return ERROR_SUCCESS;\n}\n\n") # EventPipeProvider and EventPipeEvent initialization + if extern: WriteEventImpl.append('extern "C" ') WriteEventImpl.append( - "extern \"C\" void Init" + + "void Init" + providerPrettyName + "()\n{\n") WriteEventImpl.append( @@ -134,7 +150,6 @@ def generateClrEventPipeWriteEventsImpl( eventVersion = eventNode.getAttribute('version') eventLevel = eventNode.getAttribute('level') eventLevel = eventLevel.replace("win:", "EventPipeEventLevel::") - exclusionInfo = parseExclusionList(exclusionListFile) taskName = eventNode.getAttribute('task') initEvent = """ EventPipeEvent%s = EventPipeProvider%s->AddEvent(%s,%s,%s,%s); @@ -150,8 +165,8 @@ def generateWriteEventBody(template, providerName, eventName): header = """ char stackBuffer[%s]; char *buffer = stackBuffer; - unsigned int offset = 0; - unsigned int size = %s; + size_t offset = 0; + size_t size = %s; bool fixedBuffer = true; bool success = true; @@ -198,7 +213,7 @@ def generateWriteEventBody(template, providerName, eventName): }\n\n""" body = " EventPipe::WriteEvent(*EventPipeEvent" + \ - eventName + ", (BYTE *)buffer, offset);\n" + eventName + ", (BYTE *)buffer, (unsigned int)offset);\n" footer = """ if (!fixedBuffer) @@ -221,20 +236,23 @@ def generateEventKeywords(eventKeywords): return mask -def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory): +def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory, extern): tree = DOM.parse(etwmanifest) - with open(eventpipe_directory + "CMakeLists.txt", 'w') as topCmake: - topCmake.write(stdprolog_cmake + "\n") - topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2) + with open_for_update(os.path.join(eventpipe_directory, "CMakeLists.txt")) as cmake_file: + cmake_file.write(stdprolog_cmake) + cmake_file.write("cmake_minimum_required(VERSION 2.8.12.2)\n") + if extern: cmake_file.write("\nproject(eventpipe)\n") + cmake_file.write(""" - project(eventpipe) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +include_directories(${CLR_DIR}/src/vm) - set(CMAKE_INCLUDE_CURRENT_DIR ON) - include_directories(${CLR_DIR}/src/vm) - - add_library(eventpipe - STATIC\n""") +""") + if extern: cmake_file.write("add_library") + else: cmake_file.write("add_library_clr") + cmake_file.write("""(eventpipe + STATIC\n""") for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') @@ -244,34 +262,41 @@ def generateEventPipeCmakeFile(etwmanifest, eventpipe_directory): providerName_File = providerName.replace('-', '') providerName_File = providerName_File.lower() - topCmake.write(' "%s.cpp"\n' % (providerName_File)) - topCmake.write(' "eventpipehelpers.cpp"\n') - topCmake.write(""" ) - - add_dependencies(eventpipe GeneratedEventingFiles) - - # Install the static eventpipe library - install(TARGETS eventpipe DESTINATION lib) - """) - - topCmake.close() + cmake_file.write(' "%s/%s.cpp"\n' % (eventpipe_dirname, providerName_File)) + cmake_file.write(' "%s/eventpipehelpers.cpp"\n)' % (eventpipe_dirname,)) + if extern: cmake_file.write(""" +# Install the static eventpipe library +install(TARGETS eventpipe DESTINATION lib) +""") -def generateEventPipeHelperFile(etwmanifest, eventpipe_directory): - with open(eventpipe_directory + "eventpipehelpers.cpp", 'w') as helper: - helper.write(stdprolog) +def generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern): + with open_for_update(os.path.join(eventpipe_directory, "eventpipehelpers.cpp")) as helper: + helper.write(stdprolog_cpp) helper.write(""" -#include "stdlib.h" - -bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer) +#include "common.h" +#include <stdlib.h> +#include <string.h> + +#ifndef FEATURE_PAL +#include <windef.h> +#include <crtdbg.h> +#else +#include "pal.h" +#endif //FEATURE_PAL + +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer) { - newSize *= 1.5; + newSize = (size_t)(newSize * 1.5); _ASSERTE(newSize > size); // check for overflow if (newSize < 32) newSize = 32; - char *newBuffer = new char[newSize]; + char *newBuffer = new (nothrow) char[newSize]; + + if (newBuffer == NULL) + return false; memcpy(newBuffer, buffer, currLen); @@ -285,7 +310,7 @@ bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsig return true; } -bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { if(!src) return true; if (offset + len > size) @@ -299,10 +324,10 @@ bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned in return true; } -bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { if(!str) return true; - unsigned int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str); + size_t byteCount = (wcslen(str) + 1) * sizeof(*str); if (offset + byteCount > size) { @@ -315,10 +340,10 @@ bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int return true; } -bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { if(!str) return true; - unsigned int len = strlen(str) + 1; + size_t len = strlen(str) + 1; if (offset + len > size) { if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) @@ -339,12 +364,18 @@ bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigne providerPrettyName = providerName.replace("Windows-", '') providerPrettyName = providerPrettyName.replace("Microsoft-", '') providerPrettyName = providerPrettyName.replace('-', '_') + if extern: helper.write( + 'extern "C" ' + ) helper.write( - "extern \"C\" void Init" + + "void Init" + providerPrettyName + "();\n\n") - helper.write("extern \"C\" void InitProvidersAndEvents()\n{\n") + if extern: helper.write( + 'extern "C" ' + ) + helper.write("void InitProvidersAndEvents()\n{\n") for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') providerPrettyName = providerName.replace("Windows-", '') @@ -355,11 +386,20 @@ bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigne helper.close() - def generateEventPipeImplFiles( - etwmanifest, eventpipe_directory, exclusionListFile): + etwmanifest, eventpipe_directory, extern): tree = DOM.parse(etwmanifest) - coreclrRoot = os.getcwd() + + # 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') @@ -368,74 +408,77 @@ def generateEventPipeImplFiles( providerName_File = providerPrettyName.replace('-', '') providerName_File = providerName_File.lower() providerPrettyName = providerPrettyName.replace('-', '_') - eventpipefile = eventpipe_directory + providerName_File + ".cpp" - eventpipeImpl = open(eventpipefile, 'w') - eventpipeImpl.write(stdprolog) + eventpipefile = os.path.join(eventpipe_directory, providerName_File + ".cpp") + with open_for_update(eventpipefile) as eventpipeImpl: + eventpipeImpl.write(stdprolog_cpp) + + header = """ +#include "{root:s}/vm/common.h" +#include "{root:s}/vm/eventpipeprovider.h" +#include "{root:s}/vm/eventpipeevent.h" +#include "{root:s}/vm/eventpipe.h" - header = """ -#include \"%s/src/vm/common.h\" -#include \"%s/src/vm/eventpipeprovider.h\" -#include \"%s/src/vm/eventpipeevent.h\" -#include \"%s/src/vm/eventpipe.h\" +#if defined(FEATURE_PAL) +#define wcslen PAL_wcslen +#endif -bool ResizeBuffer(char *&buffer, unsigned int& size, unsigned int currLen, unsigned int newSize, bool &fixedBuffer); -bool WriteToBuffer(PCWSTR str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); -bool WriteToBuffer(const char *str, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); -bool WriteToBuffer(const BYTE *src, unsigned int len, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer); +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer); +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); template <typename T> -bool WriteToBuffer(const T &value, char *&buffer, unsigned int& offset, unsigned int& size, bool &fixedBuffer) -{ +bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) +{{ if (sizeof(T) + offset > size) - { - if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) - return false; - } + {{ + if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) + return false; + }} *(T *)(buffer + offset) = value; offset += sizeof(T); return true; -} +}} -""" % (coreclrRoot, coreclrRoot, coreclrRoot, coreclrRoot) +""".format(root=src_dirname.replace('\\', '/')) - eventpipeImpl.write(header) - eventpipeImpl.write( - "const WCHAR* %sName = W(\"%s\");\n" % ( - providerPrettyName, - providerName + eventpipeImpl.write(header) + eventpipeImpl.write( + "const WCHAR* %sName = W(\"%s\");\n" % ( + providerPrettyName, + providerName + ) ) - ) - eventpipeImpl.write( - "EventPipeProvider *EventPipeProvider%s = nullptr;\n" % ( - providerPrettyName, + eventpipeImpl.write( + "EventPipeProvider *EventPipeProvider%s = nullptr;\n" % ( + providerPrettyName, + ) ) - ) - templateNodes = providerNode.getElementsByTagName('template') - allTemplates = parseTemplateNodes(templateNodes) - eventNodes = providerNode.getElementsByTagName('event') - eventpipeImpl.write( - generateClrEventPipeWriteEventsImpl( - providerName, - eventNodes, - allTemplates, - exclusionListFile) + "\n") - eventpipeImpl.close() + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') + eventpipeImpl.write( + generateClrEventPipeWriteEventsImpl( + providerName, + eventNodes, + allTemplates, + extern) + "\n") def generateEventPipeFiles( - etwmanifest, eventpipe_directory, exclusionListFile): - eventpipe_directory = eventpipe_directory + "/" + etwmanifest, intermediate, extern): + eventpipe_directory = os.path.join(intermediate, eventpipe_dirname) tree = DOM.parse(etwmanifest) if not os.path.exists(eventpipe_directory): os.makedirs(eventpipe_directory) - # generate Cmake file - generateEventPipeCmakeFile(etwmanifest, eventpipe_directory) + # generate CMake file + generateEventPipeCmakeFile(etwmanifest, intermediate, extern) # generate helper file - generateEventPipeHelperFile(etwmanifest, eventpipe_directory) + generateEventPipeHelperFile(etwmanifest, eventpipe_directory, extern) # generate all keywords for keywordNode in tree.getElementsByTagName('keyword'): @@ -447,12 +490,12 @@ def generateEventPipeFiles( generateEventPipeImplFiles( etwmanifest, eventpipe_directory, - exclusionListFile) + extern + ) import argparse import sys - def main(argv): # parse the command line @@ -464,19 +507,19 @@ def main(argv): help='full path to manifest containig the description of events') required.add_argument('--intermediate', type=str, required=True, help='full path to eventprovider intermediate directory') - required.add_argument('--exc', type=str, required=True, - help='full path to exclusion list') + required.add_argument('--nonextern', action='store_true', + help='if specified, will generate files to be compiled into the CLR rather than extern' ) args, unknown = parser.parse_known_args(argv) if unknown: print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments + return 1 sClrEtwAllMan = args.man intermediate = args.intermediate - exclusionListFile = args.exc + extern = not args.nonextern - generateEventPipeFiles(sClrEtwAllMan, intermediate, exclusionListFile) + generateEventPipeFiles(sClrEtwAllMan, intermediate, extern) if __name__ == '__main__': return_code = main(sys.argv[1:]) - sys.exit(return_code) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genXplatEventing.py b/src/scripts/genEventing.py index 4c9ce873b7..d6d6afbb90 100644 --- a/src/scripts/genXplatEventing.py +++ b/src/scripts/genEventing.py @@ -6,7 +6,7 @@ # #USAGE: #Add Events: modify <root>src/vm/ClrEtwAll.man -#Look at the Code in <root>/src/scripts/genXplatLttng.py for using subroutines in this file +#Look at the Code in <root>/src/scripts/genLttngProvider.py for using subroutines in this file # # Python 2 compatibility @@ -14,6 +14,7 @@ from __future__ import print_function import os import xml.dom.minidom as DOM +from utilities import open_for_update stdprolog=""" // Licensed to the .NET Foundation under one or more agreements. @@ -23,7 +24,7 @@ stdprolog=""" /****************************************************************** DO NOT MODIFY. AUTOGENERATED FILE. -This file is generated using the logic from <root>/src/scripts/genXplatEventing.py +This file is generated using the logic from <root>/src/scripts/genEventing.py ******************************************************************/ """ @@ -34,7 +35,7 @@ stdprolog_cmake=""" #****************************************************************** #DO NOT MODIFY. AUTOGENERATED FILE. -#This file is generated using the logic from <root>/src/scripts/genXplatEventing.py +#This file is generated using the logic from <root>/src/scripts/genEventing.py #****************************************************************** """ @@ -260,7 +261,7 @@ def parseTemplateNodes(templateNodes): assert(countVarName in fnPrototypes.paramlist) if not countVarName: raise ValueError("Struct '%s' in template '%s' does not have an attribute count." % (structName, templateName)) - + names = [x.attributes['name'].value for x in structToBeMarshalled.getElementsByTagName("data")] types = [x.attributes['inType'].value for x in structToBeMarshalled.getElementsByTagName("data")] @@ -305,8 +306,8 @@ def generateClrallEvents(eventNodes,allTemplates): typewName = palDataTypeMapping[wintypeName] winCount = fnparam.count countw = palDataTypeMapping[winCount] - - + + if params in template.structs: fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params)) @@ -321,7 +322,7 @@ def generateClrallEvents(eventNodes,allTemplates): for params in fnSig.paramlist: fnparam = fnSig.getParam(params) - if params in template.structs: + if params in template.structs: line.append(fnparam.name + "_ElementSize") line.append(", ") @@ -349,20 +350,23 @@ def generateClrallEvents(eventNodes,allTemplates): return ''.join(clrallEvents) -def generateClrXplatEvents(eventNodes, allTemplates): +def generateClrXplatEvents(eventNodes, allTemplates, extern): clrallEvents = [] for eventNode in eventNodes: eventName = eventNode.getAttribute('symbol') templateName = eventNode.getAttribute('template') #generate EventEnabled - clrallEvents.append("extern \"C\" BOOL EventXplatEnabled") + if extern: clrallEvents.append('extern "C" ') + clrallEvents.append("BOOL EventXplatEnabled") clrallEvents.append(eventName) clrallEvents.append("();\n") + #generate FireEtw functions fnptype = [] fnptypeline = [] - fnptype.append("extern \"C\" ULONG FireEtXplat") + if extern: fnptype.append('extern "C" ') + fnptype.append("ULONG FireEtXplat") fnptype.append(eventName) fnptype.append("(\n") @@ -377,7 +381,7 @@ def generateClrXplatEvents(eventNodes, allTemplates): winCount = fnparam.count countw = palDataTypeMapping[winCount] - + if params in template.structs: fnptypeline.append("%sint %s_ElementSize,\n" % (lindent, params)) @@ -398,7 +402,7 @@ def generateClrXplatEvents(eventNodes, allTemplates): return ''.join(clrallEvents) -def generateClrEventPipeWriteEvents(eventNodes, allTemplates): +def generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern): clrallEvents = [] for eventNode in eventNodes: eventName = eventNode.getAttribute('symbol') @@ -409,11 +413,13 @@ def generateClrEventPipeWriteEvents(eventNodes, allTemplates): writeevent = [] fnptypeline = [] - eventenabled.append("extern \"C\" bool EventPipeEventEnabled") + if extern:eventenabled.append('extern "C" ') + eventenabled.append("BOOL EventPipeEventEnabled") eventenabled.append(eventName) eventenabled.append("();\n") - writeevent.append("extern \"C\" ULONG EventPipeWriteEvent") + if extern: writeevent.append('extern "C" ') + writeevent.append("ULONG EventPipeWriteEvent") writeevent.append(eventName) writeevent.append("(\n") @@ -554,63 +560,70 @@ def generateSanityTest(sClrEtwAllMan,testDir): cmake_file = testDir + "/CMakeLists.txt" test_cpp = "clralltestevents.cpp" testinfo = testDir + "/testinfo.dat" - Cmake_file = open(cmake_file,'w') - Test_cpp = open(testDir + "/" + test_cpp,'w') - Testinfo = open(testinfo,'w') #CMake File: - Cmake_file.write(stdprolog_cmake) - Cmake_file.write(""" - cmake_minimum_required(VERSION 2.8.12.2) - set(CMAKE_INCLUDE_CURRENT_DIR ON) - set(SOURCES - """) - Cmake_file.write(test_cpp) - Cmake_file.write(""" - ) - include_directories(${GENERATED_INCLUDE_DIR}) + with open_for_update(cmake_file) as Cmake_file: + Cmake_file.write(stdprolog_cmake) + Cmake_file.write(""" +cmake_minimum_required(VERSION 2.8.12.2) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(SOURCES +""") + Cmake_file.write(test_cpp) + Cmake_file.write(""" + ) +include_directories(${GENERATED_INCLUDE_DIR}) + +if(FEATURE_PAL) include_directories(${COREPAL_SOURCE_DIR}/inc/rt) +endif(FEATURE_PAL) + +add_executable(eventprovidertest + ${SOURCES} + ) +set(EVENT_PROVIDER_DEPENDENCIES "") +set(EVENT_PROVIDER_LINKER_OTPTIONS "") +if(FEATURE_EVENT_TRACE) + add_definitions(-DFEATURE_EVENT_TRACE=1) + list(APPEND EVENT_PROVIDER_DEPENDENCIES + eventprovider + ) + if(CLR_CMAKE_PLATFORM_LINUX) + list(APPEND EVENT_PROVIDER_DEPENDENCIES + coreclrtraceptprovider + ) + endif(CLR_CMAKE_PLATFORM_LINUX) + list(APPEND EVENT_PROVIDER_LINKER_OTPTIONS + ${EVENT_PROVIDER_DEPENDENCIES} + ) +endif(FEATURE_EVENT_TRACE) + +add_dependencies(eventprovidertest ${EVENT_PROVIDER_DEPENDENCIES} coreclrpal) +target_link_libraries(eventprovidertest + coreclrpal + ${EVENT_PROVIDER_LINKER_OTPTIONS} + ) +""") + + + with open_for_update(testinfo) as Testinfo: + Testinfo.write(""" +Copyright (c) Microsoft Corporation. All rights reserved. +# - add_executable(eventprovidertest - ${SOURCES} - ) - set(EVENT_PROVIDER_DEPENDENCIES "") - set(EVENT_PROVIDER_LINKER_OTPTIONS "") - if(FEATURE_EVENT_TRACE) - add_definitions(-DFEATURE_EVENT_TRACE=1) - list(APPEND EVENT_PROVIDER_DEPENDENCIES - coreclrtraceptprovider - eventprovider - ) - list(APPEND EVENT_PROVIDER_LINKER_OTPTIONS - ${EVENT_PROVIDER_DEPENDENCIES} - ) - - endif(FEATURE_EVENT_TRACE) - - add_dependencies(eventprovidertest ${EVENT_PROVIDER_DEPENDENCIES} coreclrpal) - target_link_libraries(eventprovidertest - coreclrpal - ${EVENT_PROVIDER_LINKER_OTPTIONS} - ) - """) - Testinfo.write(""" - Copyright (c) Microsoft Corporation. All rights reserved. - # - - Version = 1.0 - Section = EventProvider - Function = EventProvider - Name = PAL test for FireEtW* and EventEnabled* functions - TYPE = DEFAULT - EXE1 = eventprovidertest - Description - =This is a sanity test to check that there are no crashes in Xplat eventing - """) +Version = 1.0 +Section = EventProvider +Function = EventProvider +Name = PAL test for FireEtW* and EventEnabled* functions +TYPE = DEFAULT +EXE1 = eventprovidertest +Description = This is a sanity test to check that there are no crashes in Xplat eventing +""") #Test.cpp - Test_cpp.write(stdprolog) - Test_cpp.write(""" + with open_for_update(testDir + "/" + test_cpp) as Test_cpp: + Test_cpp.write(stdprolog) + Test_cpp.write(""" /*===================================================================== ** ** Source: clralltestevents.cpp @@ -619,7 +632,9 @@ def generateSanityTest(sClrEtwAllMan,testDir): ** ** **===================================================================*/ +#if FEATURE_PAL #include <palsuite.h> +#endif //FEATURE_PAL #include <clrxplatevents.h> typedef struct _Struct1 { @@ -646,39 +661,42 @@ int win_Int32 = 12; BYTE* win_Binary =(BYTE*)var21 ; int __cdecl main(int argc, char **argv) { - +#if defined(FEATURE_PAL) /* Initialize the PAL. */ if(0 != PAL_Initialize(argc, argv)) { - return FAIL; + return FAIL; } +#endif ULONG Error = ERROR_SUCCESS; #if defined(FEATURE_EVENT_TRACE) Trace("\\n Starting functional eventing APIs tests \\n"); """) - Test_cpp.write(generateClralltestEvents(sClrEtwAllMan)) - Test_cpp.write(""" -/* Shutdown the PAL. - */ - - if (Error != ERROR_SUCCESS) - { - Fail("One or more eventing Apis failed\\n "); - return FAIL; - } - Trace("\\n All eventing APIs were fired succesfully \\n"); + Test_cpp.write(generateClralltestEvents(sClrEtwAllMan)) + Test_cpp.write(""" + + if (Error != ERROR_SUCCESS) + { + Fail("One or more eventing Apis failed\\n "); + return FAIL; + } + Trace("\\n All eventing APIs were fired succesfully \\n"); #endif //defined(FEATURE_EVENT_TRACE) - PAL_Terminate(); - return PASS; - } +#if defined(FEATURE_PAL) + +/* Shutdown the PAL. +*/ + + PAL_Terminate(); +#endif + return PASS; + } """) - Cmake_file.close() - Test_cpp.close() Testinfo.close() def generateEtmDummyHeader(sClrEtwAllMan,clretwdummy): @@ -693,19 +711,17 @@ def generateEtmDummyHeader(sClrEtwAllMan,clretwdummy): if not os.path.exists(incDir): os.makedirs(incDir) - Clretwdummy = open(clretwdummy,'w') - Clretwdummy.write(stdprolog + "\n") - - for providerNode in tree.getElementsByTagName('provider'): - templateNodes = providerNode.getElementsByTagName('template') - allTemplates = parseTemplateNodes(templateNodes) - eventNodes = providerNode.getElementsByTagName('event') - #pal: create etmdummy.h - Clretwdummy.write(generateclrEtwDummy(eventNodes, allTemplates) + "\n") + with open_for_update(clretwdummy) as Clretwdummy: + Clretwdummy.write(stdprolog + "\n") - Clretwdummy.close() + for providerNode in tree.getElementsByTagName('provider'): + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') + #pal: create etmdummy.h + Clretwdummy.write(generateclrEtwDummy(eventNodes, allTemplates) + "\n") -def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile): +def generatePlatformIndependentFiles(sClrEtwAllMan, incDir, etmDummyFile, extern): generateEtmDummyHeader(sClrEtwAllMan,etmDummyFile) tree = DOM.parse(sClrEtwAllMan) @@ -717,152 +733,43 @@ def generatePlformIndependentFiles(sClrEtwAllMan,incDir,etmDummyFile): if not os.path.exists(incDir): os.makedirs(incDir) - clrallevents = incDir + "/clretwallmain.h" - clrxplatevents = incDir + "/clrxplatevents.h" - clreventpipewriteevents = incDir + "/clreventpipewriteevents.h" - - Clrallevents = open(clrallevents,'w') - Clrxplatevents = open(clrxplatevents,'w') - Clreventpipewriteevents = open(clreventpipewriteevents,'w') + # Write the main header for FireETW* functions + clrallevents = os.path.join(incDir, "clretwallmain.h") + with open_for_update(clrallevents) as Clrallevents: + Clrallevents.write(stdprolog) + Clrallevents.write(""" +#include "clrxplatevents.h" +#include "clreventpipewriteevents.h" - Clrallevents.write(stdprolog + "\n") - Clrxplatevents.write(stdprolog + "\n") - Clreventpipewriteevents.write(stdprolog + "\n") +""") + for providerNode in tree.getElementsByTagName('provider'): + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') - Clrallevents.write("\n#include \"clrxplatevents.h\"\n") - Clrallevents.write("#include \"clreventpipewriteevents.h\"\n\n") - - for providerNode in tree.getElementsByTagName('provider'): - templateNodes = providerNode.getElementsByTagName('template') - allTemplates = parseTemplateNodes(templateNodes) - eventNodes = providerNode.getElementsByTagName('event') - #vm header: - Clrallevents.write(generateClrallEvents(eventNodes, allTemplates) + "\n") + #vm header: + Clrallevents.write(generateClrallEvents(eventNodes, allTemplates) + "\n") - #pal: create clrallevents.h - Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates) + "\n") - #eventpipe: create clreventpipewriteevents.h - Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates) + "\n") + # Write secondary headers for FireEtXplat* and EventPipe* functions + clrxplatevents = os.path.join(incDir, "clrxplatevents.h") + clreventpipewriteevents = os.path.join(incDir, "clreventpipewriteevents.h") + with open_for_update(clrxplatevents) as Clrxplatevents: + with open_for_update(clreventpipewriteevents) as Clreventpipewriteevents: + Clrxplatevents.write(stdprolog + "\n") + Clreventpipewriteevents.write(stdprolog + "\n") - Clrxplatevents.close() - Clrallevents.close() - Clreventpipewriteevents.close() + for providerNode in tree.getElementsByTagName('provider'): + templateNodes = providerNode.getElementsByTagName('template') + allTemplates = parseTemplateNodes(templateNodes) + eventNodes = providerNode.getElementsByTagName('event') -class EventExclusions: - def __init__(self): - self.nostack = set() - self.explicitstack = set() - self.noclrinstance = set() - -def parseExclusionList(exclusionListFile): - ExclusionFile = open(exclusionListFile,'r') - exclusionInfo = EventExclusions() - - for line in ExclusionFile: - line = line.strip() - - #remove comments - if not line or line.startswith('#'): - continue - - tokens = line.split(':') - #entries starting with nomac are ignored - if "nomac" in tokens: - continue - - if len(tokens) > 5: - raise Exception("Invalid Entry " + line + "in "+ exclusionListFile) - - eventProvider = tokens[2] - eventTask = tokens[1] - eventSymbol = tokens[4] - - if eventProvider == '': - eventProvider = "*" - if eventTask == '': - eventTask = "*" - if eventSymbol == '': - eventSymbol = "*" - entry = eventProvider + ":" + eventTask + ":" + eventSymbol - - if tokens[0].lower() == "nostack": - exclusionInfo.nostack.add(entry) - if tokens[0].lower() == "stack": - exclusionInfo.explicitstack.add(entry) - if tokens[0].lower() == "noclrinstanceid": - exclusionInfo.noclrinstance.add(entry) - ExclusionFile.close() - - return exclusionInfo - -def getStackWalkBit(eventProvider, taskName, eventSymbol, stackSet): - for entry in stackSet: - tokens = entry.split(':') - - if len(tokens) != 3: - raise Exception("Error, possible error in the script which introduced the enrty "+ entry) - - eventCond = tokens[0] == eventProvider or tokens[0] == "*" - taskCond = tokens[1] == taskName or tokens[1] == "*" - symbolCond = tokens[2] == eventSymbol or tokens[2] == "*" - - if eventCond and taskCond and symbolCond: - return False - return True - -#Add the miscelaneous checks here -def checkConsistency(sClrEtwAllMan,exclusionListFile): - tree = DOM.parse(sClrEtwAllMan) - exclusionInfo = parseExclusionList(exclusionListFile) - for providerNode in tree.getElementsByTagName('provider'): + #pal: create clrallevents.h + Clrxplatevents.write(generateClrXplatEvents(eventNodes, allTemplates, extern) + "\n") - stackSupportSpecified = {} - eventNodes = providerNode.getElementsByTagName('event') - templateNodes = providerNode.getElementsByTagName('template') - eventProvider = providerNode.getAttribute('name') - allTemplates = parseTemplateNodes(templateNodes) + #eventpipe: create clreventpipewriteevents.h + Clreventpipewriteevents.write(generateClrEventPipeWriteEvents(eventNodes, allTemplates, extern) + "\n") - for eventNode in eventNodes: - taskName = eventNode.getAttribute('task') - eventSymbol = eventNode.getAttribute('symbol') - eventTemplate = eventNode.getAttribute('template') - eventValue = int(eventNode.getAttribute('value')) - clrInstanceBit = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.noclrinstance) - sLookupFieldName = "ClrInstanceID" - sLookupFieldType = "win:UInt16" - - if clrInstanceBit and allTemplates.get(eventTemplate): - # check for the event template and look for a field named ClrInstanceId of type win:UInt16 - fnParam = allTemplates[eventTemplate].getFnParam(sLookupFieldName) - - if not(fnParam and fnParam.winType == sLookupFieldType): - raise Exception(exclusionListFile + ":No " + sLookupFieldName + " field of type " + sLookupFieldType + " for event symbol " + eventSymbol) - - # If some versions of an event are on the nostack/stack lists, - # and some versions are not on either the nostack or stack list, - # then developer likely forgot to specify one of the versions - - eventStackBitFromNoStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack) - eventStackBitFromExplicitStackList = getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack) - sStackSpecificityError = exclusionListFile + ": Error processing event :" + eventSymbol + "(ID" + str(eventValue) + "): This file must contain either ALL versions of this event or NO versions of this event. Currently some, but not all, versions of this event are present\n" - - if not stackSupportSpecified.get(eventValue): - # Haven't checked this event before. Remember whether a preference is stated - if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): - stackSupportSpecified[eventValue] = True - else: - stackSupportSpecified[eventValue] = False - else: - # We've checked this event before. - if stackSupportSpecified[eventValue]: - # When we last checked, a preference was previously specified, so it better be specified here - if eventStackBitFromNoStackList and eventStackBitFromExplicitStackList: - raise Exception(sStackSpecificityError) - else: - # When we last checked, a preference was not previously specified, so it better not be specified here - if ( not eventStackBitFromNoStackList) or ( not eventStackBitFromExplicitStackList): - raise Exception(sStackSpecificityError) import argparse import sys @@ -874,28 +781,28 @@ def main(argv): required = parser.add_argument_group('required arguments') required.add_argument('--man', type=str, required=True, help='full path to manifest containig 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=None, help='full path to directory where the header files will be generated') required.add_argument('--dummy', type=str,default=None, help='full path to file that will have dummy definitions of FireEtw functions') required.add_argument('--testdir', type=str, default=None, help='full path to directory where the test assets will be deployed' ) + required.add_argument('--nonextern', action='store_true', + help='if specified, will not generated extern function stub headers' ) args, unknown = parser.parse_known_args(argv) if unknown: print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments + return 1 sClrEtwAllMan = args.man - exclusionListFile = args.exc incdir = args.inc etmDummyFile = args.dummy testDir = args.testdir + extern = not args.nonextern + + generatePlatformIndependentFiles(sClrEtwAllMan, incdir, etmDummyFile, extern) + generateSanityTest(sClrEtwAllMan, testDir) - checkConsistency(sClrEtwAllMan, exclusionListFile) - generatePlformIndependentFiles(sClrEtwAllMan,incdir,etmDummyFile) - generateSanityTest(sClrEtwAllMan,testDir) if __name__ == '__main__': return_code = main(sys.argv[1:]) - sys.exit(return_code) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genXplatLttng.py b/src/scripts/genLttngProvider.py index 9959895f5a..382cb74675 100644 --- a/src/scripts/genXplatLttng.py +++ b/src/scripts/genLttngProvider.py @@ -50,7 +50,8 @@ # import os -from genXplatEventing import * +from genEventing import * +from utilities import open_for_update stdprolog=""" // Licensed to the .NET Foundation under one or more agreements. @@ -60,7 +61,7 @@ stdprolog=""" /****************************************************************** DO NOT MODIFY. AUTOGENERATED FILE. -This file is generated using the logic from <root>/src/scripts/genXplatLttng.py +This file is generated using the logic from <root>/src/scripts/genLttngProvider.py ******************************************************************/ """ @@ -70,7 +71,7 @@ stdprolog_cmake=""" #****************************************************************** #DO NOT MODIFY. AUTOGENERATED FILE. -#This file is generated using the logic from <root>/src/scripts/genXplatLttng.py +#This file is generated using the logic from <root>/src/scripts/genLttngProvider.py #****************************************************************** """ @@ -159,7 +160,7 @@ def generateArgList(template): def generateFieldList(template): header = " " + " TP_FIELDS(\n" footer = "\n )\n)\n" - + if shouldPackTemplate(template): field_list = " ctf_integer(ULONG, length, length)\n" field_list += " ctf_sequence(char, __data__, __data__, ULONG, length)" @@ -209,7 +210,7 @@ def generateLttngHeader(providerName, allTemplates, eventNodes): for templateName in allTemplates: template = allTemplates[templateName] fnSig = allTemplates[templateName].signature - + lTTngHdr.append("\n#define " + templateName + "_TRACEPOINT_ARGS \\\n") #TP_ARGS @@ -289,7 +290,7 @@ def generateMethodBody(template, providerName, eventName): return "\n do_tracepoint(%s, %s);\n" % (providerName, eventName) fnSig = template.signature - + for paramName in fnSig.paramlist: fnparam = fnSig.getParam(paramName) paramname = fnparam.name @@ -298,7 +299,7 @@ def generateMethodBody(template, providerName, eventName): result.append(" INT " + paramname + "_path_size = -1;\n") result.append(" PathCharString " + paramname + "_PS;\n") result.append(" INT " + paramname + "_full_name_path_size") - result.append(" = (PAL_wcslen(" + paramname + ") + 1)*sizeof(WCHAR);\n") + result.append(" = (wcslen(" + paramname + ") + 1)*sizeof(WCHAR);\n") result.append(" CHAR* " + paramname + "_full_name = ") result.append(paramname + "_PS.OpenStringBuffer(" + paramname + "_full_name_path_size );\n") result.append(" if (" + paramname + "_full_name == NULL )") @@ -308,7 +309,7 @@ def generateMethodBody(template, providerName, eventName): #emit tracepoints fnSig = template.signature - + if not shouldPackTemplate(template): linefnbody = [" do_tracepoint(%s,\n %s" % (providerName, eventName)] @@ -360,8 +361,8 @@ def generateMethodBody(template, providerName, eventName): header = """ char stackBuffer[%s]; char *buffer = stackBuffer; - int offset = 0; - int size = %s; + size_t offset = 0; + size_t size = %s; bool fixedBuffer = true; bool success = true; @@ -401,7 +402,7 @@ def generateMethodBody(template, providerName, eventName): do_tracepoint(%s, %s, offset, buffer);\n""" % (providerName, eventName) return header + code + tracepoint + footer - + @@ -420,7 +421,7 @@ def generateLttngTpProvider(providerName, eventNodes, allTemplates): fnptype.append(eventName) fnptype.append("(\n") - + if templateName: template = allTemplates[templateName] else: @@ -489,7 +490,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): os.makedirs(eventprovider_directory + tracepointprovider_directory) #Top level Cmake - with open(eventprovider_directory + "CMakeLists.txt", 'w') as topCmake: + with open_for_update(eventprovider_directory + "CMakeLists.txt") as topCmake: topCmake.write(stdprolog_cmake + "\n") topCmake.write("""cmake_minimum_required(VERSION 2.8.12.2) @@ -514,7 +515,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): providerName_File = providerName_File.lower() topCmake.write(' "%s%s.cpp"\n' % (lttngevntprovPre, providerName_File)) - + topCmake.write(' "%shelpers.cpp"\n' % (lttngevntprovPre,)) topCmake.write(""") add_subdirectory(tracepointprovider) @@ -525,7 +526,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): #TracepointProvider Cmake - with open(eventprovider_directory + tracepointprovider_directory + "/CMakeLists.txt", 'w') as tracepointprovider_Cmake: + with open_for_update(eventprovider_directory + tracepointprovider_directory + "/CMakeLists.txt") as tracepointprovider_Cmake: tracepointprovider_Cmake.write(stdprolog_cmake + "\n") tracepointprovider_Cmake.write("""cmake_minimum_required(VERSION 2.8.12.2) @@ -562,7 +563,7 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): install_clr(coreclrtraceptprovider) """) - with open(eventprovider_directory + lttng_directory + "/eventprovhelpers.cpp", 'w') as helper: + with open_for_update(eventprovider_directory + lttng_directory + "/eventprovhelpers.cpp") as helper: helper.write(""" #include "palrt.h" #include "pal.h" @@ -572,72 +573,81 @@ def generateLttngFiles(etwmanifest,eventprovider_directory): #include <new> #include <memory.h> -bool ResizeBuffer(char *&buffer, int& size, int currLen, int newSize, bool &fixedBuffer) +#define wcslen PAL_wcslen + +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer) { - newSize *= 1.5; - _ASSERTE(newSize > size); // check for overflow + newSize = (size_t)(newSize * 1.5); + _ASSERTE(newSize > size); // check for overflow if (newSize < 32) newSize = 32; - char *newBuffer = new char[newSize]; + // We can't use coreclr includes here so we use std::nothrow + // rather than the coreclr version + char *newBuffer = new (std::nothrow) char[newSize]; - memcpy(newBuffer, buffer, currLen); + if (newBuffer == NULL) + return false; - if (!fixedBuffer) - delete[] buffer; + memcpy(newBuffer, buffer, currLen); - buffer = newBuffer; - size = newSize; - fixedBuffer = false; + if (!fixedBuffer) + delete[] buffer; - return true; + buffer = newBuffer; + size = newSize; + fixedBuffer = false; + + return true; } -bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { - if (!src) return true; - if (offset + len > size) - { - if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) - return false; - } - - memcpy(buffer + offset, src, len); - offset += len; - return true; + if(!src) return true; + if (offset + len > size) + { + if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, src, len); + offset += len; + return true; } -bool WriteToBuffer(PCWSTR str, char *&buffer, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { - if (!str) return true; - int byteCount = (PAL_wcslen(str) + 1) * sizeof(*str); - - if (offset + byteCount > size) - { - if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer)) - return false; - } - - memcpy(buffer + offset, str, byteCount); - offset += byteCount; - return true; + if(!str) return true; + size_t byteCount = (wcslen(str) + 1) * sizeof(*str); + + if (offset + byteCount > size) + { + if (!ResizeBuffer(buffer, size, offset, size + byteCount, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, str, byteCount); + offset += byteCount; + return true; } -bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { - if (!str) return true; - int len = strlen(str) + 1; - if (offset + len > size) - { - if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) - return false; - } - - memcpy(buffer + offset, str, len); - offset += len; - return true; -}""") + if(!str) return true; + size_t len = strlen(str) + 1; + if (offset + len > size) + { + if (!ResizeBuffer(buffer, size, offset, size + len, fixedBuffer)) + return false; + } + + memcpy(buffer + offset, str, len); + offset += len; + return true; +} + +""") # Generate Lttng specific instrumentation for providerNode in tree.getElementsByTagName('provider'): @@ -650,24 +660,19 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool providerName_File = providerName_File.lower() providerName = providerName.replace('-','_') - lttngevntheadershortname = "tp" + providerName_File +".h"; + lttngevntheadershortname = "tp" + providerName_File +".h" lttngevntheader = eventprovider_directory + "lttng/" + lttngevntheadershortname lttngevntprov = eventprovider_directory + lttngevntprovPre + providerName_File + ".cpp" lttngevntprovTp = eventprovider_directory + lttngevntprovTpPre + providerName_File +".cpp" - lTTngHdr = open(lttngevntheader, 'w') - lTTngImpl = open(lttngevntprov, 'w') - lTTngTpImpl = open(lttngevntprovTp, 'w') - - lTTngHdr.write(stdprolog + "\n") - lTTngImpl.write(stdprolog + "\n") - lTTngTpImpl.write(stdprolog + "\n") - - lTTngTpImpl.write("\n#define TRACEPOINT_CREATE_PROBES\n") + templateNodes = providerNode.getElementsByTagName('template') + eventNodes = providerNode.getElementsByTagName('event') + allTemplates = parseTemplateNodes(templateNodes) - lTTngTpImpl.write("#include \"./"+lttngevntheadershortname + "\"\n") - lTTngHdr.write(""" + with open_for_update(lttngevntheader) as lttnghdr_file: + lttnghdr_file.write(stdprolog + "\n") + lttnghdr_file.write(""" #include "palrt.h" #include "pal.h" @@ -675,20 +680,24 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool """) - lTTngHdr.write("#define TRACEPOINT_PROVIDER " + providerName + "\n") - lTTngHdr.write(""" + lttnghdr_file.write("#define TRACEPOINT_PROVIDER " + providerName + "\n") + lttnghdr_file.write(""" #undef TRACEPOINT_INCLUDE """) - lTTngHdr.write("#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n\n") + lttnghdr_file.write("#define TRACEPOINT_INCLUDE \"./" + lttngevntheadershortname + "\"\n\n") + + lttnghdr_file.write("#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n") + lttnghdr_file.write("#define LTTNG_CORECLR_H" + providerName + "\n") - lTTngHdr.write("#if !defined(LTTNG_CORECLR_H" + providerName + ") || defined(TRACEPOINT_HEADER_MULTI_READ)\n\n") - lTTngHdr.write("#define LTTNG_CORECLR_H" + providerName + "\n") + lttnghdr_file.write("\n#include <lttng/tracepoint.h>\n\n") - lTTngHdr.write("\n#include <lttng/tracepoint.h>\n\n") + lttnghdr_file.write(generateLttngHeader(providerName,allTemplates,eventNodes) + "\n") - lTTngImpl.write(""" + with open_for_update(lttngevntprov) as lttngimpl_file: + lttngimpl_file.write(stdprolog + "\n") + lttngimpl_file.write(""" #define TRACEPOINT_DEFINE #define TRACEPOINT_PROBE_DYNAMIC_LINKAGE @@ -700,48 +709,43 @@ bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool #define PAL_realloc realloc #include "pal/stackstring.hpp" """) - lTTngImpl.write("#include \"" + lttngevntheadershortname + "\"\n\n") + lttngimpl_file.write("#include \"" + lttngevntheadershortname + "\"\n\n") - lTTngImpl.write("""#ifndef tracepoint_enabled + lttngimpl_file.write("""#ifndef tracepoint_enabled #define tracepoint_enabled(provider, name) TRUE #define do_tracepoint tracepoint #endif +#define wcslen PAL_wcslen -bool ResizeBuffer(char *&buffer, int& size, int currLen, int newSize, bool &fixedBuffer); -bool WriteToBuffer(PCWSTR str, char *&buffer, int& offset, int& size, bool &fixedBuffer); -bool WriteToBuffer(const char *str, char *&buffer, int& offset, int& size, bool &fixedBuffer); -bool WriteToBuffer(const BYTE *src, int len, char *&buffer, int& offset, int& size, bool &fixedBuffer); +bool ResizeBuffer(char *&buffer, size_t& size, size_t currLen, size_t newSize, bool &fixedBuffer); +bool WriteToBuffer(PCWSTR str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const char *str, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); +bool WriteToBuffer(const BYTE *src, size_t len, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer); template <typename T> -bool WriteToBuffer(const T &value, char *&buffer, int& offset, int& size, bool &fixedBuffer) +bool WriteToBuffer(const T &value, char *&buffer, size_t& offset, size_t& size, bool &fixedBuffer) { - if (sizeof(T) + offset > size) - { - if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) - return false; - } - - *(T *)(buffer + offset) = value; - offset += sizeof(T); - return true; + if (sizeof(T) + offset > size) + { + if (!ResizeBuffer(buffer, size, offset, size + sizeof(T), fixedBuffer)) + return false; + } + + *(T *)(buffer + offset) = value; + offset += sizeof(T); + return true; } """) + lttngimpl_file.write(generateLttngTpProvider(providerName,eventNodes,allTemplates) + "\n") - templateNodes = providerNode.getElementsByTagName('template') - eventNodes = providerNode.getElementsByTagName('event') - - allTemplates = parseTemplateNodes(templateNodes) - #generate the header - lTTngHdr.write(generateLttngHeader(providerName,allTemplates,eventNodes) + "\n") + with open_for_update(lttngevntprovTp) as tpimpl_file: + tpimpl_file.write(stdprolog + "\n") - #create the implementation of eventing functions : lttngeventprov*.cp - lTTngImpl.write(generateLttngTpProvider(providerName,eventNodes,allTemplates) + "\n") + tpimpl_file.write("\n#define TRACEPOINT_CREATE_PROBES\n") - lTTngHdr.close() - lTTngImpl.close() - lTTngTpImpl.close() + tpimpl_file.write("#include \"./"+lttngevntheadershortname + "\"\n") import argparse import sys @@ -759,7 +763,7 @@ def main(argv): args, unknown = parser.parse_known_args(argv) if unknown: print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments + return 1 sClrEtwAllMan = args.man intermediate = args.intermediate @@ -768,4 +772,4 @@ def main(argv): if __name__ == '__main__': return_code = main(sys.argv[1:]) - sys.exit(return_code) + sys.exit(return_code)
\ No newline at end of file diff --git a/src/scripts/genWinEtw.py b/src/scripts/genWinEtw.py deleted file mode 100644 index aa75f680cd..0000000000 --- a/src/scripts/genWinEtw.py +++ /dev/null @@ -1,125 +0,0 @@ - -## Licensed to the .NET Foundation under one or more agreements. -## The .NET Foundation licenses this file to you under the MIT license. -## See the LICENSE file in the project root for more information. -# - -import os -from genXplatEventing import * - -stdprolog=""" -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -/****************************************************************** - -DO NOT MODIFY. AUTOGENERATED FILE. -This file is generated using the logic from <root>/src/scripts/genWinEtw.py - -******************************************************************/ - -""" -import argparse -import sys -import xml.dom.minidom as DOM - -def generateEtwMacroHeader(sClrEtwAllMan, sExcludeFile,macroHeader,inHeader): - tree = DOM.parse(sClrEtwAllMan) - numOfProviders = len(tree.getElementsByTagName('provider')) - nMaxEventBytesPerProvider = 64 - - exclusionInfo = parseExclusionList(sExcludeFile) - incDir = os.path.dirname(os.path.realpath(macroHeader)) - if not os.path.exists(incDir): - os.makedirs(incDir) - - outHeader = open(macroHeader,'w') - outHeader.write(stdprolog + "\n") - - outHeader.write("#include \"" + os.path.basename(inHeader) + '"\n') - outHeader.write("#define NO_OF_ETW_PROVIDERS " + str(numOfProviders) + "\n") - outHeader.write("#define MAX_BYTES_PER_ETW_PROVIDER " + str(nMaxEventBytesPerProvider) + "\n") - outHeader.write("EXTERN_C __declspec(selectany) const BYTE etwStackSupportedEvents[NO_OF_ETW_PROVIDERS][MAX_BYTES_PER_ETW_PROVIDER] = \n{\n") - - for providerNode in tree.getElementsByTagName('provider'): - stackSupportedEvents = [0]*nMaxEventBytesPerProvider - eventNodes = providerNode.getElementsByTagName('event') - eventProvider = providerNode.getAttribute('name') - - for eventNode in eventNodes: - taskName = eventNode.getAttribute('task') - eventSymbol = eventNode.getAttribute('symbol') - eventTemplate = eventNode.getAttribute('template') - eventTemplate = eventNode.getAttribute('template') - eventValue = int(eventNode.getAttribute('value')) - eventIndex = eventValue // 8 - eventBitPositionInIndex = eventValue % 8 - - eventStackBitFromNoStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.nostack)) - eventStackBitFromExplicitStackList = int(getStackWalkBit(eventProvider, taskName, eventSymbol, exclusionInfo.explicitstack)) - - # Shift those bits into position. For the explicit stack list, swap 0 and 1, so the eventValue* variables - # have 1 in the position iff we should issue a stack for the event. - eventValueUsingNoStackListByPosition = (eventStackBitFromNoStackList << eventBitPositionInIndex) - eventValueUsingExplicitStackListByPosition = ((1 - eventStackBitFromExplicitStackList) << eventBitPositionInIndex) - - # Commit the values to the in-memory array that we'll dump into the header file - stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingNoStackListByPosition; - if eventStackBitFromExplicitStackList == 0: - stackSupportedEvents[eventIndex] = stackSupportedEvents[eventIndex] | eventValueUsingExplicitStackListByPosition - - # print the bit array - line = [] - line.append("\t{") - for elem in stackSupportedEvents: - line.append(str(elem)) - line.append(", ") - - del line[-1] - line.append("},") - outHeader.write(''.join(line) + "\n") - outHeader.write("};\n") - - outHeader.close() - - -def generateEtwFiles(sClrEtwAllMan, exclusionListFile, etmdummyHeader, macroHeader, inHeader): - - checkConsistency(sClrEtwAllMan, exclusionListFile) - generateEtmDummyHeader(sClrEtwAllMan, etmdummyHeader) - generateEtwMacroHeader(sClrEtwAllMan, exclusionListFile, macroHeader, inHeader) - -def main(argv): - - #parse the command line - parser = argparse.ArgumentParser(description="Generates the Code required to instrument LTTtng logging mechanism") - - required = parser.add_argument_group('required arguments') - required.add_argument('--man', type=str, required=True, - help='full path to manifest containig the description of events') - required.add_argument('--exc', type=str, required=True, - help='full path to exclusion list') - required.add_argument('--eventheader', type=str, required=True, - help='full path to the header file') - required.add_argument('--macroheader', type=str, required=True, - help='full path to the macro header file') - required.add_argument('--dummy', type=str, required=True, - help='full path to file that will have dummy definitions of FireEtw functions') - - args, unknown = parser.parse_known_args(argv) - if unknown: - print('Unknown argument(s): ', ', '.join(unknown)) - return const.UnknownArguments - - sClrEtwAllMan = args.man - exclusionListFile = args.exc - inHeader = args.eventheader - macroHeader = args.macroheader - etmdummyHeader = args.dummy - - generateEtwFiles(sClrEtwAllMan, exclusionListFile, etmdummyHeader, macroHeader, inHeader) - -if __name__ == '__main__': - return_code = main(sys.argv[1:]) - sys.exit(return_code) diff --git a/src/scripts/utilities.py b/src/scripts/utilities.py new file mode 100644 index 0000000000..6898bb7542 --- /dev/null +++ b/src/scripts/utilities.py @@ -0,0 +1,106 @@ +from filecmp import dircmp +from hashlib import sha256 +from io import StringIO +import shutil +import os + +class WrappedStringIO(StringIO): + """A wrapper around StringIO to allow writing str objects""" + def write(self, s): + if isinstance(s, str): + s = unicode(s) + super(WrappedStringIO, self).write(s) + +class UpdateFileWriter: + """A file-like context object which will only write to a file if the result would be different + + Attributes: + filename (str): The name of the file to update + stream (WrappedStringIO): The file-like stream provided upon context enter + + Args: + filename (str): Sets the filename attribute + """ + filemode = 'w' + + def __init__(self, filename): + self.filename = filename + self.stream = None + + def __enter__(self): + self.stream = WrappedStringIO() + return self.stream + + def __exit__(self, exc_type, exc_value, traceback): + if exc_value is None: + new_content = self.stream.getvalue() + new_hash = sha256() + cur_hash = sha256() + + try: + with open(self.filename, 'r') as fstream: + cur_hash.update(fstream.read()) + file_found = True + except IOError: + file_found = False + + if file_found: + new_hash.update(new_content) + update = new_hash.digest() != cur_hash.digest() + else: + update = True + + if update: + with open(self.filename, 'w') as fstream: + fstream.write(new_content) + + self.stream.close() + +def open_for_update(filename): + return UpdateFileWriter(filename) + +def walk_recursively_and_update(dcmp): + #for different Files Copy from right to left + for name in dcmp.diff_files: + srcpath = dcmp.right + "/" + name + destpath = dcmp.left + "/" + name + print("Updating %s" % (destpath)) + if os.path.isfile(srcpath): + shutil.copyfile(srcpath, destpath) + else : + raise Exception("path: " + srcpath + "is neither a file or folder") + + #copy right only files + for name in dcmp.right_only: + srcpath = dcmp.right + "/" + name + destpath = dcmp.left + "/" + name + print("Updating %s" % (destpath)) + if os.path.isfile(srcpath): + shutil.copyfile(srcpath, destpath) + elif os.path.isdir(srcpath): + shutil.copytree(srcpath, destpath) + else : + raise Exception("path: " + srcpath + "is neither a file or folder") + + #delete left only files + for name in dcmp.left_only: + path = dcmp.left + "/" + name + print("Deleting %s" % (path)) + if os.path.isfile(path): + os.remove(path) + elif os.path.isdir(path): + shutil.rmtree(path) + else : + raise Exception("path: " + path + "is neither a file or folder") + + #call recursively + for sub_dcmp in dcmp.subdirs.values(): + walk_recursively_and_update(sub_dcmp) + +def UpdateDirectory(destpath,srcpath): + + print("Updating %s with %s" % (destpath,srcpath)) + if not os.path.exists(destpath): + os.makedirs(destpath) + dcmp = dircmp(destpath,srcpath) + walk_recursively_and_update(dcmp) diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index f49d01bc91..97ab656f81 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -1,7 +1,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) # Needed due to the cmunged files being in the binary folders, the set(CMAKE_INCLUDE_CURRENT_DIR ON) is not enough -include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${ARCH_SOURCES_DIR}) add_definitions(-DUNICODE) @@ -9,7 +9,7 @@ add_definitions(-D_UNICODE) if(CMAKE_CONFIGURATION_TYPES) # multi-configuration generator? - foreach (Config DEBUG CHECKED) + foreach (Config DEBUG CHECKED) set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:${Config}>:WRITE_BARRIER_CHECK=1>) endforeach (Config) else() @@ -291,7 +291,7 @@ set(VM_SOURCES_DAC_AND_WKS_WIN32 winrttypenameconverter.cpp ) -list(APPEND VM_SOURCES_WKS +list(APPEND VM_SOURCES_WKS ${VM_SOURCES_DAC_AND_WKS_WIN32} # These should not be included for Linux appxutil.cpp @@ -313,17 +313,17 @@ list(APPEND VM_SOURCES_WKS extensibleclassfactory.cpp mngstdinterfaces.cpp notifyexternals.cpp - olecontexthelpers.cpp + olecontexthelpers.cpp rcwrefcache.cpp rtlfunctions.cpp runtimecallablewrapper.cpp stacksampler.cpp stdinterfaces.cpp stdinterfaces_wrapper.cpp - winrthelpers.cpp + winrthelpers.cpp ) -list(APPEND VM_SOURCES_DAC +list(APPEND VM_SOURCES_DAC ${VM_SOURCES_DAC_AND_WKS_WIN32} # These should not be included for Linux clrprivbinderwinrt.cpp @@ -423,7 +423,7 @@ else(WIN32) ${ARCH_SOURCES_DIR}/pinvokestubs.S ) endif() - + endif(WIN32) @@ -434,7 +434,7 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64) ${ARCH_SOURCES_DIR}/gmsamd64.cpp ${ARCH_SOURCES_DIR}/stublinkeramd64.cpp ) - + set(VM_SOURCES_WKS_ARCH ${ARCH_SOURCES_DIR}/jithelpersamd64.cpp ${ARCH_SOURCES_DIR}/jitinterfaceamd64.cpp @@ -452,7 +452,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_I386) ${ARCH_SOURCES_DIR}/gmsx86.cpp ${ARCH_SOURCES_DIR}/stublinkerx86.cpp ) - + set(VM_SOURCES_WKS_ARCH ${ARCH_SOURCES_DIR}/jitinterfacex86.cpp ${ARCH_SOURCES_DIR}/profiler.cpp @@ -465,7 +465,7 @@ elseif(CLR_CMAKE_TARGET_ARCH_ARM) ${ARCH_SOURCES_DIR}/stubs.cpp ${ARCH_SOURCES_DIR}/armsinglestepper.cpp ) - + set(VM_SOURCES_WKS_ARCH ${ARCH_SOURCES_DIR}/jithelpersarm.cpp ${ARCH_SOURCES_DIR}/profiler.cpp @@ -492,7 +492,7 @@ set(VM_SOURCES_DAC_ARCH exceptionhandling.cpp ) -list(APPEND VM_SOURCES_WKS +list(APPEND VM_SOURCES_WKS ${VM_SOURCES_WKS_ARCH} ${VM_SOURCES_DAC_AND_WKS_ARCH} ) @@ -519,6 +519,6 @@ convert_to_absolute_path(VM_SOURCES_DAC ${VM_SOURCES_DAC}) add_subdirectory(dac) add_subdirectory(wks) -if(CLR_CMAKE_PLATFORM_LINUX) - add_subdirectory($ENV{__IntermediatesDir}/Generated/eventpipe ${CMAKE_CURRENT_BINARY_DIR}/eventpipe) -endif(CLR_CMAKE_PLATFORM_LINUX) +if(FEATURE_PERFTRACING) + add_subdirectory(${GENERATED_EVENTING_DIR}/eventpipe ${CMAKE_CURRENT_BINARY_DIR}/eventpipe) +endif(FEATURE_PERFTRACING)
\ No newline at end of file diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp index 8f2e8ff937..37de4c3b36 100644 --- a/src/vm/eventpipe.cpp +++ b/src/vm/eventpipe.cpp @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#include "common.h" #include "clrtypes.h" #include "safemath.h" -#include "common.h" #include "eventpipe.h" #include "eventpipebuffermanager.h" #include "eventpipeconfiguration.h" @@ -33,11 +33,8 @@ EventPipeJsonFile* EventPipe::s_pJsonFile = NULL; #ifdef FEATURE_PAL // This function is auto-generated from /src/scripts/genEventPipe.py extern "C" void InitProvidersAndEvents(); -#endif - -#ifdef FEATURE_PAL -// This function is auto-generated from /src/scripts/genEventPipe.py -extern "C" void InitProvidersAndEvents(); +#else +void InitProvidersAndEvents(); #endif EventPipeEventPayload::EventPipeEventPayload(BYTE *pData, unsigned int length) @@ -97,7 +94,7 @@ EventPipeEventPayload::~EventPipeEventPayload() CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -114,7 +111,7 @@ void EventPipeEventPayload::Flatten() CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -168,7 +165,7 @@ BYTE* EventPipeEventPayload::GetFlatData() CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -193,11 +190,9 @@ void EventPipe::Initialize() s_pBufferManager = new EventPipeBufferManager(); -#ifdef FEATURE_PAL // This calls into auto-generated code to initialize the runtime providers // and events so that the EventPipe configuration lock isn't taken at runtime InitProvidersAndEvents(); -#endif } void EventPipe::EnableOnStartup() @@ -227,13 +222,19 @@ void EventPipe::Shutdown() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; - Disable(); + // We are shutting down, so if diasabling EventPipe throws, we need to move along anyway + EX_TRY + { + Disable(); + } + EX_CATCH { } + EX_END_CATCH(SwallowAllExceptions); if(s_pConfig != NULL) { @@ -262,7 +263,13 @@ void EventPipe::Enable( CONTRACTL_END; // If tracing is not initialized or is already enabled, bail here. - if(!s_tracingInitialized || s_pConfig->Enabled()) + if(!s_tracingInitialized || s_pConfig == NULL || s_pConfig->Enabled()) + { + return; + } + + // If the state or aurguments are invalid, bail + if(pProviders == NULL || numProviders <= 0) { return; } @@ -312,7 +319,7 @@ void EventPipe::Disable() // Take the lock before disabling tracing. CrstHolder _crst(GetLock()); - if(s_pConfig->Enabled()) + if(s_pConfig != NULL && s_pConfig->Enabled()) { // Disable the profiler. SampleProfiler::Disable(); @@ -468,7 +475,6 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload NOTHROW; GC_NOTRIGGER; MODE_ANY; - PRECONDITION(s_pBufferManager != NULL); } CONTRACTL_END; @@ -486,6 +492,12 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload return; } + if(s_pConfig == NULL) + { + // We can't procede without a configuration + return; + } + if(!s_pConfig->RundownEnabled() && s_pBufferManager != NULL) { if(!s_pBufferManager->WriteEvent(pThread, event, payload, pActivityId, pRelatedActivityId)) @@ -501,6 +513,10 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload { // Write synchronously to the file. // We're under lock and blocking the disabling thread. + // This copy occurs here (rather than at file write) because + // A) The FastSerializer API would need to change if we waited + // B) It is unclear there is a benefit to multiple file write calls + // as opposed a a buffer copy here EventPipeEventInstance instance( event, pThread->GetOSThreadId(), @@ -511,12 +527,22 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload if(s_pFile != NULL) { - s_pFile->WriteEvent(instance); + // EventPipeFile::WriteEvent needs to allocate a metadata event + // and can therefore throw. In this context we will silently + // fail rather than disrupt the caller + EX_TRY + { + s_pFile->WriteEvent(instance); + } + EX_CATCH { } + EX_END_CATCH(SwallowAllExceptions); } } } -#ifdef _DEBUG +// This section requires a call to GCX_PREEMP which violates the GC_NOTRIGGER contract +// It should only be enabled when debugging this specific component and contracts are off +#ifdef DEBUG_JSON_EVENT_FILE { GCX_PREEMP(); @@ -537,7 +563,7 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload { s_pSyncFile->WriteEvent(instance); } - + // Write to the EventPipeJsonFile if it exists. if(s_pJsonFile != NULL) { @@ -545,7 +571,7 @@ void EventPipe::WriteEventInternal(EventPipeEvent &event, EventPipeEventPayload } } } -#endif // _DEBUG +#endif // DEBUG_JSON_EVENT_FILE } void EventPipe::WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData, unsigned int length) @@ -641,7 +667,7 @@ StackWalkAction EventPipe::StackWalkCallback(CrawlFrame *pCf, StackContents *pDa { NOTHROW; GC_NOTRIGGER; - MODE_PREEMPTIVE; + MODE_ANY; PRECONDITION(pCf != NULL); PRECONDITION(pData != NULL); } @@ -686,15 +712,15 @@ CrstStatic* EventPipe::GetLock() void QCALLTYPE EventPipeInternal::Enable( __in_z LPCWSTR outputFile, - unsigned int circularBufferSizeInMB, - long profilerSamplingRateInNanoseconds, + UINT32 circularBufferSizeInMB, + INT64 profilerSamplingRateInNanoseconds, EventPipeProviderConfiguration *pProviders, - int numProviders) + INT32 numProviders) { QCALL_CONTRACT; BEGIN_QCALL; - SampleProfiler::SetSamplingRate(profilerSamplingRateInNanoseconds); + SampleProfiler::SetSamplingRate((unsigned long)profilerSamplingRateInNanoseconds); EventPipe::Enable(outputFile, circularBufferSizeInMB, pProviders, numProviders); END_QCALL; } @@ -727,12 +753,12 @@ INT_PTR QCALLTYPE EventPipeInternal::CreateProvider( INT_PTR QCALLTYPE EventPipeInternal::DefineEvent( INT_PTR provHandle, - unsigned int eventID, + UINT32 eventID, __int64 keywords, - unsigned int eventVersion, - unsigned int level, + UINT32 eventVersion, + UINT32 level, void *pMetadata, - unsigned int metadataLength) + UINT32 metadataLength) { QCALL_CONTRACT; @@ -768,9 +794,9 @@ void QCALLTYPE EventPipeInternal::DeleteProvider( void QCALLTYPE EventPipeInternal::WriteEvent( INT_PTR eventHandle, - unsigned int eventID, + UINT32 eventID, void *pData, - unsigned int length, + UINT32 length, LPCGUID pActivityId, LPCGUID pRelatedActivityId) { @@ -786,9 +812,9 @@ void QCALLTYPE EventPipeInternal::WriteEvent( void QCALLTYPE EventPipeInternal::WriteEventData( INT_PTR eventHandle, - unsigned int eventID, + UINT32 eventID, EventData **pEventData, - unsigned int eventDataCount, + UINT32 eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId) { diff --git a/src/vm/eventpipe.h b/src/vm/eventpipe.h index bac7be6ac8..4fd3d88127 100644 --- a/src/vm/eventpipe.h +++ b/src/vm/eventpipe.h @@ -6,8 +6,10 @@ #define __EVENTPIPE_H__ #ifdef FEATURE_PERFTRACING +#include "common.h" class CrstStatic; +class CrawlFrame; class EventPipeConfiguration; class EventPipeEvent; class EventPipeFile; @@ -58,7 +60,7 @@ public: // If a buffer was allocated internally, delete it ~EventPipeEventPayload(); - + // Copy the data (whether flat or array of objects) into a flat buffer at pDst // Assumes that pDst points to an appropriatly sized buffer void CopyData(BYTE *pDst); @@ -259,7 +261,7 @@ class EventPipe // Write out a sample profile event. static void WriteSampleProfileEvent(Thread *pSamplingThread, EventPipeEvent *pEvent, Thread *pTargetThread, StackContents &stackContents, BYTE *pData = NULL, unsigned int length = 0); - + // Get the managed call stack for the current thread. static bool WalkManagedStackForCurrentThread(StackContents &stackContents); @@ -301,7 +303,7 @@ private: LPCWSTR m_pProviderName; UINT64 m_keywords; - unsigned int m_loggingLevel; + UINT32 m_loggingLevel; public: @@ -316,7 +318,7 @@ public: EventPipeProviderConfiguration( LPCWSTR pProviderName, UINT64 keywords, - unsigned int loggingLevel) + UINT32 loggingLevel) { LIMITED_METHOD_CONTRACT; m_pProviderName = pProviderName; @@ -336,7 +338,7 @@ public: return m_keywords; } - unsigned int GetLevel() const + UINT32 GetLevel() const { LIMITED_METHOD_CONTRACT; return m_loggingLevel; @@ -350,10 +352,10 @@ public: static void QCALLTYPE Enable( __in_z LPCWSTR outputFile, - unsigned int circularBufferSizeInMB, - long profilerSamplingRateInNanoseconds, + UINT32 circularBufferSizeInMB, + INT64 profilerSamplingRateInNanoseconds, EventPipeProviderConfiguration *pProviders, - int numProviders); + INT32 numProviders); static void QCALLTYPE Disable(); @@ -363,28 +365,28 @@ public: static INT_PTR QCALLTYPE DefineEvent( INT_PTR provHandle, - unsigned int eventID, + UINT32 eventID, __int64 keywords, - unsigned int eventVersion, - unsigned int level, + UINT32 eventVersion, + UINT32 level, void *pMetadata, - unsigned int metadataLength); + UINT32 metadataLength); static void QCALLTYPE DeleteProvider( INT_PTR provHandle); static void QCALLTYPE WriteEvent( INT_PTR eventHandle, - unsigned int eventID, + UINT32 eventID, void *pData, - unsigned int length, + UINT32 length, LPCGUID pActivityId, LPCGUID pRelatedActivityId); static void QCALLTYPE WriteEventData( INT_PTR eventHandle, - unsigned int eventID, + UINT32 eventID, EventData **pEventData, - unsigned int eventDataCount, + UINT32 eventDataCount, LPCGUID pActivityId, LPCGUID pRelatedActivityId); }; diff --git a/src/vm/eventpipebuffer.cpp b/src/vm/eventpipebuffer.cpp index 80b4a4f1b7..407c875fa6 100644 --- a/src/vm/eventpipebuffer.cpp +++ b/src/vm/eventpipebuffer.cpp @@ -35,7 +35,7 @@ EventPipeBuffer::~EventPipeBuffer() { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_ANY; } @@ -52,7 +52,7 @@ bool EventPipeBuffer::WriteEvent(Thread *pThread, EventPipeEvent &event, EventPi CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; PRECONDITION(pThread != NULL); } @@ -143,7 +143,7 @@ EventPipeEventInstance* EventPipeBuffer::GetNext(EventPipeEventInstance *pEvent, CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; diff --git a/src/vm/eventpipebuffermanager.cpp b/src/vm/eventpipebuffermanager.cpp index e7d97d5732..045e1d999a 100644 --- a/src/vm/eventpipebuffermanager.cpp +++ b/src/vm/eventpipebuffermanager.cpp @@ -37,7 +37,7 @@ EventPipeBufferManager::~EventPipeBufferManager() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -80,7 +80,7 @@ EventPipeBuffer* EventPipeBufferManager::AllocateBufferForThread(Thread *pThread { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(pThread != NULL); @@ -97,8 +97,19 @@ EventPipeBuffer* EventPipeBufferManager::AllocateBufferForThread(Thread *pThread EventPipeBufferList *pThreadBufferList = pThread->GetEventPipeBufferList(); if(pThreadBufferList == NULL) { - pThreadBufferList = new EventPipeBufferList(this); - m_pPerThreadBufferList->InsertTail(new SListElem<EventPipeBufferList*>(pThreadBufferList)); + pThreadBufferList = new (nothrow) EventPipeBufferList(this); + if (pThreadBufferList == NULL) + { + return NULL; + } + + SListElem<EventPipeBufferList*> *pElem = new (nothrow) SListElem<EventPipeBufferList*>(pThreadBufferList); + if (pElem == NULL) + { + return NULL; + } + + m_pPerThreadBufferList->InsertTail(pElem); pThread->SetEventPipeBufferList(pThreadBufferList); allocateNewBuffer = true; } @@ -181,7 +192,24 @@ EventPipeBuffer* EventPipeBufferManager::AllocateBufferForThread(Thread *pThread bufferSize = requestSize; } - pNewBuffer = new EventPipeBuffer(bufferSize); + // EX_TRY is used here as opposed to new (nothrow) because + // the constructor also allocates a private buffer, which + // could throw, and cannot be easily checked + EX_TRY + { + pNewBuffer = new EventPipeBuffer(bufferSize); + } + EX_CATCH + { + pNewBuffer = NULL; + } + EX_END_CATCH(SwallowAllExceptions); + + if (pNewBuffer == NULL) + { + return NULL; + } + m_sizeOfAllBuffers += bufferSize; #ifdef _DEBUG m_numBuffersAllocated++; @@ -202,7 +230,7 @@ EventPipeBufferList* EventPipeBufferManager::FindThreadToStealFrom() { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_ANY; PRECONDITION(m_lock.OwnedByCurrentThread()); @@ -362,7 +390,7 @@ void EventPipeBufferManager::WriteAllBuffersToFile(EventPipeFile *pFile, LARGE_I { CONTRACTL { - NOTHROW; + THROWS; GC_NOTRIGGER; MODE_ANY; PRECONDITION(pFile != NULL); diff --git a/src/vm/eventpipeconfiguration.cpp b/src/vm/eventpipeconfiguration.cpp index ae1dd4e099..a74bdbc28f 100644 --- a/src/vm/eventpipeconfiguration.cpp +++ b/src/vm/eventpipeconfiguration.cpp @@ -20,6 +20,7 @@ EventPipeConfiguration::EventPipeConfiguration() m_rundownEnabled = false; m_circularBufferSizeInBytes = 1024 * 1024 * 1000; // Default to 1000MB. m_pEnabledProviderList = NULL; + m_pConfigProvider = NULL; m_pProviderList = new SList<SListElem<EventPipeProvider*>>(); } @@ -27,7 +28,7 @@ EventPipeConfiguration::~EventPipeConfiguration() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -35,8 +36,15 @@ EventPipeConfiguration::~EventPipeConfiguration() if(m_pConfigProvider != NULL) { - delete(m_pConfigProvider); - m_pConfigProvider = NULL; + // This unregisters the provider, which takes a + // HOST_BREAKABLE lock + EX_TRY + { + DeleteProvider(m_pConfigProvider); + m_pConfigProvider = NULL; + } + EX_CATCH { } + EX_END_CATCH(SwallowAllExceptions); } if(m_pEnabledProviderList != NULL) @@ -47,19 +55,28 @@ EventPipeConfiguration::~EventPipeConfiguration() if(m_pProviderList != NULL) { - // Take the lock before manipulating the provider list. - CrstHolder _crst(EventPipe::GetLock()); - - SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead(); - while(pElem != NULL) + // We swallow exceptions here because the HOST_BREAKABLE + // lock may throw and this destructor gets called in throw + // intolerant places. If that happens the provider list will leak + EX_TRY { - // We don't delete provider itself because it can be in-use - SListElem<EventPipeProvider*> *pCurElem = pElem; - pElem = m_pProviderList->GetNext(pElem); - delete(pCurElem); + // Take the lock before manipulating the list. + CrstHolder _crst(EventPipe::GetLock()); + + SListElem<EventPipeProvider*> *pElem = m_pProviderList->GetHead(); + while(pElem != NULL) + { + // We don't delete provider itself because it can be in-use + SListElem<EventPipeProvider*> *pCurElem = pElem; + pElem = m_pProviderList->GetNext(pElem); + delete(pCurElem); + } + + delete(m_pProviderList); } + EX_CATCH { } + EX_END_CATCH(SwallowAllExceptions); - delete(m_pProviderList); m_pProviderList = NULL; } } @@ -110,7 +127,7 @@ void EventPipeConfiguration::DeleteProvider(EventPipeProvider *pProvider) CONTRACTL { THROWS; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; PRECONDITION(pProvider != NULL); } @@ -177,7 +194,7 @@ bool EventPipeConfiguration::UnregisterProvider(EventPipeProvider &provider) CONTRACTL { THROWS; - GC_NOTRIGGER; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; @@ -271,7 +288,7 @@ size_t EventPipeConfiguration::GetCircularBufferSize() const void EventPipeConfiguration::SetCircularBufferSize(size_t circularBufferSize) { LIMITED_METHOD_CONTRACT; - + if(!m_enabled) { m_circularBufferSizeInBytes = circularBufferSize; @@ -484,9 +501,7 @@ void EventPipeConfiguration::DeleteDeferredProviders() pElem = m_pProviderList->GetNext(pElem); if(pProvider->GetDeleteDeferred()) { - // The act of deleting the provider unregisters it, - // removes it from the list, and deletes the list element - delete(pProvider); + DeleteProvider(pProvider); } } } @@ -525,7 +540,7 @@ EventPipeEnabledProviderList::EventPipeEnabledProviderList( } m_pProviders = new EventPipeEnabledProvider[m_numProviders]; - for(int i=0; i<m_numProviders; i++) + for(unsigned int i=0; i<m_numProviders; i++) { m_pProviders[i].Set( pConfigs[i].GetProviderName(), @@ -538,7 +553,7 @@ EventPipeEnabledProviderList::~EventPipeEnabledProviderList() { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_ANY; } @@ -582,7 +597,7 @@ EventPipeEnabledProvider* EventPipeEnabledProviderList::GetEnabledProvider( LPCWSTR providerName = providerNameStr.GetUnicode(); EventPipeEnabledProvider *pEnabledProvider = NULL; - for(int i=0; i<m_numProviders; i++) + for(unsigned int i=0; i<m_numProviders; i++) { EventPipeEnabledProvider *pCandidate = &m_pProviders[i]; if(pCandidate != NULL) @@ -609,7 +624,7 @@ EventPipeEnabledProvider::~EventPipeEnabledProvider() { CONTRACTL { - THROWS; + NOTHROW; GC_NOTRIGGER; MODE_ANY; } @@ -640,7 +655,7 @@ void EventPipeEnabledProvider::Set(LPCWSTR providerName, UINT64 keywords, EventP if(providerName != NULL) { - unsigned int bufSize = wcslen(providerName) + 1; + size_t bufSize = wcslen(providerName) + 1; m_pProviderName = new WCHAR[bufSize]; wcscpy_s(m_pProviderName, bufSize, providerName); } diff --git a/src/vm/eventpipeevent.cpp b/src/vm/eventpipeevent.cpp index abf942b253..1b2d4ebe40 100644 --- a/src/vm/eventpipeevent.cpp +++ b/src/vm/eventpipeevent.cpp @@ -40,6 +40,14 @@ EventPipeEvent::EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsi EventPipeEvent::~EventPipeEvent() { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + if (m_pMetadata != NULL) { delete[] m_pMetadata; diff --git a/src/vm/eventpipeeventinstance.cpp b/src/vm/eventpipeeventinstance.cpp index 305b6dac04..6cb7438639 100644 --- a/src/vm/eventpipeeventinstance.cpp +++ b/src/vm/eventpipeeventinstance.cpp @@ -20,8 +20,8 @@ EventPipeEventInstance::EventPipeEventInstance( { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -102,8 +102,8 @@ void EventPipeEventInstance::FastSerialize(FastSerializer *pSerializer, StreamLa { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; diff --git a/src/vm/eventpipefile.cpp b/src/vm/eventpipefile.cpp index 26e04480ee..ba4eb39b29 100644 --- a/src/vm/eventpipefile.cpp +++ b/src/vm/eventpipefile.cpp @@ -62,7 +62,7 @@ EventPipeFile::~EventPipeFile() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -87,7 +87,7 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance) CONTRACTL { THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -126,8 +126,8 @@ StreamLabel EventPipeFile::GetMetadataLabel(EventPipeEvent &event) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_ANY; } CONTRACTL_END; @@ -147,7 +147,7 @@ void EventPipeFile::SaveMetadataLabel(EventPipeEvent &event, StreamLabel label) CONTRACTL { THROWS; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_ANY; PRECONDITION(label > 0); } diff --git a/src/vm/eventpipejsonfile.cpp b/src/vm/eventpipejsonfile.cpp index 2edd6f4366..aa60df7b07 100644 --- a/src/vm/eventpipejsonfile.cpp +++ b/src/vm/eventpipejsonfile.cpp @@ -38,7 +38,7 @@ EventPipeJsonFile::~EventPipeJsonFile() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -59,14 +59,26 @@ EventPipeJsonFile::~EventPipeJsonFile() void EventPipeJsonFile::WriteEvent(EventPipeEventInstance &instance) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; instance.SerializeToJsonFile(this); } void EventPipeJsonFile::WriteEvent(LARGE_INTEGER timeStamp, DWORD threadID, SString &message, StackContents &stackContents) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; if(m_pFileStream == NULL || m_writeErrorEncountered) { @@ -98,7 +110,7 @@ void EventPipeJsonFile::Write(SString &str) { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -106,19 +118,35 @@ void EventPipeJsonFile::Write(SString &str) StackScratchBuffer scratch; const char * charStr = str.GetANSI(scratch); - ULONG inCount = str.GetCount(); - ULONG outCount; - m_pFileStream->Write(charStr, inCount, &outCount); - if(inCount != outCount) + EX_TRY + { + ULONG inCount = str.GetCount(); + ULONG outCount; + + m_pFileStream->Write(charStr, inCount, &outCount); + + if(inCount != outCount) + { + m_writeErrorEncountered = true; + } + } + EX_CATCH { m_writeErrorEncountered = true; } + EX_END_CATCH(SwallowAllExceptions); } void EventPipeJsonFile::FormatCallStack(StackContents &stackContents, SString &resultStr) { - STANDARD_VM_CONTRACT; + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; StackScratchBuffer scratch; SString frameStr; diff --git a/src/vm/eventpipeprovider.cpp b/src/vm/eventpipeprovider.cpp index c10dd33638..84a90e4abb 100644 --- a/src/vm/eventpipeprovider.cpp +++ b/src/vm/eventpipeprovider.cpp @@ -24,6 +24,7 @@ EventPipeProvider::EventPipeProvider(EventPipeConfiguration *pConfig, const SStr m_providerName = providerName; m_enabled = false; + m_deleteDeferred = false; m_keywords = 0; m_providerLevel = EventPipeEventLevel::Critical; m_pEventList = new SList<SListElem<EventPipeEvent*>>(); @@ -36,8 +37,8 @@ EventPipeProvider::~EventPipeProvider() { CONTRACTL { - THROWS; - GC_NOTRIGGER; + NOTHROW; + GC_TRIGGERS; MODE_ANY; } CONTRACTL_END; @@ -45,21 +46,30 @@ EventPipeProvider::~EventPipeProvider() // Free all of the events. if(m_pEventList != NULL) { - // Take the lock before manipulating the list. - CrstHolder _crst(EventPipe::GetLock()); - - SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead(); - while(pElem != NULL) + // We swallow exceptions here because the HOST_BREAKABLE + // lock may throw and this destructor gets called in throw + // intolerant places. If that happens the event list will leak + EX_TRY { - EventPipeEvent *pEvent = pElem->GetValue(); - delete pEvent; + // Take the lock before manipulating the list. + CrstHolder _crst(EventPipe::GetLock()); + + SListElem<EventPipeEvent*> *pElem = m_pEventList->GetHead(); + while(pElem != NULL) + { + EventPipeEvent *pEvent = pElem->GetValue(); + delete pEvent; + + SListElem<EventPipeEvent*> *pCurElem = pElem; + pElem = m_pEventList->GetNext(pElem); + delete pCurElem; + } - SListElem<EventPipeEvent*> *pCurElem = pElem; - pElem = m_pEventList->GetNext(pElem); - delete pCurElem; + delete m_pEventList; } + EX_CATCH { } + EX_END_CATCH(SwallowAllExceptions); - delete m_pEventList; m_pEventList = NULL; } } diff --git a/src/vm/eventpipeprovider.h b/src/vm/eventpipeprovider.h index 405ce32154..0ffe46f887 100644 --- a/src/vm/eventpipeprovider.h +++ b/src/vm/eventpipeprovider.h @@ -31,9 +31,6 @@ class EventPipeProvider friend class SampleProfiler; private: - // The GUID of the provider. - GUID m_providerID; - // The name of the provider. SString m_providerName; diff --git a/src/vm/fastserializer.cpp b/src/vm/fastserializer.cpp index 8e0e0ad768..66fce30793 100644 --- a/src/vm/fastserializer.cpp +++ b/src/vm/fastserializer.cpp @@ -40,7 +40,7 @@ FastSerializer::~FastSerializer() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -98,7 +98,7 @@ void FastSerializer::WriteBuffer(BYTE *pBuffer, unsigned int length) CONTRACTL { NOTHROW; - GC_TRIGGERS; + GC_NOTRIGGER; MODE_PREEMPTIVE; PRECONDITION(pBuffer != NULL); PRECONDITION(length > 0); @@ -263,7 +263,7 @@ void FastSerializer::WriteFileHeader() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_ANY; } @@ -278,7 +278,7 @@ void FastSerializer::WriteString(const char *strContents, unsigned int length) { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_PREEMPTIVE; } @@ -295,7 +295,7 @@ StreamLabel FastSerializer::WriteForwardReferenceTable() { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_PREEMPTIVE; } @@ -317,7 +317,7 @@ void FastSerializer::WriteTrailer(StreamLabel forwardReferencesTableStart) { CONTRACTL { - THROWS; + NOTHROW; GC_TRIGGERS; MODE_PREEMPTIVE; } diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp index 3e2d478bbf..75c1f058f0 100644 --- a/src/vm/mscorlib.cpp +++ b/src/vm/mscorlib.cpp @@ -96,6 +96,10 @@ #include "eventpipe.h" #endif //defined(FEATURE_EVENTSOURCE_XPLAT) +#ifdef FEATURE_PERFTRACING +#include "eventpipe.h" +#endif //FEATURE_PERFTRACING + #endif // CROSSGEN_MSCORLIB diff --git a/src/vm/sampleprofiler.cpp b/src/vm/sampleprofiler.cpp index d99667eea2..ade21669c4 100644 --- a/src/vm/sampleprofiler.cpp +++ b/src/vm/sampleprofiler.cpp @@ -11,6 +11,13 @@ #ifdef FEATURE_PERFTRACING +#ifndef FEATURE_PAL +#include <mmsystem.h> +#endif //FEATURE_PAL + +// To avoid counting zeros in conversions +#define MILLION * 1000000 + Volatile<BOOL> SampleProfiler::s_profilingEnabled = false; Thread* SampleProfiler::s_pSamplingThread = NULL; const WCHAR* SampleProfiler::s_providerName = W("Microsoft-DotNETCore-SampleProfiler"); @@ -19,7 +26,16 @@ EventPipeEvent* SampleProfiler::s_pThreadTimeEvent = NULL; BYTE* SampleProfiler::s_pPayloadExternal = NULL; BYTE* SampleProfiler::s_pPayloadManaged = NULL; CLREventStatic SampleProfiler::s_threadShutdownEvent; -long SampleProfiler::s_samplingRateInNs = 1000000; // 1ms +unsigned long SampleProfiler::s_samplingRateInNs = 1 MILLION; // 1ms +bool SampleProfiler::s_timePeriodIsSet = FALSE; + +#ifndef FEATURE_PAL +PVOID SampleProfiler::s_timeBeginPeriodFn = NULL; +PVOID SampleProfiler::s_timeEndPeriodFn = NULL; +HINSTANCE SampleProfiler::s_hMultimediaLib = NULL; + +typedef MMRESULT (WINAPI *TimePeriodFnPtr) (UINT uPeriod); +#endif //FEATURE_PAL void SampleProfiler::Enable() { @@ -33,6 +49,8 @@ void SampleProfiler::Enable() PRECONDITION(EventPipe::GetLock()->OwnedByCurrentThread()); } CONTRACTL_END; + + LoadDependencies(); if(s_pEventPipeProvider == NULL) { @@ -72,6 +90,10 @@ void SampleProfiler::Enable() { _ASSERT(!"Unable to create sample profiler thread."); } + + s_threadShutdownEvent.CreateManualEvent(FALSE); + + SetTimeGranularity(); } void SampleProfiler::Disable() @@ -101,12 +123,32 @@ void SampleProfiler::Disable() // Wait for the sampling thread to clean itself up. s_threadShutdownEvent.Wait(0, FALSE /* bAlertable */); + + if(s_timePeriodIsSet) + { + ResetTimeGranularity(); + } + UnloadDependencies(); } -void SampleProfiler::SetSamplingRate(long nanoseconds) +void SampleProfiler::SetSamplingRate(unsigned long nanoseconds) { LIMITED_METHOD_CONTRACT; + + // If the time period setting was modified by us, + // make sure to change it back before changing our period + // and losing track of what we set it to + if(s_timePeriodIsSet) + { + ResetTimeGranularity(); + } + s_samplingRateInNs = nanoseconds; + + if(!s_timePeriodIsSet) + { + SetTimeGranularity(); + } } DWORD WINAPI SampleProfiler::ThreadProc(void *args) @@ -132,7 +174,7 @@ DWORD WINAPI SampleProfiler::ThreadProc(void *args) if(ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0)) { // Skip the current sample. - PAL_nanosleep(s_samplingRateInNs); + PlatformSleep(s_samplingRateInNs); continue; } @@ -146,7 +188,7 @@ DWORD WINAPI SampleProfiler::ThreadProc(void *args) ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */); // Wait until it's time to sample again. - PAL_nanosleep(s_samplingRateInNs); + PlatformSleep(s_samplingRateInNs); } } @@ -156,7 +198,7 @@ DWORD WINAPI SampleProfiler::ThreadProc(void *args) // Signal Disable() that the thread has been destroyed. s_threadShutdownEvent.Set(); - + return S_OK; } @@ -201,4 +243,115 @@ void SampleProfiler::WalkManagedThreads() } } +void SampleProfiler::PlatformSleep(unsigned long nanoseconds) +{ + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + +#ifdef FEATURE_PAL + PAL_nanosleep(nanoseconds); +#else //FEATURE_PAL + ClrSleepEx(s_samplingRateInNs / 1 MILLION, FALSE); +#endif //FEATURE_PAL +} + +void SampleProfiler::SetTimeGranularity() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#ifndef FEATURE_PAL + // Attempt to set the systems minimum timer period to the sampling rate + // If the sampling rate is lower than the current system setting (16ms by default), + // this will cause the OS to wake more often for scheduling descsion, allowing us to take samples + // Note that is effects a system-wide setting and when set low will increase the amount of time + // the OS is on-CPU, decreasing overall system performance and increasing power consumption + if(s_timeBeginPeriodFn != NULL) + { + if(((TimePeriodFnPtr) s_timeBeginPeriodFn)(s_samplingRateInNs / 1 MILLION) == TIMERR_NOERROR) + { + s_timePeriodIsSet = TRUE; + } + } +#endif //FEATURE_PAL +} + +void SampleProfiler::ResetTimeGranularity() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#ifndef FEATURE_PAL + // End the modifications we had to the timer period in Enable + if(s_timeEndPeriodFn != NULL) + { + if(((TimePeriodFnPtr) s_timeEndPeriodFn)(s_samplingRateInNs / 1 MILLION) == TIMERR_NOERROR) + { + s_timePeriodIsSet = FALSE; + } + } +#endif //FEATURE_PAL +} + +bool SampleProfiler::LoadDependencies() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#ifndef FEATURE_PAL + s_hMultimediaLib = WszLoadLibrary(W("winmm.dll")); + + if (s_hMultimediaLib != NULL) + { + s_timeBeginPeriodFn = (PVOID) GetProcAddress(s_hMultimediaLib, "timeBeginPeriod"); + s_timeEndPeriodFn = (PVOID) GetProcAddress(s_hMultimediaLib, "timeEndPeriod"); + } + + return s_hMultimediaLib != NULL && s_timeBeginPeriodFn != NULL && s_timeEndPeriodFn != NULL; +#else + return FALSE; +#endif //FEATURE_PAL +} + +void SampleProfiler::UnloadDependencies() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + +#ifndef FEATURE_PAL + if (s_hMultimediaLib != NULL) + { + FreeLibrary(s_hMultimediaLib); + s_hMultimediaLib = NULL; + s_timeBeginPeriodFn = NULL; + s_timeEndPeriodFn = NULL; + } +#endif //FEATURE_PAL +} + #endif // FEATURE_PERFTRACING diff --git a/src/vm/sampleprofiler.h b/src/vm/sampleprofiler.h index 51290b4d9c..1bee70e8f6 100644 --- a/src/vm/sampleprofiler.h +++ b/src/vm/sampleprofiler.h @@ -33,7 +33,7 @@ class SampleProfiler static void Disable(); // Set the sampling rate. - static void SetSamplingRate(long nanoseconds); + static void SetSamplingRate(unsigned long nanoseconds); private: @@ -43,6 +43,31 @@ class SampleProfiler // Profiling thread proc. Invoked on a new thread when profiling is enabled. static DWORD WINAPI ThreadProc(void *args); + // Calls either PAL_nanosleep or ClrSleepEx depending on platform + // Note: Although we specify the time in ns, that is no indication + // of the actually accuracy with which we will return from sleep + // In reality Unix will have a minimum granularity of ~10ms + // and Windows has a default granularity of ~16ms, but can be + // adjusted to as low as ~1ms + // Even this however is not gaurenteed. If the system is under load + // the sampling thread may be delayed up to hundreds of ms due to + // scheduling priority. There is no way to prevent this from user threads + // Additionally we may get lucky and there will be an open CPU to run + // and under light load the timings will achieve great accuracy! + static void PlatformSleep(unsigned long nanoseconds); + + static bool LoadDependencies(); + static void UnloadDependencies(); + +#ifndef FEATURE_PAL + static HINSTANCE s_hMultimediaLib; + static PVOID s_timeBeginPeriodFn; + static PVOID s_timeEndPeriodFn; +#endif //FEATURE_PAL + + static void SetTimeGranularity(); + static void ResetTimeGranularity(); + // True when profiling is enabled. static Volatile<BOOL> s_profilingEnabled; @@ -65,7 +90,10 @@ class SampleProfiler static CLREventStatic s_threadShutdownEvent; // The sampling rate. - static long s_samplingRateInNs; + static unsigned long s_samplingRateInNs; + + // Whether or not timeBeginPeriod has been used to set the scheduler period + static bool s_timePeriodIsSet; }; #endif // FEATURE_PERFTRACING diff --git a/tests/runtest.proj b/tests/runtest.proj index 9c12e275d7..3ab7b9f708 100644 --- a/tests/runtest.proj +++ b/tests/runtest.proj @@ -12,7 +12,6 @@ <ItemGroup> <DisabledTestDir Include="Common" /> - <DisabledTestDir Include="tracing" /> <_SkipTestDir Include="@(DisabledTestDir)" /> </ItemGroup> @@ -404,4 +403,4 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\",""). <Target Name="Clean"> <RemoveDir Condition=" '$(BuildWrappers)'=='true'" Directories="$(XunitWrapperGeneratedCSDirBase);$(XunitWrapperOutputIntermediatedDirBase)" ContinueOnError="WarnAndContinue" /> </Target> -</Project>
\ No newline at end of file +</Project> diff --git a/tests/src/JIT/config/benchmark+roslyn/benchmark+roslyn.csproj b/tests/src/JIT/config/benchmark+roslyn/benchmark+roslyn.csproj index 77cba12414..563a9a7087 100644 --- a/tests/src/JIT/config/benchmark+roslyn/benchmark+roslyn.csproj +++ b/tests/src/JIT/config/benchmark+roslyn/benchmark+roslyn.csproj @@ -67,6 +67,9 @@ <PackageReference Include="System.Threading"> <Version>4.4.0-beta-24913-02</Version> </PackageReference> + <PackageReference Include="System.Threading.Thread"> + <Version>4.4.0-beta-24913-02</Version> + </PackageReference> <PackageReference Include="System.Threading.Tasks"> <Version>4.4.0-beta-24913-02</Version> </PackageReference> diff --git a/tests/src/JIT/config/benchmark/benchmark.csproj b/tests/src/JIT/config/benchmark/benchmark.csproj index 5ade686330..4d49fdee3e 100644 --- a/tests/src/JIT/config/benchmark/benchmark.csproj +++ b/tests/src/JIT/config/benchmark/benchmark.csproj @@ -76,6 +76,9 @@ <PackageReference Include="System.Threading"> <Version>4.4.0-beta-24913-02</Version> </PackageReference> + <PackageReference Include="System.Threading.Thread"> + <Version>4.4.0-beta-24913-02</Version> + </PackageReference> <PackageReference Include="System.Threading.Tasks"> <Version>4.4.0-beta-24913-02</Version> </PackageReference> diff --git a/tests/src/dirs.proj b/tests/src/dirs.proj index 471598d82d..543935f752 100644 --- a/tests/src/dirs.proj +++ b/tests/src/dirs.proj @@ -30,6 +30,7 @@ <DisabledProjects Include="Performance\performance.csproj" /> <DisabledProjects Include="Loader\classloader\generics\regressions\DD117522\Test.csproj" /> <DisabledProjects Include="Loader\classloader\generics\GenericMethods\VSW491668.csproj" /> <!-- issue 5501 --> + <DisabledProjects Include="tracing\eventsource*" /> </ItemGroup> <ItemGroup> diff --git a/tests/src/performance/performance.csproj b/tests/src/performance/performance.csproj index 8c2cd3c7de..94caf35ac2 100644 --- a/tests/src/performance/performance.csproj +++ b/tests/src/performance/performance.csproj @@ -70,6 +70,9 @@ <PackageReference Include="System.Threading"> <Version>4.4.0-beta-24913-02</Version> </PackageReference> + <PackageReference Include="System.Threading.Thread"> + <Version>4.4.0-beta-24913-02</Version> + </PackageReference> <PackageReference Include="System.Threading.Tasks"> <Version>4.4.0-beta-24913-02</Version> </PackageReference> diff --git a/tests/src/tracing/common/common.csproj b/tests/src/tracing/common/common.csproj index ca34349b16..ca10e7ffe2 100644 --- a/tests/src/tracing/common/common.csproj +++ b/tests/src/tracing/common/common.csproj @@ -12,7 +12,7 @@ <CLRTestKind>BuildOnly</CLRTestKind> <DefineConstants>$(DefineConstants);STATIC</DefineConstants> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <CLRTestPriority>1</CLRTestPriority> + <CLRTestPriority>0</CLRTestPriority> </PropertyGroup> <!-- Default configurations to help VS understand the configurations --> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> diff --git a/tests/src/tracing/eventpipesmoke/EventPipeSmoke.cs b/tests/src/tracing/eventpipesmoke/EventPipeSmoke.cs index c12893d38a..2fa8786fd2 100644 --- a/tests/src/tracing/eventpipesmoke/EventPipeSmoke.cs +++ b/tests/src/tracing/eventpipesmoke/EventPipeSmoke.cs @@ -1,7 +1,5 @@ using System; -using System.Threading.Tasks; using System.IO; - using Tracing.Tests.Common; namespace Tracing.Tests diff --git a/tests/src/tracing/eventpipesmoke/eventpipesmoke.csproj b/tests/src/tracing/eventpipesmoke/eventpipesmoke.csproj index 8ba6eb5c4a..4a1cd0c0ce 100644 --- a/tests/src/tracing/eventpipesmoke/eventpipesmoke.csproj +++ b/tests/src/tracing/eventpipesmoke/eventpipesmoke.csproj @@ -12,7 +12,7 @@ <CLRTestKind>BuildAndRun</CLRTestKind> <DefineConstants>$(DefineConstants);STATIC</DefineConstants> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <CLRTestPriority>1</CLRTestPriority> + <CLRTestPriority>0</CLRTestPriority> </PropertyGroup> <!-- Default configurations to help VS understand the configurations --> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup> diff --git a/tests/src/tracing/eventpipetrace/EventPipeTrace.cs b/tests/src/tracing/eventpipetrace/EventPipeTrace.cs new file mode 100644 index 0000000000..af0c619ef9 --- /dev/null +++ b/tests/src/tracing/eventpipetrace/EventPipeTrace.cs @@ -0,0 +1,110 @@ +using System; +using System.IO; +using Tracing.Tests.Common; +using Microsoft.Diagnostics.Tracing; +using Microsoft.Diagnostics.Tracing.Parsers; +using Microsoft.Diagnostics.Tracing.Parsers.Clr; + +namespace Tracing.Tests +{ + class EventPipeTrace + { + private static int allocIterations = 10000; + private static int gcIterations = 10; + + static void AssertEqual<T>(T left, T right) where T : IEquatable<T> + { + if (left.Equals(right) == false) + { + throw new Exception(string.Format("Values were not equal! {0} and {1}", left, right)); + } + } + + static int Main(string[] args) + { + bool pass = true; + bool keepOutput = false; + + // Use the first arg as an output filename if there is one + string outputFilename = null; + if (args.Length >= 1) { + outputFilename = args[0]; + keepOutput = true; + } + else { + outputFilename = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".netperf"; + } + + try + { + Console.WriteLine("\tStart: Enable tracing."); + TraceControl.EnableDefault(outputFilename); + Console.WriteLine("\tEnd: Enable tracing.\n"); + + Console.WriteLine("\tStart: Generating CLR events"); + // Allocate for allocIterations iterations. + for(int i=0; i<allocIterations; i++) + { + GC.KeepAlive(new object()); + } + // GC gcIternation times + for(int i=0; i<gcIterations; i++) + { + GC.Collect(); + } + Console.WriteLine("\tEnd: Generating CLR Events\n"); + + Console.WriteLine("\tStart: Disable tracing."); + TraceControl.Disable(); + Console.WriteLine("\tEnd: Disable tracing.\n"); + + Console.WriteLine("\tStart: Processing events from file."); + int allocTickCount = 0; + int gcTriggerCount = 0; + using (var trace = TraceEventDispatcher.GetDispatcherFromFileName(outputFilename)) + { + trace.Clr.GCAllocationTick += delegate(GCAllocationTickTraceData data) + { + allocTickCount += 1; + + // Some basic integrity checks + // AssertEqual(data.TypeName, "System.Object"); https://github.com/Microsoft/perfview/issues/470 + AssertEqual(data.AllocationKind.ToString(), GCAllocationKind.Small.ToString()); + AssertEqual(data.ProviderName, "Microsoft-Windows-DotNETRuntime"); + AssertEqual(data.EventName, "GC/AllocationTick"); + }; + trace.Clr.GCTriggered += delegate(GCTriggeredTraceData data) + { + gcTriggerCount += 1; + + // Some basic integrity checks + AssertEqual(data.Reason.ToString(), GCReason.Induced.ToString()); + AssertEqual(data.ProviderName, "Microsoft-Windows-DotNETRuntime"); + AssertEqual(data.EventName, "GC/Triggered"); + }; + + trace.Process(); + } + Console.WriteLine("\tEnd: Processing events from file.\n"); + + Console.WriteLine("\tProcessed {0} GCAllocationTick events", allocTickCount); + Console.WriteLine("\tProcessed {0} GCTriggered events", gcTriggerCount); + + pass &= allocTickCount > 0; + pass &= gcTriggerCount == gcIterations; + } + finally { + if (keepOutput) + { + Console.WriteLine("\n\tOutput file: {0}", outputFilename); + } + else + { + System.IO.File.Delete(outputFilename); + } + } + + return pass ? 100 : 0; + } + } +} diff --git a/tests/src/tracing/eventpipetrace/eventpipetrace.csproj b/tests/src/tracing/eventpipetrace/eventpipetrace.csproj new file mode 100644 index 0000000000..ec7305abe9 --- /dev/null +++ b/tests/src/tracing/eventpipetrace/eventpipetrace.csproj @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>BuildAndRun</CLRTestKind> + <DefineConstants>$(DefineConstants);STATIC</DefineConstants> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <CLRTestPriority>0</CLRTestPriority> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"></PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="EventPipeTrace.cs" /> + <ProjectReference Include="../common/common.csproj" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file diff --git a/tests/src/tracing/eventsourcesmoke/EventSourceSmoke.cs b/tests/src/tracing/eventsourcesmoke/EventSourceSmoke.cs index b7d321dde6..ddd5192e18 100644 --- a/tests/src/tracing/eventsourcesmoke/EventSourceSmoke.cs +++ b/tests/src/tracing/eventsourcesmoke/EventSourceSmoke.cs @@ -1,8 +1,6 @@ using System; -using System.Threading.Tasks; using System.IO; using System.Diagnostics.Tracing; - using Tracing.Tests.Common; namespace Tracing.Tests diff --git a/tests/src/tracing/eventsourcetrace/EventSourceTrace.cs b/tests/src/tracing/eventsourcetrace/EventSourceTrace.cs new file mode 100644 index 0000000000..57a53183ed --- /dev/null +++ b/tests/src/tracing/eventsourcetrace/EventSourceTrace.cs @@ -0,0 +1,131 @@ +using System; +using System.IO; +using System.Collections.Generic; +using Tracing.Tests.Common; +using System.Diagnostics.Tracing; +using Microsoft.Diagnostics.Tracing; +using Microsoft.Diagnostics.Tracing.Parsers; +using Microsoft.Diagnostics.Tracing.Parsers.Clr; + +namespace Tracing.Tests +{ + [EventSource(Name = "SimpleEventSource")] + class SimpleEventSource : EventSource + { + public SimpleEventSource() : base(true) { } + + [Event(1)] + internal void MathResult(int x, int y, int z, string formula) { this.WriteEvent(1, x, y, z, formula); } + } + + class EventSourceTrace + { + private static int messageIterations = 10000; + + public static TraceConfiguration GetConfig(EventSource eventSource, string outputFile="default.netperf") + { + // Setup the configuration values. + uint circularBufferMB = 1024; // 1 GB + uint level = 5;//(uint)EventLevel.Informational; + TimeSpan profSampleDelay = TimeSpan.FromMilliseconds(1); + + // Create a new instance of EventPipeConfiguration. + TraceConfiguration config = new TraceConfiguration(outputFile, circularBufferMB); + // Setup the provider values. + // Public provider. + string providerName = eventSource.Name; + UInt64 keywords = 0xffffffffffffffff; + + // Enable the provider. + config.EnableProvider(providerName, keywords, level); + + // Set the sampling rate. + config.SetSamplingRate(profSampleDelay); + + return config; + } + + static int Main(string[] args) + { + bool pass = true; + bool keepOutput = false; + + // Use the first arg as an output filename if there is one + string outputFilename = null; + if (args.Length >= 1) { + outputFilename = args[0]; + keepOutput = true; + } + else { + outputFilename = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".netperf"; + } + + SimpleEventSource eventSource = new SimpleEventSource(); + + try + { + Console.WriteLine("\tStart: Enable tracing."); + TraceControl.Enable(GetConfig(eventSource, outputFilename)); + Console.WriteLine("\tEnd: Enable tracing.\n"); + + Console.WriteLine("\tStart: Messaging."); + // Send messages + // Use random numbers and addition as a simple, human readble checksum + Random generator = new Random(); + for(int i=0; i<messageIterations; i++) + { + int x = generator.Next(1,1000); + int y = generator.Next(1,1000); + string formula = String.Format("{0} + {1} = {2}", x, y, x+y); + + eventSource.MathResult(x, y, x+y, formula); + } + Console.WriteLine("\tEnd: Messaging.\n"); + + Console.WriteLine("\tStart: Disable tracing."); + TraceControl.Disable(); + Console.WriteLine("\tEnd: Disable tracing.\n"); + + Console.WriteLine("\tStart: Processing events from file."); + int msgCount = 0; + using (var trace = TraceEventDispatcher.GetDispatcherFromFileName(outputFilename)) + { + var names = new HashSet<string>(); + + trace.Dynamic.All += delegate(TraceEvent data) + { + if (!names.Contains(data.ProviderName)) + { + Console.WriteLine("\t{0}", data.ProviderName); + names.Add(data.ProviderName); + } + + if (data.ProviderName == "SimpleEventSource") + { + msgCount += 1; + } + }; + + trace.Process(); + } + Console.WriteLine("\tEnd: Processing events from file.\n"); + + Console.WriteLine("\tProcessed {0} events from EventSource", msgCount); + + pass &= msgCount == messageIterations; + } + finally { + if (keepOutput) + { + Console.WriteLine("\n\tOutput file: {0}", outputFilename); + } + else + { + System.IO.File.Delete(outputFilename); + } + } + + return pass ? 100 : 0; + } + } +} diff --git a/tests/src/tracing/eventsourcetrace/eventsourcetrace.csproj b/tests/src/tracing/eventsourcetrace/eventsourcetrace.csproj new file mode 100644 index 0000000000..833146ec64 --- /dev/null +++ b/tests/src/tracing/eventsourcetrace/eventsourcetrace.csproj @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{8E3244CB-407F-4142-BAAB-E7A55901A5FA}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <CLRTestKind>BuildAndRun</CLRTestKind> + <DefineConstants>$(DefineConstants);STATIC</DefineConstants> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <CLRTestPriority>1</CLRTestPriority> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"></PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="EventSourceTrace.cs" /> + <ProjectReference Include="../common/common.csproj" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project>
\ No newline at end of file |