Skip to content

Commit f307984

Browse files
author
Gregory LEOCADIE
committed
Add support for events collection through EventPipe
1 parent 9b5b7a6 commit f307984

File tree

2 files changed

+225
-7
lines changed

2 files changed

+225
-7
lines changed

src/perfcollect/perfcollect

Lines changed: 213 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ usePerf=1
642642
# Use LTTng
643643
useLTTng=1
644644

645+
# Use dotnet-trace tool to collect CLR events
646+
useDotnetTrace=0
647+
sdkAndToolDir="/tmp/perfcollect-dotnet-sdk"
648+
645649
# LTTng Installed
646650
lttngInstalled=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+
12001273
SupportsAutoInstall()
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+
19612158
DoCollect()
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
21392343
fi
21402344

@@ -2150,6 +2354,8 @@ fi
21502354
# Process arguments.
21512355
ProcessArguments $@
21522356

2357+
ValidateOptions
2358+
21532359
# Ensure prerequisites are installed.
21542360
EnsurePrereqsInstalled
21552361

src/perfcollect/tests/container-entrypoint.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,15 @@ if [ "$perf_data_txt_size" == "0" ]
2727
then
2828
exit -1
2929
fi
30+
31+
# Capture a short trace with dotnet-trace activated.
32+
$perfcollect collect test-dotnettrace -dotnet-trace -collectsec 5
33+
34+
# Open the trace
35+
unzip test-dotnettrace.trace.zip
36+
37+
# Test the size of the trace.nettrace file
38+
if [[ ! -s test-dotnettrace.trace/trace.nettrace ]]
39+
then
40+
exit -1
41+
fi

0 commit comments

Comments
 (0)