Skip to content

Commit 5c5bec1

Browse files
[build] Build tracer with ReadyToRun (DataDog#5962)
## Summary of changes Allows tracer publishing to be compiled with [ReadyToRun](https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run) to improve Serverless workloads init duration. ## Reason for change It has showcased a 500ms init duration improvement for AWS Lambda. Potentially could be used for other workloads in the future. ## Implementation details Followed DataDog#4573 and [ReadyToRun](https://learn.microsoft.com/en-us/dotnet/core/deploying/ready-to-run) docs. ## Test coverage - TBD - Tested manually in AWS Lambda. ## Other details Increases tracer size by 3x. <!-- ⚠️ Note: where possible, please obtain 2 approvals prior to merging. Unless CODEOWNERS specifies otherwise, for external teams it is typically best to have one review from a team member, and one review from apm-dotnet. Trivial changes do not require 2 reviews. --> --------- Co-authored-by: Andrew Lock <[email protected]>
1 parent 8a81a8b commit 5c5bec1

File tree

7 files changed

+294
-10
lines changed

7 files changed

+294
-10
lines changed

.azure-pipelines/ultimate-pipeline.yml

+106
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,69 @@ stages:
414414
displayName: publish tracer and native loader test results
415415
artifact: build_linux_tracer_unit_tests_results_$(artifactSuffix)_$(System.JobAttempt)
416416

417+
- stage: build_linux_tracer_r2r
418+
dependsOn: [merge_commit_id]
419+
variables:
420+
targetShaId: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.sha']]
421+
targetBranch: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.branch']]
422+
jobs:
423+
- template: steps/update-github-status-jobs.yml
424+
parameters:
425+
jobs: [build]
426+
427+
- job: build
428+
timeoutInMinutes: 60 #default value
429+
dependsOn: []
430+
pool:
431+
name: azure-linux-scale-set-2
432+
433+
steps:
434+
- template: steps/clone-repo.yml
435+
parameters:
436+
targetShaId: $(targetShaId)
437+
targetBranch: $(targetBranch)
438+
439+
- template: steps/run-in-docker.yml
440+
parameters:
441+
build: true
442+
target: builder
443+
baseImage: debian
444+
command: "Clean CompileManagedLoader"
445+
retryCountForRunCommand: 1
446+
447+
- template: steps/run-in-docker.yml
448+
parameters:
449+
build: true
450+
target: builder
451+
baseImage: centos7
452+
useNativeSdkVersion: true
453+
command: "BuildNativeTracerHome CompileTracerNativeTests RunTracerNativeTests"
454+
retryCountForRunCommand: 1
455+
apiKey: $(DD_LOGGER_DD_API_KEY)
456+
457+
- template: steps/run-in-docker.yml
458+
parameters:
459+
target: builder
460+
baseImage: debian
461+
command: "BuildManagedTracerHomeR2R ExtractDebugInfoLinux"
462+
retryCountForRunCommand: 1
463+
464+
- publish: $(monitoringHome)
465+
displayName: Uploading linux tracer home artifact
466+
artifact: linux-tracer-home-linux-x64-r2r
467+
468+
- publish: $(System.DefaultWorkingDirectory)
469+
displayName: Upload working directory after the build
470+
artifact: build-linux-x64-r2r-working-directory
471+
472+
- publish: $(symbols)
473+
displayName: Upload linux tracer symbols
474+
artifact: linux-tracer-symbols-linux-x64-r2r
475+
476+
- publish: artifacts/build_data/tests
477+
displayName: publish tracer and native loader test results
478+
artifact: build_linux_tracer_unit_tests_results_linux-x64-r2r_$(System.JobAttempt)
479+
417480
- stage: build_linux_universal
418481
dependsOn: [merge_commit_id]
419482
variables:
@@ -657,6 +720,49 @@ stages:
657720
displayName: Upload linux tracer symbols
658721
artifact: linux-tracer-symbols-$(artifactSuffix)
659722

723+
- stage: build_arm64_tracer_r2r
724+
dependsOn: [merge_commit_id]
725+
variables:
726+
targetShaId: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.sha']]
727+
targetBranch: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.branch']]
728+
jobs:
729+
- template: steps/update-github-status-jobs.yml
730+
parameters:
731+
jobs: [build]
732+
733+
- job: build
734+
timeoutInMinutes: 60 #default value
735+
dependsOn: []
736+
737+
pool:
738+
name: aws-arm64-auto-scaling
739+
workspace:
740+
clean: all
741+
steps:
742+
- template: steps/clone-repo.yml
743+
parameters:
744+
targetShaId: $(targetShaId)
745+
targetBranch: $(targetBranch)
746+
- template: steps/run-in-docker.yml
747+
parameters:
748+
build: true
749+
target: builder
750+
baseImage: debian
751+
command: "Clean CompileManagedLoader BuildNativeTracerHome BuildManagedTracerHomeR2R ExtractDebugInfoLinux"
752+
retryCountForRunCommand: 1
753+
754+
- publish: $(monitoringHome)
755+
displayName: Uploading linux tracer home artifact
756+
artifact: linux-tracer-home-linux-arm64-r2r
757+
758+
- publish: $(System.DefaultWorkingDirectory)
759+
displayName: Upload working directory after the build
760+
artifact: build-linux-arm64-r2r-working-directory
761+
762+
- publish: $(symbols)
763+
displayName: Upload linux tracer symbols
764+
artifact: linux-tracer-symbols-linux-arm64-r2r
765+
660766
- stage: build_arm64_profiler
661767
dependsOn: [merge_commit_id]
662768
variables:

.gitlab-ci.yml

+32
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,38 @@ deploy_to_reliability_env:
116116
rules:
117117
- when: never # dd-trace-dotnet does not use reliability environment
118118

119+
download-serverless-artifacts:
120+
stage: package
121+
image: registry.ddbuild.io/docker:20.10.13-gbi-focal
122+
tags: [ "arch:amd64" ]
123+
needs: []
124+
rules:
125+
- if: $DOTNET_PACKAGE_VERSION
126+
when: on_success
127+
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+(-prerelease)?$/' # Manually triggered as artifacts are from the Github release
128+
when: manual
129+
allow_failure: false
130+
- when: delayed # Artifacts come from Azure pipeline, wait a reasonable time before polling
131+
start_in: 15 minutes
132+
script:
133+
- .gitlab/download-serverless-artifacts.sh
134+
artifacts:
135+
expire_in: 2 weeks
136+
paths:
137+
- artifacts
138+
139+
aws-lambda-layer:
140+
stage: package
141+
needs: [download-serverless-artifacts]
142+
when: manual
143+
trigger:
144+
project: DataDog/dd-trace-dotnet-aws-lambda-layer
145+
strategy: depend
146+
variables:
147+
UPSTREAM_PIPELINE_ID: $CI_PIPELINE_ID
148+
UPSTREAM_PIPELINE_REF: $CI_COMMIT_REF_NAME
149+
allow_failure: true
150+
119151
benchmark-serverless:
120152
stage: benchmarks
121153
image: registry.ddbuild.io/ci/serverless-tools:1
+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/bin/bash
2+
#
3+
# This scripts downloads the necessary binaries to be used for the AWS Lambda Layer.
4+
# This artifacts include: Tracer and ClrProfiler
5+
#
6+
7+
set -eo pipefail
8+
9+
# Create a directory to store the files
10+
target_dir=artifacts
11+
mkdir -p $target_dir
12+
13+
branchName="refs/heads/$CI_COMMIT_BRANCH"
14+
15+
echo "Looking for azure devops PR builds for branch '$branchName' for commit '$CI_COMMIT_SHA' to start"
16+
17+
# We should _definitely_ have the build by now, so if not, there probably won't be one
18+
# Check for PR builds first (as more likely to be "full" builds)
19+
allBuildsForPrUrl="https://dev.azure.com/datadoghq/dd-trace-dotnet/_apis/build/builds?api-version=7.1&definitions=54&\$top=100&queryOrder=queueTimeDescending&reasonFilter=pullRequest"
20+
buildId=$(curl -sS $allBuildsForPrUrl | jq --arg version $CI_COMMIT_SHA --arg branch $CI_COMMIT_BRANCH '.value[] | select(.triggerInfo["pr.sourceBranch"] == $branch and .triggerInfo["pr.sourceSha"] == $version) | .id' | head -n 1)
21+
22+
if [ -z "${buildId}" ]; then
23+
echo "No PR builds found for commit '$CI_COMMIT_SHA' on branch '$branchName'. Checking for standalone builds..."
24+
allBuildsForBranchUrl="https://dev.azure.com/datadoghq/dd-trace-dotnet/_apis/build/builds?api-version=7.1&definitions=54&\$top=10&queryOrder=queueTimeDescending&branchName=$branchName&reasonFilter=manual,individualCI"
25+
buildId=$(curl -sS $allBuildsForBranchUrl | jq --arg version $CI_COMMIT_SHA '.value[] | select(.sourceVersion == $version and .reason != "schedule") | .id' | head -n 1)
26+
fi
27+
28+
if [ -z "${buildId}" ]; then
29+
echo "No build found for commit '$CI_COMMIT_SHA' on branch '$branchName' (including PRs)"
30+
exit 1
31+
fi
32+
33+
echo "Found build with id '$buildId' for commit '$CI_COMMIT_SHA' on branch '$branchName'"
34+
35+
architectures=("x64" "arm64")
36+
for architecture in "${architectures[@]}"; do
37+
echo "Looking for artifacts for architecture '$architecture'"
38+
39+
artifacts=("linux-tracer-home-linux-$architecture-r2r" "linux-universal-home-linux-$architecture")
40+
41+
# Now try to download the artifacts from the build
42+
for artifactName in "${artifacts[@]}"; do
43+
artifactsUrl="https://dev.azure.com/datadoghq/dd-trace-dotnet/_apis/build/builds/$buildId/artifacts?api-version=7.1&artifactName=$artifactName"
44+
45+
# Keep trying to get the artifact for 30 minutes
46+
downloadUrl=""
47+
TIMEOUT=1800
48+
STARTED=0
49+
until (( STARTED == TIMEOUT )) || [ ! -z "${downloadUrl}" ] ; do
50+
echo "Checking for '$artifactName' at '$artifactsUrl'..."
51+
# If the artifact doesn't exist, .resource.downloadUrl will be null, so we filter that out
52+
downloadUrl=$(curl -s $artifactsUrl | jq -r '.resource.downloadUrl | select( . != null )')
53+
sleep 100
54+
(( STARTED += 100 ))
55+
done
56+
(( STARTED < TIMEOUT ))
57+
58+
if [ -z "${downloadUrl}" ]; then
59+
echo "No downloadUrl found after 30 minutes for commit '$CI_COMMIT_SHA' on branch '$branchName'"
60+
exit 1
61+
fi
62+
63+
echo "Downloading '$artifactName' from '$downloadUrl'..."
64+
curl -o $target_dir/artifacts.zip "$downloadUrl"
65+
unzip $target_dir/artifacts.zip -d $target_dir/$architecture
66+
mv $target_dir/$architecture/$artifactName/* $target_dir/$architecture
67+
rm -rf $target_dir/artifacts.zip
68+
rmdir $target_dir/$architecture/$artifactName
69+
done
70+
done
71+
72+
ls -l $target_dir

.nuke/build.schema.json

+8
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@
263263
"type": "string",
264264
"description": "Root directory during build execution"
265265
},
266+
"RuntimeIdentifier": {
267+
"type": "string",
268+
"description": "RuntimeIdentifier sets the target platform for ReadyToRun assemblies in 'PublishManagedTracerR2R'.See https://learn.microsoft.com/en-us/dotnet/core/rid-catalog"
269+
},
266270
"SampleName": {
267271
"type": "string",
268272
"description": "The sample name to execute when running or building sample apps"
@@ -296,6 +300,7 @@
296300
"BuildIisSampleApp",
297301
"BuildLinuxIntegrationTests",
298302
"BuildManagedTracerHome",
303+
"BuildManagedTracerHomeR2R",
299304
"BuildMsi",
300305
"BuildNativeLoader",
301306
"BuildNativeTracerHome",
@@ -405,6 +410,7 @@
405410
"PublishDdDotnetSymbolsWindows",
406411
"PublishIisSamples",
407412
"PublishManagedTracer",
413+
"PublishManagedTracerR2R",
408414
"PublishNativeLoader",
409415
"PublishNativeLoaderOsx",
410416
"PublishNativeLoaderUnix",
@@ -515,6 +521,7 @@
515521
"BuildIisSampleApp",
516522
"BuildLinuxIntegrationTests",
517523
"BuildManagedTracerHome",
524+
"BuildManagedTracerHomeR2R",
518525
"BuildMsi",
519526
"BuildNativeLoader",
520527
"BuildNativeTracerHome",
@@ -624,6 +631,7 @@
624631
"PublishDdDotnetSymbolsWindows",
625632
"PublishIisSamples",
626633
"PublishManagedTracer",
634+
"PublishManagedTracerR2R",
627635
"PublishNativeLoader",
628636
"PublishNativeLoaderOsx",
629637
"PublishNativeLoaderUnix",

tracer/build/_build/Build.Steps.cs

+37-10
Original file line numberDiff line numberDiff line change
@@ -639,23 +639,50 @@ async Task DownloadWafVersion(string libddwafVersion = null, string uncompressFo
639639
.EnableNoRestore()
640640
.CombineWith(targetFrameworks, (p, framework) => p
641641
.SetFramework(framework)
642-
.SetOutput(MonitoringHomeDirectory / framework)));
642+
.SetOutput(MonitoringHomeDirectory / framework))
643+
);
643644
});
644645

646+
Target PublishManagedTracerR2R => _ => _
647+
.Unlisted()
648+
.After(CompileManagedSrc)
649+
.Executes(() =>
650+
{
651+
var targetFramework = TargetFramework.NET6_0;
652+
653+
// Needed as we need to restore with the RuntimeIdentifier
654+
DotNetRestore(s => s
655+
.SetProjectFile(Solution.GetProject(Projects.DatadogTraceMsBuild))
656+
.SetPublishReadyToRun(true)
657+
.SetRuntime(RuntimeIdentifier)
658+
);
659+
660+
DotNetPublish(s => s
661+
.SetProject(Solution.GetProject(Projects.DatadogTraceMsBuild))
662+
.SetConfiguration(BuildConfiguration)
663+
.SetTargetPlatformAnyCPU()
664+
.SetPublishReadyToRun(true)
665+
.SetRuntime(RuntimeIdentifier)
666+
.SetSelfContained(false)
667+
.SetFramework(targetFramework)
668+
.SetOutput(MonitoringHomeDirectory / targetFramework)
669+
);
670+
});
671+
645672
Target PublishNativeSymbolsWindows => _ => _
646-
.Unlisted()
647-
.OnlyWhenStatic(() => IsWin)
648-
.After(CompileTracerNativeSrc, PublishManagedTracer)
649-
.Executes(() =>
650-
{
651-
foreach (var architecture in ArchitecturesForPlatformForTracer)
652-
{
673+
.Unlisted()
674+
.OnlyWhenStatic(() => IsWin)
675+
.After(CompileTracerNativeSrc, PublishManagedTracer)
676+
.Executes(() =>
677+
{
678+
foreach (var architecture in ArchitecturesForPlatformForTracer)
679+
{
653680
var source = NativeTracerProject.Directory / "bin" / BuildConfiguration / architecture.ToString() /
654681
$"{NativeTracerProject.Name}.pdb";
655682
var dest = SymbolsDirectory / $"win-{architecture}" / Path.GetFileName(source);
656683
CopyFile(source, dest, FileExistsPolicy.Overwrite);
657-
}
658-
});
684+
}
685+
});
659686

660687
Target PublishDdDotnetSymbolsWindows => _ => _
661688
.Unlisted()

tracer/build/_build/Build.Utilities.cs

+16
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,22 @@ private static MSBuildTargetPlatform GetDefaultTargetPlatform()
492492

493493
return MSBuildTargetPlatform.x64;
494494
}
495+
496+
private static string GetDefaultRuntimeIdentifier(bool isAlpine)
497+
{
498+
// https://learn.microsoft.com/en-us/dotnet/core/rid-catalog
499+
return (Platform, (string)GetDefaultTargetPlatform()) switch
500+
{
501+
(PlatformFamily.Windows, "x86") => "win-x86",
502+
(PlatformFamily.Windows, "x64") => "win-x64",
503+
504+
(PlatformFamily.Linux, "x64") => isAlpine ? "linux-musl-x64" : "linux-x64",
505+
(PlatformFamily.Linux, "ARM64" or "ARM64EC") => isAlpine ? "linux-musl-arm64" : "linux-arm64",
506+
507+
(PlatformFamily.OSX, "ARM64" or "ARM64EC") => "osx-arm64",
508+
_ => null
509+
};
510+
}
495511

496512
private static MSBuildTargetPlatform ARM64TargetPlatform = (MSBuildTargetPlatform)"ARM64";
497513
private static MSBuildTargetPlatform ARM64ECTargetPlatform = (MSBuildTargetPlatform)"ARM64EC";

0 commit comments

Comments
 (0)