Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7022b47
Add HybridUnwinder for ARM64 only
gleocadie Mar 19, 2026
54b4333
Add CI job
gleocadie Mar 19, 2026
02a29e0
Make sure profiler is not disabled in the code
gleocadie Mar 19, 2026
7093f0a
Fix path construction when running the integration tests
gleocadie Mar 19, 2026
c808f72
Fix bug in ManagedCodeCache
gleocadie Mar 19, 2026
9195795
Fix native loader
gleocadie Mar 19, 2026
4deeae6
Fix tracer/profiler test
gleocadie Mar 19, 2026
fd55320
Fix bugs
gleocadie Mar 19, 2026
3fbeaae
Fix framework for test + check lr-fallback approach
gleocadie Mar 20, 2026
c835d15
Make it better
gleocadie Mar 20, 2026
3d2e3ee
Display in CI stack mismatch
gleocadie Mar 20, 2026
fe2757c
Try fixing stack walking with jit stub/helper
gleocadie Mar 20, 2026
b210b4f
Try fixing net9 issue with stack collection
gleocadie Mar 20, 2026
e6fa80c
Try something: more native frames mixed with managed frames
gleocadie Mar 23, 2026
972e329
Fix deadlock
gleocadie Mar 23, 2026
c916852
Try fixing crash in libunwind
gleocadie Mar 24, 2026
68d731d
TO run CI
gleocadie Mar 24, 2026
655c27a
Add UnwindTracer
gleocadie Mar 25, 2026
89a798b
Fix build + adjust libunwind mirrored data structures
gleocadie Mar 27, 2026
ce425bc
Try another one fix
gleocadie Mar 28, 2026
d984ffe
Try my fix
gleocadie Mar 28, 2026
7a40684
Try something else with UnwindTracersProvider
gleocadie Mar 30, 2026
288b808
Build ME
gleocadie Mar 31, 2026
909e163
Try new cursor snapshot api + cfa update in unw_step
gleocadie Apr 3, 2026
5c2fd19
add RecordStart with ucontext_t address
gleocadie Apr 13, 2026
724389d
Finish early TimerCreate-based CPU profiler
gleocadie Apr 13, 2026
62f3ca3
Add Sanitizers jobs
gleocadie Apr 13, 2026
1eaa1f0
Try fixigin ubsan job
gleocadie Apr 13, 2026
e298a45
Fix asan job
gleocadie Apr 13, 2026
79786bb
Investigate crash
gleocadie Apr 14, 2026
5c1a535
Try fixing ubsan
gleocadie Apr 16, 2026
433c864
Fix build
gleocadie Apr 17, 2026
3089ceb
Start clean up a bit
gleocadie Apr 20, 2026
a534494
Fix FrameStore
gleocadie Apr 21, 2026
dfd96d4
Try fixing test
gleocadie Apr 21, 2026
6ff543c
Clean up
gleocadie Apr 22, 2026
1ea736e
More cleanup
gleocadie Apr 22, 2026
9c812c4
fix(profiler): restore unique-ownership semantics on ScopedTracer (ar…
gleocadie Apr 22, 2026
5e7dffb
chore(profiler): arm64 polish pass (logs, comments, atomics, EOF newl…
gleocadie Apr 22, 2026
3eee3d7
docs(profiler): capture arm64 build-system gotchas (C7, E1..E4)
gleocadie Apr 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .azure-pipelines/steps/update-github-pipeline-status.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ stages:
- integration_tests_linux_debugger
- profiler_integration_tests_windows
- profiler_integration_tests_linux
- profiler_integration_tests_arm64
- asan_profiler_tests
- asan_arm64_profiler_tests
- ubsan_arm64_profiler_tests
- ubsan_profiler_tests
- tsan_profiler_tests
- integration_tests_arm64
Expand Down Expand Up @@ -118,7 +121,10 @@ stages:
in(dependencies.integration_tests_linux_debugger.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.profiler_integration_tests_windows.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.profiler_integration_tests_linux.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.profiler_integration_tests_arm64.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.asan_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.asan_arm64_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.ubsan_arm64_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.ubsan_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.tsan_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.integration_tests_arm64.result, 'Succeeded','SucceededWithIssues','Skipped'),
Expand Down Expand Up @@ -209,7 +215,10 @@ stages:
- integration_tests_linux_debugger
- profiler_integration_tests_windows
- profiler_integration_tests_linux
- profiler_integration_tests_arm64
- asan_profiler_tests
- asan_arm64_profiler_tests
- ubsan_arm64_profiler_tests
- ubsan_profiler_tests
- tsan_profiler_tests
- integration_tests_arm64
Expand Down Expand Up @@ -288,7 +297,10 @@ stages:
in(dependencies.integration_tests_linux_debugger.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.profiler_integration_tests_windows.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.profiler_integration_tests_linux.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.profiler_integration_tests_arm64.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.asan_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.asan_arm64_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.ubsan_arm64_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.ubsan_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.tsan_profiler_tests.result, 'Succeeded','SucceededWithIssues','Skipped'),
in(dependencies.integration_tests_arm64.result, 'Succeeded','SucceededWithIssues','Skipped'),
Expand Down
209 changes: 209 additions & 0 deletions .azure-pipelines/ultimate-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2907,6 +2907,107 @@ stages:
testResultsFiles: profiler/build_data/results/**/*.trx
condition: succeededOrFailed()

- stage: profiler_integration_tests_arm64
condition: >
and(
succeeded(),
or(
eq(variables.isMainOrReleaseBranch, true),
eq(dependencies.generate_variables.outputs['generate_variables_job.generate_variables_step.IsProfilerChanged'], 'True')
)
)
dependsOn: [package_arm64, generate_variables, merge_commit_id]
variables:
targetShaId: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.sha']]
targetBranch: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.branch']]
jobs:
- template: steps/update-github-status-jobs.yml
parameters:
jobs: [Test]

- job: Test
timeoutInMinutes: 60 #default value
strategy:
matrix:
arm64:
baseImage: debian
artifactSuffix: linux-arm64
alpine:
baseImage: alpine
artifactSuffix: linux-musl-arm64

variables:
IncludeMinorPackageVersions: $[eq(variables.perform_comprehensive_testing, 'true')]

pool:
name: $(linuxArm64Pool)

steps:
- template: steps/clone-repo.yml
parameters:
targetShaId: $(targetShaId)
targetBranch: $(targetBranch)

- template: steps/restore-working-directory.yml
parameters:
artifact: build-$(artifactSuffix)-working-directory

- template: steps/download-artifact.yml
parameters:
artifact: linux-monitoring-home-$(artifactSuffix)
path: $(monitoringHome)

- template: steps/download-artifact.yml
parameters:
artifact: linux-profiler-symbols-$(artifactSuffix)
path: $(monitoringHome)

- template: steps/run-in-docker.yml
parameters:
build: true
baseImage: $(baseImage)
command: "BuildProfilerSamples"
apiKey: $(DD_LOGGER_DD_API_KEY)
retryCountForRunCommand: 3

- template: steps/run-in-docker.yml
parameters:
baseImage: $(baseImage)
command: "BuildAndRunProfilerCpuLimitTests"
extraArgs: "--cpus 2 --env CONTAINER_CPUS=1"
apiKey: $(DD_LOGGER_DD_API_KEY)
retryCountForRunCommand: 3

- template: steps/run-in-docker.yml
parameters:
baseImage: $(baseImage)
command: "BuildAndRunProfilerCpuLimitTests"
extraArgs: "--cpus 0.5 --env CONTAINER_CPUS=0.5"
apiKey: $(DD_LOGGER_DD_API_KEY)
retryCountForRunCommand: 3

- script: |
docker-compose -f docker-compose.yml -p $(DockerComposeProjectName) \
run --rm \
-e baseImage=$(baseImage) \
ProfilerIntegrationTests
displayName: docker-compose run --no-deps ProfilerIntegrationTests
env:
DD_LOGGER_DD_API_KEY: $(ddApiKey)
baseImage: $(baseImage) # for interpolation in the docker-compose file

- publish: profiler/build_data
artifact: _$(System.StageName)_$(Agent.JobName)_logs_$(System.JobAttempt)
condition: always()
continueOnError: true

- task: PublishTestResults@2
displayName: publish test results
inputs:
testResultsFormat: VSTest
testResultsFiles: profiler/build_data/results/**/*.trx
condition: succeededOrFailed()

- stage: asan_profiler_tests
#address sanitizer tests
condition: >
Expand Down Expand Up @@ -2992,6 +3093,114 @@ stages:
condition: always()
continueOnError: false

- stage: asan_arm64_profiler_tests
#address sanitizer tests on arm64
condition: >
and(
succeeded(),
eq(dependencies.generate_variables.outputs['generate_variables_job.generate_variables_step.IsProfilerChanged'], 'True')
)
dependsOn: [merge_commit_id, generate_variables]
variables:
targetShaId: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.sha']]
targetBranch: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.branch']]
jobs:
- template: steps/update-github-status-jobs.yml
parameters:
jobs: [Linux]

- job: Linux
timeoutInMinutes: 60

pool:
name: $(linuxArm64Pool)

steps:
- template: steps/clone-repo.yml
parameters:
targetShaId: $(targetShaId)
targetBranch: $(targetBranch)

- template: steps/run-in-docker.yml
parameters:
build: true
baseImage: debian
command: "BuildProfilerAsanTest -Framework net7.0"
apiKey: $(DD_LOGGER_DD_API_KEY)

- template: steps/run-in-docker.yml
parameters:
build: true
baseImage: debian
command: "BuildProfilerSampleForSanitiserTests -Framework net7.0"
apiKey: $(DD_LOGGER_DD_API_KEY)

- template: steps/run-in-docker.yml
parameters:
baseImage: debian
command: "RunSampleWithProfilerAsan -Framework net7.0"
apiKey: $(DD_LOGGER_DD_API_KEY)

- publish: profiler/build_data
displayName: Uploading Address sanitizer test results
artifact: _$(System.StageName)_$(Agent.JobName)_test_results_$(System.JobAttempt)
condition: always()
continueOnError: false

- stage: ubsan_arm64_profiler_tests
#undefined behavior sanitizer tests on arm64
condition: >
and(
succeeded(),
eq(dependencies.generate_variables.outputs['generate_variables_job.generate_variables_step.IsProfilerChanged'], 'True')
)
dependsOn: [merge_commit_id, generate_variables]
variables:
targetShaId: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.sha']]
targetBranch: $[ stageDependencies.merge_commit_id.fetch.outputs['set_sha.branch']]
jobs:
- template: steps/update-github-status-jobs.yml
parameters:
jobs: [Linux]

- job: Linux
timeoutInMinutes: 60

pool:
name: $(linuxArm64Pool)

steps:
- template: steps/clone-repo.yml
parameters:
targetShaId: $(targetShaId)
targetBranch: $(targetBranch)

- template: steps/run-in-docker.yml
parameters:
build: true
baseImage: debian
command: "BuildProfilerUbsanTest -Framework net7.0"
apiKey: $(DD_LOGGER_DD_API_KEY)

- template: steps/run-in-docker.yml
parameters:
build: true
baseImage: debian
command: "BuildProfilerSampleForSanitiserTests -Framework net7.0"
apiKey: $(DD_LOGGER_DD_API_KEY)

- template: steps/run-in-docker.yml
parameters:
baseImage: debian
command: "RunSampleWithProfilerUbsan -Framework net7.0"
apiKey: $(DD_LOGGER_DD_API_KEY)

- publish: profiler/build_data
displayName: Uploading test results
artifact: _$(System.StageName)_$(Agent.JobName)_logs_$(System.JobAttempt)
condition: always()
continueOnError: false

- stage: ubsan_profiler_tests
#undefined behavior sanitizer tests
condition: >
Expand Down
23 changes: 21 additions & 2 deletions build/cmake/FindLibunwind.cmake
Original file line number Diff line number Diff line change
@@ -1,10 +1,29 @@
SET(LIBUNWIND_VERSION "v1.8.3")
# We intentionally pin to the DataDog/libunwind fork on tag
# gleocadie/v1.8.1-custom-3 rather than upstream libunwind v1.8.1 or v1.8.3.
# The fork carries the following patches that the Continuous Profiler's
# HybridUnwinder depends on (arm64 Linux):
# - unw_cursor_snapshot_t / unw_cursor_snapshot(): a signal-safe public API
# to inspect the dwarf cursor (CFA, loc_fp/loc_lr/loc_sp, frame_type,
# cfa_reg_sp, cfa_reg_offset, dwarf_step_ret, step_method, loc_info).
# Used by UnwinderTracer.h / HybridUnwinder.cpp without having to mirror
# libunwind's internal layouts.
# - unw_init_local2() + UNW_INIT_SIGNAL_FRAME flag: lets us initialize the
# cursor directly from a signal-delivered ucontext_t and flag the first
# frame as a signal frame so libunwind returns the interrupted PC instead
# of the signal-trampoline PC.
# - Additional accessors on the tdep_frame (fp_cfa_offset / lr_cfa_offset /
# sp_cfa_offset, cfa_is_unreliable, next_to_signal_frame) consumed by the
# tracer for diagnostics.
# Upstream libunwind 1.8.3 does not expose these APIs. When they land upstream
# (or when the fork is rebased on top of a newer upstream tag), update this
# file accordingly.
SET(LIBUNWIND_VERSION "v1.8.1-custom-3")

SET(LIBUNWIND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/libunwind-prefix/src/libunwind-build)

ExternalProject_Add(libunwind
GIT_REPOSITORY https://github.com/DataDog/libunwind.git
GIT_TAG gleocadie/v1.8.3
GIT_TAG gleocadie/v1.8.1-custom-3
GIT_PROGRESS true
INSTALL_COMMAND ""
UPDATE_COMMAND ""
Expand Down
10 changes: 8 additions & 2 deletions profiler/src/Demos/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

Expand All @@ -7,7 +7,13 @@
<PropertyGroup>
<!-- only run .NET Framework tests on Windows -->
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net48;netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' And '$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' != 'Arm64'">netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<!--
netcoreapp3.1 is deliberately excluded on arm64 Linux: the Continuous Profiler
refuses to initialize when major < 5 on that platform (see CorProfilerCallback::Initialize),
so running the demos against .NET Core 3.1 arm64 would produce no profiles at all.
-->
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' And '$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'Arm64'">net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<Platforms>AnyCPU;x64;x86</Platforms>

<!-- Hide warnings for EOL .NET Core targets (e.g. netcoreapp3.0) -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' And '$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' != 'Arm64'">netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' And '$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'Arm64'">net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<Platforms>AnyCPU;x64;x86</Platforms>

<!--This is required for smoke test assembly discovery-->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' And '$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' != 'Arm64'">netcoreapp3.1;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' And '$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture)' == 'Arm64'">net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<RootNamespace>Samples.Website_AspNetCore01</RootNamespace>
<Platforms>AnyCPU;x64;x86</Platforms>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ endif()
# ******************************************************

SET(API_WRAPPER_BASENAME Datadog.Linux.ApiWrapper)
# For arm64, we cannot replace the x64 suffix with arm64.
# This library is already shipped and used by customers. Their scripts expect the x64 suffix.
# SSI relies on this file.
# Changing this would bring little value but lots of headaches.
SET(API_WRAPPER_SHARED_LIB_NAME ${API_WRAPPER_BASENAME}.x64)

SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${DEPLOY_DIR})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@

Backtrace2Unwinder::Backtrace2Unwinder() = default;

std::int32_t Backtrace2Unwinder::Unwind(void* ctx, std::uintptr_t* buffer, std::size_t bufferSize) const
std::int32_t Backtrace2Unwinder::Unwind(void* ctx, std::uintptr_t* buffer, std::size_t bufferSize,
std::uintptr_t stackBase, std::uintptr_t stackEnd,
UnwinderTracer* tracer) const
{
// unw_backtrace2 handles the case ctx == nullptr
auto* context = reinterpret_cast<unw_context_t*>(ctx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class Backtrace2Unwinder : public IUnwinder
~Backtrace2Unwinder() override = default;

// Returns the number of frames unwound
std::int32_t Unwind(void* ctx, std::uintptr_t* buffer, std::size_t bufferSize) const override;
std::int32_t Unwind(void* ctx, std::uintptr_t* buffer, std::size_t bufferSize,
std::uintptr_t stackBase = 0, std::uintptr_t stackEnd = 0,
UnwinderTracer* tracer = nullptr) const override;

};
};
Loading
Loading