From 6f498794fe3768023c9c644f864d4356ba3f6498 Mon Sep 17 00:00:00 2001 From: Bryan Antigua Date: Fri, 16 May 2025 17:04:06 -0400 Subject: [PATCH 01/15] added new page for automated analysis, as well as screenshots --- config/_default/menus/main.en.yaml | 25 ++-- content/en/profiler/automated_analysis.md | 114 ++++++++++++++++++ .../profiler/connect_traces_and_profiles.md | 13 +- .../profiler/profiling_automated_analysis.png | Bin 0 -> 679370 bytes ...rofiling_automated_analysis_aggregated.png | Bin 0 -> 860490 bytes .../profiling_automated_analysis_banner.png | Bin 0 -> 575096 bytes .../profiling_automated_analysis_column.png | Bin 0 -> 495624 bytes .../profiling_automated_analysis_details.png | Bin 0 -> 711843 bytes ...rofiling_automated_analysis_individual.png | Bin 0 -> 687209 bytes 9 files changed, 137 insertions(+), 15 deletions(-) create mode 100644 content/en/profiler/automated_analysis.md create mode 100644 static/images/profiler/profiling_automated_analysis.png create mode 100644 static/images/profiler/profiling_automated_analysis_aggregated.png create mode 100644 static/images/profiler/profiling_automated_analysis_banner.png create mode 100644 static/images/profiler/profiling_automated_analysis_column.png create mode 100644 static/images/profiler/profiling_automated_analysis_details.png create mode 100644 static/images/profiler/profiling_automated_analysis_individual.png diff --git a/config/_default/menus/main.en.yaml b/config/_default/menus/main.en.yaml index d4e253c1a05ae..13ff86e4b2211 100644 --- a/config/_default/menus/main.en.yaml +++ b/config/_default/menus/main.en.yaml @@ -4093,56 +4093,61 @@ menu: parent: profiler identifier: profiler_compare weight: 5 + - name: Automated Analysis + url: profiler/automated_analysis + parent: profiler + identifier: profiler_automated_analysis + weight: 6 - name: Profiler Troubleshooting url: profiler/profiler_troubleshooting/ parent: profiler identifier: profiler_troubleshooting - weight: 6 + weight: 7 - name: Java url: profiler/profiler_troubleshooting/java/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_java - weight: 601 + weight: 701 - name: Python url: profiler/profiler_troubleshooting/python/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_python - weight: 602 + weight: 702 - name: Go url: profiler/profiler_troubleshooting/go/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_go - weight: 603 + weight: 703 - name: Ruby url: profiler/profiler_troubleshooting/ruby/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_ruby - weight: 604 + weight: 704 - name: Node.js url: profiler/profiler_troubleshooting/nodejs/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_nodejs - weight: 605 + weight: 705 - name: .NET url: profiler/profiler_troubleshooting/dotnet/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_dotnet - weight: 606 + weight: 706 - name: PHP url: profiler/profiler_troubleshooting/php/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_php - weight: 607 + weight: 707 - name: C/C++/Rust url: profiler/profiler_troubleshooting/ddprof/ parent: profiler_troubleshooting identifier: profiler_troubleshooting_linux - weight: 608 + weight: 708 - name: Guides url: profiler/guide/ parent: profiler identifier: profiler_guides - weight: 7 + weight: 8 - name: Database Monitoring url: database_monitoring/ pre: database-2 diff --git a/content/en/profiler/automated_analysis.md b/content/en/profiler/automated_analysis.md new file mode 100644 index 0000000000000..0b795d6240a13 --- /dev/null +++ b/content/en/profiler/automated_analysis.md @@ -0,0 +1,114 @@ +--- +title: Automated Analysis +description: Automatically surfacing critical issues with contextual insights and recommended next steps +aliases: + - /profiler/automated_analysis/ +further_reading: + - link: 'profiler/enabling' + tag: 'Documentation' + text: 'Enable continuous profiler for your application' + - link: 'getting_started/profiler' + tag: 'Documentation' + text: 'Getting Started with Profiler' + - link: 'https://www.datadoghq.com/blog/introducing-datadog-profiling/' + tag: 'Blog' + text: 'Introducing always-on production profiling in Datadog' + - link: 'https://www.datadoghq.com/blog/continuous-profiler-timeline-view/' + tag: 'Blog' + text: "Diagnose runtime and code inefficiencies using Continuous Profiler's timeline view" +multifiltersearch: + # "id" must match the corresponding key in the "data" object + headers: + - name: Name + id: name + filter_by: true + - name: Severity + id: severity + filter_by: true + - name: Description + id: description + filter_by: false + + data: + - name: GC Setup + severity: Info + description: Triggers when one of the following is detected - serial GC used on a multi-core machine, parallel GC on a single-core machine, more GC threads were configured than available cores, or a parallel GC was configured to run in 1 thread + - name: Duplicated Flags + severity: Info + description: Triggers if duplicate flags were provided to the runtime (e.g. `-Xmx2g -Xmx5g`). This is a problem as it may lead to changes not having the expected effect. + - name: Options + severity: Warn + description: Triggers if undocumented, deprecated or non-recommended option flags were detected. + - name: Stackdepth Setting + severity: Warn + description: Triggers if events were found with truncated stacktraces which may make it hard to understand profiling data. + - name: VMOperation Peak Duration + severity: Warn + description: Triggers if a blocking VM operation (or combination of ops close in time) taking more than 2 seconds. Reports details about the operation with the highest duration. + - name: GC Pauses + severity: Warn + description: Triggers if more than 10% of time was spent in GC pauses. + - name: GC Pause Peak Duration + severity: Info + description: Triggers if at least one GC pause took more than 1 second. + - name: Deadlocked Threads + severity: Warn + description: Triggers if we see a custom datadog event capturing deadlocked threads during the profile. + - name: Deadlocked Threads Detected + severity: Warn + description: Triggers if max number of deadlocked threads over query context is bigger than 0. + - name: Thrown Exceptions + severity: Warn + description: Triggers when the rate of thrown (caught and uncaught) exceptions per minute goes above a threshold (defauls to 10K) + - name: Primitive Value Boxing + severity: Info + description: Triggers if more than 5% of CPU time was spent doing primitive<>object value conversions. + - name: Explicit GC + severity: Info + description: Triggers if there are System.gc() calls. + - name: Head of line blocking + severity: Info + description: Triggers if a queue event gets stuck behind the given activity. +--- + +## Overview +Automated Analysis helps teams detect and troubleshoot problems faster, without requiring deep expertise in code profiling. Powered by Continuous Profiler, Automated Analysis continuously monitors your applications and surfaces critical issues in real time, along with actionable insights to guide resolution. When a problem is detected, Automated Analysis provides: + +- A high-level summary explaining the issue and why it matters +- Contextual insights from profiling data (e.g., affected methods, packages, or processes) +- Recommended next steps to help you resolve the issue efficiently + +By reducing the expertise required to take action, Automated Analysis enables faster resolution of performance issues, increases product adoption, and helps teams avoid costly blind spots. It also lays the foundation for powering performance and cost insights across the Datadog platform. + + +{{< img src="profiler/profiling_automated_analysis.png" alt="The Profiler Thread Time line showing a Thrown Exception insight" style="width:100%;" >}} + +## Explore insights +Automated Analysis will be surfaced within the [Profile explorer][1] +- As a banner at the top of the page when you're scoped to a specific service +{{< img src="profiler/profiling_automated_analysis_banner.png" alt="The Automated Analysis banner displaying insights detected for a given service" style="width:100%;">}} +- As a column within the service list +{{< img src="profiler/profiling_automated_analysis_column.png" alt="The Automated Analysis column displaying insights detected for a given service within the service list" style="width:100%;">}} + +Clicking an an insight in either area will display a high-level summary explaining the issue, contextual insights from profiling data, and recommended next steps. +{{< img src="profiler/profiling_automated_analysis_details.png" alt="Expanded Profiling Insights showing the details of a detected Issue" style="width:100%;">}} + +## Aggregated vs Individual Insights +Individual insights are tied to a specific profile and show up directly in the flamegraph and timeline views. They highlight problems detected within a single recording, giving detailed context about a specific performance issue observed in that exact moment. +{{< img src="profiler/profiling_automated_analysis_individual.png" alt="Example of an individual profile insight within the trace explorer" style="width:100%;">}} + +Aggregated insights, on the other hand, are surfaced at the service level and represent patterns detected across many profiles. They help you identify recurring or systemic issues affecting a service over time, making them ideal for quickly spotting problematic trends without digging into individual profiles. +{{< img src="profiler/profiling_automated_analysis_aggregated.png" alt="Example of an aggregated insight within the profiler explorer" style="width:100%;">}} + + +## Supported Insights + +{{< multifilter-search >}} + + +## Further reading + +{{< partial name="whats-next/whats-next.html" >}} + +[1]: https://app.datadoghq.com/profiling/explorer + diff --git a/content/en/profiler/connect_traces_and_profiles.md b/content/en/profiler/connect_traces_and_profiles.md index 9a48080c33a51..05fb40c87cd43 100644 --- a/content/en/profiler/connect_traces_and_profiles.md +++ b/content/en/profiler/connect_traces_and_profiles.md @@ -116,15 +116,18 @@ The Trace to Profiling integration is enabled when you [turn on profiling for yo ### Span execution timeline view -{{< img src="profiler/profiles_tab.png" alt="Profiles tab has a timeline view that breaks down threads and execution over time" >}} +{{< img src="profiler/profiling_automated_analysis_individual.png" alt="Profiles tab has a timeline view that breaks down threads and execution over time" >}} -The timeline view surfaces time-based patterns and work distribution over the period of the span. +The timeline view surfaces time-based patterns and work distribution over the period of the span. It provides a visual breakdown of how threads contributed to the request over time. With the span timeline view, you can: -- Isolate time-consuming methods. -- Sort out complex interactions between threads. -- Surface runtime activity that impacted the request. +- Isolate time-consuming methods +- Sort out complex interactions between threads +- Surface runtime activity that impacted the request +- Leverage [Automated Analysis][1] to highlight performance issues directly in the view, such as oversized thread pools or GC contention + +[1]: https://www.datadoghq.com//profiler/automated_analysis/ Depending on the runtime and language, the lanes vary: diff --git a/static/images/profiler/profiling_automated_analysis.png b/static/images/profiler/profiling_automated_analysis.png new file mode 100644 index 0000000000000000000000000000000000000000..f4744c8aeebb3ebd35f0c69483a8b0dcde8ad19e GIT binary patch literal 679370 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 z zOxXFvGr5?KW1Y!qS0xD}a|ZC*wk2HS$zvo6N-BLC{;qNR^8jb?slB16EDl@ha*a=v z*tAEcs$dD&aUhK&$%?j@lpNZ2y&~^YSciabBovpkvt{@lC%pXnOq+el{nJFLb{7xi z5WE-N8YHh!6sxO{@>V6!D2dkjWQMOz$QY}GvzzH4UHn#|4vN*^Ad9Po;)%WI!Pr@Hpn@?CUElJjXxY&>k> zxbn5b_|UXmXKINk?_{*tRUt%Sp~zvbQ{OTKPhIOn`jg+?eUZ*#1viK}ujHg-!S}J1 z@-n9*WQ6)p9B+{^d}t-$8Cfwv>d3(~YKW8zh0T;1Qx$~|tkktiS|t!=QOwPej?*)aXfLL44k3u)DY#p`?qAp@d@V*c)3b>5wKtP&O12TLn?)$ zt_oTz(W5HA>$EC=*KHD{_sgY~>-TpLK=NmLc(lFY&;>tvy7@CnlzoBo)JEd5g$Y>m z=K9>EO-SfM7e~*3wo?15E7q^I*=qx^fTtB#ggXSgCq%dBhm$I}=|=70uwBP_%l01> zGmeW%7Zy=2OTkK1( zjt=2*uZ^!Se3e}Z9|}E0^%okOKppYf8jnf!<^6_i?_kQ}i0+k!Zw?f(F6SoL070b= z1br89;-k&cpQNhsO>hDs%m05QJ;oLA-efO23am*EWq9}T;vu(Uu&>hoLx!rhw(y{^ ztl&NO=60k?I*6e$eD{+T`e>_AVQRU7oRj_7<<5R_=r{^BW9ub!s1NrXKHYG^FZbX+ zy%QP=Ebu9slaUF{G88PbfZeQu#_`$@v9|G%2pFl(^^3Of!zp3Y&Wtr(=kJ%) zZGIcpI16dW>s5L#64nGLq%UH3%{0kz&VG_L&^J1-y!8pE^|IadVBPMyfo#@v-xm%u7{XAB*Q|d{4f50Hhfj@J15j=|fZ!{U^Cl6WkXr1?j~iMD1KqlA zn<`hseqxI2Nz2vQ0G_lQTg>2#?Q1($Htz%B7ge)uw;x;&W_AB3+#)^vN;1m>KJ*)i zVQRYbclyA`u=6(uoy^W_r_<~Ke&Pf1Y;ls<5|;@$ufPkJim zr2LWyN||*bsdM0!F*1JeF+Ur)%PqMgPT1qmb)@e=C!iI{XSt?{-&c$?#H0Ah#LUB! z{7VB;eU9=pVAM9-TB?KD;;q&bxbZ434vR$KKnreI1Oxf&P9CgaOI!v{<|R2`;k1n-B8t!dz>oR zY0os_jy@$9np!=%GDCQDjzHk7tmLgC@Rs~=77-Z`wUDOZB~XB;#y62HwciJa<(