@@ -642,6 +642,10 @@ usePerf=1
642642# Use LTTng
643643useLTTng=1
644644
645+ # Use dotnet-trace tool to collect CLR events
646+ useDotnetTrace=0
647+ sdkAndToolDir=" /tmp/perfcollect-dotnet-sdk"
648+
645649# LTTng Installed
646650lttngInstalled=0
647651
@@ -709,6 +713,11 @@ InitializeLog()
709713 then
710714 LogAppend ' LTTng version: ' ` $lttngcmd --version`
711715 fi
716+
717+ if [ " $dotnettracecmd " != " " ]
718+ then
719+ LogAppend ' dotnet-trace version:' $( eval $dotnettracecmd --version)
720+ fi
712721 LogAppend
713722}
714723
@@ -887,6 +896,19 @@ DiscoverCommands()
887896 fi
888897 fi
889898
899+ if [ " $( IsSdkInstalledGlobally) " == 0 ]
900+ then
901+ dotnettracecmd=" dotnet trace"
902+ else
903+ dotnettracecmd=" DOTNET_ROOT=\" $sdkAndToolDir \" $sdkAndToolDir /dotnet-trace"
904+ fi
905+
906+ eval " $dotnettracecmd --version" > /dev/null 2>&1
907+ if [ " $? " != " 0" ]
908+ then
909+ FatalError " Unable to find dotnet-trace tool. Try re-installing via ./perfcollect install."
910+ fi
911+
890912 lttngcmd=` GetCommandFullPath " lttng" `
891913 zipcmd=` GetCommandFullPath " zip" `
892914 unzipcmd=` GetCommandFullPath " unzip" `
@@ -1197,6 +1219,57 @@ InstallLTTng()
11971219 fi
11981220}
11991221
1222+ IsSdkInstalledGlobally ()
1223+ {
1224+ installed=1
1225+ dotnet tool list > /dev/null 2>&1
1226+ if [ " $? " == " 0" ]
1227+ then
1228+ installed=0
1229+ fi
1230+ echo $installed
1231+ }
1232+
1233+ InstallSdkAndDotNetTraceLocally ()
1234+ {
1235+ # install SDK, if needed
1236+ if [ ! -d " $sdkAndToolDir " ] || [ ! -f " $sdkAndToolDir /dotnet" ]
1237+ then
1238+ WriteStatus " Installing dotnet sdk in $sdkAndToolDir "
1239+ ResetText
1240+ RunSilent " mkdir $sdkAndToolDir "
1241+ RunSilent " cd $sdkAndToolDir "
1242+ RunSilent " curl -OL https://dot.net/v1/dotnet-install.sh"
1243+ RunSilent " bash ./dotnet-install.sh --install-dir ."
1244+ fi
1245+
1246+ # install dotnet-trace, if needed
1247+ if [ ! -f " $sdkAndToolDir /dotnet-trace" ]
1248+ then
1249+ WriteStatus " Installing dotnet trace"
1250+ RunSilent " $sdkAndToolDir /dotnet tool install dotnet-trace --tool-path $sdkAndToolDir "
1251+ fi
1252+
1253+ # Check if it works
1254+ DOTNET_ROOT=" $sdkAndToolDir " $sdkAndToolDir /dotnet-trace --version > /dev/null 2>&1
1255+ if [ " $? " != " 0" ]
1256+ then
1257+ FatalError " dotnet-trace tool was not installed correctly. Delete $sdkAndToolDir and re-install via ./perfcollect install."
1258+ fi
1259+ }
1260+
1261+ InstallDotNetTraceTool ()
1262+ {
1263+ if [ " $( IsSdkInstalledGlobally) " == 0 ]
1264+ then
1265+ WriteStatus " Installing dotnet trace using the existing SDK"
1266+ RunSilent " dotnet tool install dotnet-trace"
1267+ else
1268+ WriteStatus " Installing .NET SDK and dotnet-trace in $sdkAndToolDir "
1269+ InstallSdkAndDotNetTraceLocally
1270+ fi
1271+ }
1272+
12001273SupportsAutoInstall ()
12011274{
12021275 local supportsAutoInstall=0
@@ -1249,6 +1322,22 @@ EnsurePrereqsInstalled()
12491322
12501323 fi
12511324
1325+ # if dotnet-trace is installed consider using it.
1326+ if [ " $dotnettracecmd " == " " ] && [ " $useDotnetTrace " == " 1" ]
1327+ then
1328+ RedText
1329+ echo " dotnet-trace not installed."
1330+ if [ " $( SupportsAutoInstall) " == " 1" ]
1331+ then
1332+ echo " Run ./perfcollect install"
1333+ echo " or install dotnet-trace manually"
1334+ else
1335+ echo " Install dotnet-trace to proceed."
1336+ fi
1337+ ResetText
1338+ exit 1
1339+ fi
1340+
12521341 # If zip or unzip are not installing, then bail.
12531342 if [ " $zipcmd " == " " ] || [ " $unzipcmd " == " " ]
12541343 then
@@ -1332,6 +1421,7 @@ ProcessArguments()
13321421 if [ " -events" != " $arg " ]
13331422 then
13341423 # Convert the value to lower case.
1424+ rawvalue=$value
13351425 value=` echo $value | tr ' [:upper:]' ' [:lower:]' `
13361426 fi
13371427 fi
@@ -1377,18 +1467,29 @@ ProcessArguments()
13771467 elif [ " -nolttng" == " $arg " ]
13781468 then
13791469 useLTTng=0
1380- elif [ " -noperf" == " $arg " ]
1470+ elif [ " -dotnet-trace" == " $arg " ]
1471+ then
1472+ useDotnetTrace=1
1473+ useLTTng=0
1474+ elif [ " -providers" == " $arg " ]
1475+ then
1476+ providers=$rawvalue
1477+ i=$i +1
1478+ elif [ " -noperf" == " $arg " ]
13811479 then
13821480 usePerf=0
13831481 elif [ " -gccollectonly" == " $arg " ]
13841482 then
13851483 gcCollectOnly=1
1484+ usePerf=0
13861485 elif [ " -gconly" == " $arg " ]
13871486 then
13881487 gcOnly=1
1488+ usePerf=0
13891489 elif [ " -gcwithheap" == " $arg " ]
13901490 then
13911491 gcWithHeap=1
1492+ usePerf=0
13921493 elif [ " -events" == " $arg " ]
13931494 then
13941495 events=$value
@@ -1404,7 +1505,18 @@ ProcessArguments()
14041505
14051506}
14061507
1407-
1508+ ValidateOptions ()
1509+ {
1510+ if [ " $collectionPid " == " " ] && [ " $useDotnetTrace " == " 1" ]
1511+ then
1512+ FatalError " You must specify a .Net process id (-pid) to collect CLR events with dotnet-trace tool."
1513+ fi
1514+
1515+ if [ " $providers " != " " ] && [ " $useDotnetTrace " == " 1" ]
1516+ then
1517+ FatalError " You must specify -dotnet-trace when passing '-providers $providers '."
1518+ fi
1519+ }
14081520
14091521# #
14101522# LTTng collection
@@ -1438,21 +1550,18 @@ SetupLTTngSession()
14381550 RunSilent " $lttngcmd enable-event --userspace --tracepoint DotNETRuntime:EventSource"
14391551 elif [ " $gcCollectOnly " == " 1" ]
14401552 then
1441- usePerf=0
14421553 EnableLTTngEvents ${DotNETRuntime_GCKeyword_GCCollectOnly[@]}
14431554 EnableLTTngEvents ${DotNETRuntimePrivate_GCPrivateKeyword_GCCollectOnly[@]}
14441555 EnableLTTngEvents ${DotNETRuntime_ExceptionKeyword[@]}
14451556 elif [ " $gcOnly " == " 1" ]
14461557 then
1447- usePerf=0
14481558 EnableLTTngEvents ${DotNETRuntime_GCKeyword[@]}
14491559 EnableLTTngEvents ${DotNETRuntimePrivate_GCPrivateKeyword[@]}
14501560 EnableLTTngEvents ${DotNETRuntime_JitKeyword[@]}
14511561 EnableLTTngEvents ${DotNETRuntime_LoaderKeyword[@]}
14521562 EnableLTTngEvents ${DotNETRuntime_ExceptionKeyword[@]}
14531563 elif [ " $gcWithHeap " == " 1" ]
14541564 then
1455- usePerf=0
14561565 EnableLTTngEvents ${DotNETRuntime_GCKeyword[@]}
14571566 EnableLTTngEvents ${DotNETRuntime_GCHeapSurvivalAndMovementKeyword[@]}
14581567 else
@@ -1559,6 +1668,13 @@ ProcessCollectedData()
15591668 fi
15601669 fi
15611670
1671+ if [ " $useDotnetTrace " == " 1" ]
1672+ then
1673+ LogAppend " Saving dotnet-trace trace file."
1674+ cp $dotnetTraceOutputFile .
1675+ cp $dotnetTraceLogFile .
1676+ fi
1677+
15621678 if [ " $usePerf " == 1 ]
15631679 then
15641680 # Get any perf-$pid.map files that were used by the
@@ -1832,6 +1948,11 @@ EndCollect()
18321948 StopLTTngCollection
18331949 fi
18341950
1951+ if [ " $useDotnetTrace " == " 1" ]
1952+ then
1953+ StopDotnetTraceCollection
1954+ fi
1955+
18351956 # Update the user.
18361957 WriteStatus
18371958 WriteStatus " ...STOPPED."
@@ -1861,6 +1982,9 @@ PrintUsage()
18611982 echo " -threadtime : Collect events for thread time analysis (on and off cpu)."
18621983 echo " -offcpu : Collect events for off-cpu analysis."
18631984 echo " -hwevents : Collect (some) hardware counters."
1985+ echo " -dotnet-trace : Collect CLR events using dotnet-trace tool."
1986+ echo " -providers : Comma-separated-list of provider/keywords/verbosity (used only with -dotnet-trace option)."
1987+ echo " Example: Microsoft-Windows-DotNETRuntime:0x000000108001C039:5,Microsoft-Windows-DotNETRuntime:0x000000108001C039:4"
18641988 echo " "
18651989 echo " start:"
18661990 echo " Start collection, but with Lttng trace ONLY. It needs to be used with 'stop' action."
@@ -1954,10 +2078,83 @@ BuildPerfRecordArgs()
19542078 durationString=" sleep ${duration} "
19552079 fi
19562080
1957- # Add the events onto the collection command line args.
2081+ # Add the events onto the collection command line args.
19582082 collectionArgs=" $collectionArgs -e $eventString $durationString "
19592083}
19602084
2085+ BuildDotnetTraceArgs ()
2086+ {
2087+ dotnetTraceCollectionArgs=" collect -p $collectionPid "
2088+
2089+ activated_providers=()
2090+ if [ " $gcCollectOnly " == " 1" ]
2091+ then
2092+ # # GC & Exception
2093+ activated_providers+=(" Microsoft-Windows-DotNETRuntime:0x0000000000008001:4" )
2094+ # # Private GC
2095+ activated_providers+=(" Microsoft-Windows-DotNETRuntimePrivate:0x0000000000000001:4" )
2096+ elif [ " $gcOnly " == " 1" ]
2097+ then
2098+ # # GC & Jit & Loader & Exception
2099+ activated_providers+=(" Microsoft-Windows-DotNETRuntime:0x0000000000080019:5" )
2100+ # # Private GC
2101+ activated_providers+=(" Microsoft-Windows-DotNETRuntimePrivate:0x0000000000000001:5" )
2102+ elif [ " $gcWithHeap " == " 1" ]
2103+ then
2104+ # # GC & GCHeapSurvivalAndMovement
2105+ activated_providers+=(" Microsoft-Windows-DotNETRuntime:0x0000000000400001:5" )
2106+ else
2107+ if [ " $providers " == " " ]
2108+ then
2109+ # Enable the default set of events.
2110+
2111+ # DotNETRuntime with keywords: Exception, Contention, Jit/NGen, Loader, GC, Compilation
2112+ # Threading, ThreadTransfer & Jit
2113+ activated_providers+=(" Microsoft-Windows-DotNETRuntime:0x000000108001C039:5" )
2114+
2115+ # DotNETRuntimeRundown with keyword(s): Compilation
2116+ activated_providers+=(" Microsoft-Windows-DotNETRuntimeRundown:0x0000001000000000:4" )
2117+
2118+ # DotNETRuntimePrivate with keywords: GC, Binding, MulticoreJitPrivate
2119+ activated_providers+=(" Microsoft-Windows-DotNETRuntimePrivate:0x0000000000020003:4" )
2120+
2121+ elif [ " $providers " == " threading" ]
2122+ then
2123+ activated_providers+=(" Microsoft-Windows-DotNETRuntime:0x0000000000010000:5" )
2124+ else
2125+ # Enable other keywords
2126+ providers=(${providers// " ," / " " } )
2127+ for provider in ${providers[@]}
2128+ do
2129+ activated_providers+=($provider )
2130+ done
2131+ fi
2132+ fi
2133+ if (( ${# activated_providers[@]} ))
2134+ then
2135+ joined_providers=$( IFS=" ," ; echo " ${activated_providers[*]} " )
2136+ dotnetTraceCollectionArgs=" $dotnetTraceCollectionArgs --providers $joined_providers "
2137+ fi
2138+ dotnetTraceOutputFile=" $sdkAndToolDir /trace.nettrace"
2139+ dotnetTraceLogFile=" $sdkAndToolDir /dotnet-trace.log"
2140+ dotnetTraceCollectionArgs=" $dotnetTraceCollectionArgs -o $dotnetTraceOutputFile "
2141+ }
2142+
2143+ StartDotnetTraceCollection ()
2144+ {
2145+ eval " $dotnettracecmd $dotnetTraceCollectionArgs < /dev/null > $dotnetTraceLogFile 2>&1 &"
2146+ dotnetTraceCollectionPid=$!
2147+ }
2148+
2149+ StopDotnetTraceCollection ()
2150+ {
2151+ RunSilent " kill -15 $dotnetTraceCollectionPid "
2152+ while [ " $dotnetTraceCollectionPid " != " " ] && [ -e /proc/$dotnetTraceCollectionPid ]
2153+ do
2154+ sleep .6
2155+ done
2156+ }
2157+
19612158DoCollect ()
19622159{
19632160 # Ensure the script is run as root.
@@ -1983,6 +2180,12 @@ DoCollect()
19832180 StartLTTngCollection
19842181 fi
19852182
2183+ if [ " $useDotnetTrace " == " 1" ]
2184+ then
2185+ BuildDotnetTraceArgs
2186+ StartDotnetTraceCollection
2187+ fi
2188+
19862189 # Tell the user that collection has started and how to exit.
19872190 if [ " $duration " != " " ]
19882191 then
@@ -2001,7 +2204,7 @@ DoCollect()
20012204 # Pass trace directory and session name to the stop process.
20022205 popd > /dev/null
20032206 usePerf=0
2004- declare -p | grep -e lttngTraceDir -e lttngSessionName -e tempDir -e usePerf -e useLttng -e logFile > $collectInfoFile
2207+ declare -p | grep -e lttngTraceDir -e lttngSessionName -e tempDir -e usePerf -e useLttng -e logFile -e dotnetTraceCollectionPid -e dotnetTraceOutputFile -e dotnetTraceLogFile > $collectInfoFile
20052208 else
20062209 if [ " $usePerf " == " 1" ]
20072210 then
@@ -2135,6 +2338,7 @@ then
21352338 fi
21362339 InstallPerf
21372340 InstallLTTng
2341+ InstallDotNetTraceTool
21382342 exit 0
21392343fi
21402344
21502354# Process arguments.
21512355ProcessArguments $@
21522356
2357+ ValidateOptions
2358+
21532359# Ensure prerequisites are installed.
21542360EnsurePrereqsInstalled
21552361
0 commit comments