<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Umang Sharma</title>
    <description>The latest articles on DEV Community by Umang Sharma (@umang_sharma28).</description>
    <link>https://dev.to/umang_sharma28</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3880443%2F323c5688-42ab-4627-8940-a835426b88d3.png</url>
      <title>DEV Community: Umang Sharma</title>
      <link>https://dev.to/umang_sharma28</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/umang_sharma28"/>
    <language>en</language>
    <item>
      <title>Stop Scrolling Perfetto Timelines: Query Your Traces with SQL and Let AI Find the Bugs</title>
      <dc:creator>Umang Sharma</dc:creator>
      <pubDate>Wed, 15 Apr 2026 16:12:38 +0000</pubDate>
      <link>https://dev.to/umang_sharma28/stop-scrolling-perfetto-timelines-query-your-traces-with-sql-and-let-ai-find-the-bugs-65a</link>
      <guid>https://dev.to/umang_sharma28/stop-scrolling-perfetto-timelines-query-your-traces-with-sql-and-let-ai-find-the-bugs-65a</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://umang-sharma28.medium.com/stop-scrolling-perfetto-timelines-query-your-traces-with-sql-and-let-ai-find-the-bugs-09a042403ba4" rel="noopener noreferrer"&gt;Medium&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Stop Scrolling Perfetto Timelines — Query Your Traces with SQL and Let AI Find the Bugs
&lt;/h1&gt;

&lt;p&gt;Perfetto traces are secretly a SQL database. You can query them, pipe the results to Claude, and get a ranked list of exactly what's slowing your app down — in minutes, not hours.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You captured a Perfetto trace. Your app's cold start takes forever. Now you're doing this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔍 Zoom in… scroll right… "what was that slice?"… zoom out… scroll left… "wait, where was I?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The timeline UI is great for exploration. But you can't aggregate ("What's my P90 frame time?"), you can't compare across traces ("Is v8.1 slower than v8.0?"), and you can't automate anything.&lt;/p&gt;

&lt;p&gt;Here's what most Android devs don't realize: &lt;strong&gt;Perfetto stores every trace in a SQLite-based query engine.&lt;/strong&gt; You can run SQL against it. And once you have SQL output, you can feed it to AI for instant analysis.&lt;/p&gt;

&lt;p&gt;This post walks through the entire workflow — demo app, real trace, real AI analysis.&lt;/p&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/c1b93001-3b34-4020-ae85-f20ee04d492d" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/c1b93001-3b34-4020-ae85-f20ee04d492d&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Demo App: 5 Intentional Bottlenecks
&lt;/h2&gt;

&lt;p&gt;I built a deliberately broken app called &lt;strong&gt;SlowStart&lt;/strong&gt; with 5 common startup bottlenecks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// ❌ 1: Heavy JSON on main thread&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SlowStart::HeavyJsonParsing"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;buildLargeJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// ❌ 2: Sync SharedPreferences&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SlowStart::SharedPrefBulkRead"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;prefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;edit&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;putString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key_$it"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"val_$it"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nf"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;  &lt;span class="c1"&gt;// blocking! apply() is async&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// ❌ 3: Binder IPC&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SlowStart::PackageManagerQuery"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;packageManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstalledPackages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activity_main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// ❌ 4: Unnecessary layout inflation&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SlowStart::ExtraViewInflation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;layoutInflater&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;heavy_layout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// ❌ 5: Expensive computation&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SlowStart::ExpensiveInit"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;50_000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;shuffled&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toMutableList&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nc"&gt;Trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endSection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each bottleneck is wrapped in &lt;code&gt;Trace.beginSection()&lt;/code&gt; so it shows up as a &lt;strong&gt;named slice&lt;/strong&gt; in Perfetto. Custom trace markers are your best friend — use them in your own app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Capture the Trace
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adb shell am force-stop com.example.slowstart

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'buffers: { size_kb: 65536 } duration_ms: 15000
  data_sources: { config { name: "linux.ftrace" ftrace_config {
  ftrace_events: "sched/sched_switch"
  ftrace_events: "power/cpu_frequency"
  atrace_categories: "am" atrace_categories: "wm"
  atrace_categories: "view" atrace_categories: "dalvik"
  atrace_apps: "com.example.slowstart" }}}
  data_sources: { config { name: "linux.process_stats" }}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  | adb shell perfetto &lt;span class="nt"&gt;-c&lt;/span&gt; - &lt;span class="nt"&gt;--txt&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /data/misc/perfetto-traces/trace &lt;span class="nt"&gt;-d&lt;/span&gt;

&lt;span class="nb"&gt;sleep &lt;/span&gt;3
adb shell am start &lt;span class="nt"&gt;-n&lt;/span&gt; com.example.slowstart/.MainActivity &lt;span class="nt"&gt;-W&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;15
adb pull /data/misc/perfetto-traces/trace slowstart.perfetto-trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; 15 seconds with targeted &lt;code&gt;atrace_categories&lt;/code&gt; beats 60 seconds with everything enabled. Less noise = better analysis.&lt;/p&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/25e6875f-9f24-4ced-8430-36c776a87a24" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/25e6875f-9f24-4ced-8430-36c776a87a24&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our trace: &lt;strong&gt;520ms cold start&lt;/strong&gt;, 72 processes, 4.3MB. &lt;code&gt;LaunchState: COLD&lt;/code&gt; confirms a clean cold start.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Perfetto SQL Crash Course
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-LO&lt;/span&gt; https://get.perfetto.dev/trace_processor
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x ./trace_processor
./trace_processor slowstart.perfetto-trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use the &lt;strong&gt;Query (SQL)&lt;/strong&gt; tab at &lt;a href="https://ui.perfetto.dev" rel="noopener noreferrer"&gt;ui.perfetto.dev&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Data Model
&lt;/h3&gt;

&lt;p&gt;Four tables matter. Memorize this join chain: &lt;strong&gt;slice → thread_track → thread → process&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  slice               thread_track          thread              process
 ┌────────────┐      ┌─────────────┐      ┌──────────────┐    ┌──────────┐
 │ name       │      │ id       ◄──┼──────│              │    │          │
 │ ts         │      │ utid     ───┼──────► utid         │    │ upid  ◄──┤
 │ dur        │      └─────────────┘      │ name         │    │ pid      │
 │ track_id ──┼──►                        │ is_main_thd  │    │ name     │
 └────────────┘                           │ upid      ───┼───►└──────────┘
                                          └──────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key rule:&lt;/strong&gt; Always use &lt;code&gt;utid&lt;/code&gt;/&lt;code&gt;upid&lt;/code&gt;, never raw &lt;code&gt;tid&lt;/code&gt;/&lt;code&gt;pid&lt;/code&gt; — the OS reuses those.&lt;/p&gt;

&lt;h3&gt;
  
  
  The 7 Queries
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1 — What's in this trace?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;upid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;IS&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2 — Startup lifecycle&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dur_ms&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bindApplication'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'activityStart'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="s1"&gt;'activityResume'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'Choreographer#doFrame'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3 — Find YOUR bottlenecks&lt;/strong&gt; (the money query)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dur_ms&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'SlowStart::%'&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/a940c986-c012-463b-92e9-650d9f655af0" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/a940c986-c012-463b-92e9-650d9f655af0&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;234ms out of 520ms. That's 45% of startup — self-inflicted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Surprise: &lt;code&gt;ExpensiveInit&lt;/code&gt; dominated at &lt;strong&gt;181ms&lt;/strong&gt;, not JSON parsing. This is why you measure instead of guess.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 — Slowest main thread slices&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dur_ms&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;thread_track&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;track_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="n"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;utid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_main_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Anything &amp;gt; 16ms blocks a frame. This query shows everything blocking your main thread.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5 — Binder transactions&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dur_ms&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'binder%'&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6 — Standard Library&lt;/strong&gt; (the cheat code)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;INCLUDE&lt;/span&gt; &lt;span class="n"&gt;PERFETTO&lt;/span&gt; &lt;span class="n"&gt;MODULE&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startups&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;android_startups&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;INCLUDE&lt;/span&gt; &lt;span class="n"&gt;PERFETTO&lt;/span&gt; &lt;span class="n"&gt;MODULE&lt;/span&gt; &lt;span class="n"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;monitor_contention&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;blocking_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blocked_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;ms&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;android_monitor_contention&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The stdlib handles Android version-specific differences. Always prefer it over raw SQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7 — Frame jank&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="n"&gt;e6&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;dur_ms&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;32000000&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'🔴 SEVERE'&lt;/span&gt;
       &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;16000000&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="s1"&gt;'🟡 JANK'&lt;/span&gt;
       &lt;span class="k"&gt;ELSE&lt;/span&gt; &lt;span class="s1"&gt;'🟢 OK'&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;verdict&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="s1"&gt;'Choreographer#doFrame%'&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;dur&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt; &lt;span class="k"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's zoom into the timeline to see what's happening during startup:&lt;/p&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/14a1fddd-d953-41a3-908f-3cff6eb63d83" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/14a1fddd-d953-41a3-908f-3cff6eb63d83&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the &lt;code&gt;SlowStart::&lt;/code&gt; slices clearly on the main thread. The &lt;code&gt;ExpensiveInit&lt;/code&gt; slice at the end is visually huge — matching our SQL finding of 181ms.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Feed It to AI
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option A: Extract + Upload (2 minutes)
&lt;/h3&gt;

&lt;p&gt;A Python script runs all 13 queries and saves a single JSON:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;perfetto pandas
python3 extract_for_ai.py slowstart.perfetto-trace &lt;span class="nt"&gt;-o&lt;/span&gt; report.json &lt;span class="nt"&gt;--csv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/c8487299-016d-4d6f-9a78-6a7584ad3c38" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/c8487299-016d-4d6f-9a78-6a7584ad3c38&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upload &lt;code&gt;report.json&lt;/code&gt; to Claude → &lt;em&gt;"Analyze my Android startup. Rank bottlenecks and give Kotlin fixes."&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: Agentic Loop (fully automated)
&lt;/h3&gt;

&lt;p&gt;Let Claude &lt;strong&gt;decide&lt;/strong&gt; what queries to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;perfetto.trace_processor&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TraceProcessor&lt;/span&gt;

&lt;span class="n"&gt;tp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TraceProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;slowstart.perfetto-trace&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Anthropic&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;SYSTEM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;re an Android perf expert with SQL access to a Perfetto trace.
Write queries inside &amp;lt;sql&amp;gt;...&amp;lt;/sql&amp;gt; tags. You&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ll get results back.
When done, give a final ranked analysis with fixes.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Analyze cold startup. Find bottlenecks, give fixes.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-sonnet-4-20250514&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;max_tokens&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SYSTEM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
    &lt;span class="n"&gt;queries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;sql&amp;gt;(.*?)&amp;lt;/sql&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DOTALL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;FINAL REPORT:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;break&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;as_pandas_dataframe&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Query: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Result:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;assistant&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude autonomously explores the trace, runs 6–10 SQL queries, and produces a complete analysis with code fixes.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AI Found (Real Data)
&lt;/h2&gt;

&lt;p&gt;I uploaded &lt;code&gt;trace_report.json&lt;/code&gt; to Claude. Here's what came back:&lt;/p&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/42b34848-537f-42a9-b83d-1801f307a2ad" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/42b34848-537f-42a9-b83d-1801f307a2ad&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/4458ec80-4b21-4a3b-a933-aa4f18f7f792" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/4458ec80-4b21-4a3b-a933-aa4f18f7f792&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What AI Caught That I'd Have Missed
&lt;/h3&gt;

&lt;p&gt;Beyond the 5 obvious bottlenecks, Claude cross-referenced the data and found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A 36ms background GC&lt;/strong&gt; between JSON parsing and the sort — &lt;code&gt;buildLargeJson()&lt;/code&gt; was churning allocations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30 GC events total&lt;/strong&gt; during startup — &lt;code&gt;shuffled()&lt;/code&gt; + &lt;code&gt;sort()&lt;/code&gt; on 50K items = massive object churn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EmojiCompat&lt;/strong&gt; taking 178ms on a background thread — not blocking, but burning CPU during the critical window&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 severe jank frames&lt;/strong&gt; at 46ms each right after &lt;code&gt;activityResume&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;20 monitor contention events&lt;/strong&gt; in &lt;code&gt;system_server&lt;/code&gt;, longest 7.4ms in &lt;code&gt;ActivityStarter.execute()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the power of structured data + AI. It connects dots across tables that you'd never spot scrolling a timeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI-Generated Fixes
&lt;/h3&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/bdd026f2-7cae-4636-affd-41b2d1b2e48f" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/bdd026f2-7cae-4636-affd-41b2d1b2e48f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image: &lt;a href="https://github.com/user-attachments/assets/9039a9b7-6e82-4dbc-b0ac-66c5ad0255aa" rel="noopener noreferrer"&gt;https://github.com/user-attachments/assets/9039a9b7-6e82-4dbc-b0ac-66c5ad0255aa&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Total recoverable: 234ms — 45% of the 520ms cold start.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How Does AI Actually Decode a Trace Report?
&lt;/h2&gt;

&lt;p&gt;When I asked Claude &lt;em&gt;"How did you decode this?"&lt;/em&gt;, the answer was revealing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Anchor on &lt;code&gt;android_startups&lt;/code&gt;&lt;/strong&gt; — get the cold-start budget (520ms). Everything else is framed against this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check timestamps&lt;/strong&gt; — only slices inside the startup window are on the critical path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rank by impact&lt;/strong&gt; — main-thread slices = blocking. Background GC overlapping main thread = stall multiplier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-reference tables&lt;/strong&gt; — the 36ms GC landed between &lt;code&gt;HeavyJsonParsing&lt;/code&gt; and &lt;code&gt;ExpensiveInit&lt;/code&gt;. &lt;code&gt;class_verification&lt;/code&gt; showed JIT-compiling &lt;code&gt;buildLargeJson(int)&lt;/code&gt;. Same method. Not a coincidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flag what's missing&lt;/strong&gt; — &lt;code&gt;android_binder&lt;/code&gt; errored in our extraction. The AI flagged this gap unprompted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's not magic. It's a performance engineer who reads SQL output instantly and connects dots across tables — work that takes a human 30 minutes of scrolling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus: Claude Code CLI — Skip Everything
&lt;/h2&gt;

&lt;p&gt;If you use &lt;a href="https://docs.anthropic.com/en/docs/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt;, skip the extraction entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="s2"&gt;"Analyze the cold startup bottlenecks in this trace and give me fixes"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--file&lt;/span&gt; slowstart.perfetto-trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. Claude Code installs &lt;code&gt;perfetto&lt;/code&gt;, queries the binary trace autonomously, and gives you ranked bottlenecks + fixes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why can't you upload .perfetto-trace directly to Claude chat?&lt;/strong&gt; It's binary protobuf — LLMs can't read it. Claude Code is the exception: it has a sandbox that installs &lt;code&gt;trace_processor&lt;/code&gt; and queries the binary directly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Cheatsheet
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SETUP:      curl -LO https://get.perfetto.dev/trace_processor
            ./trace_processor my.perfetto-trace

JOIN:       slice → thread_track → thread → process

TIMESTAMPS: dur / 1e6 = milliseconds | 16ms budget = 16,000,000 ns

STATES:     R = runnable | S = sleeping | D = I/O blocked

STDLIB:     INCLUDE PERFETTO MODULE android.startup.startups;
            INCLUDE PERFETTO MODULE android.binder;
            INCLUDE PERFETTO MODULE android.monitor_contention;

WORKFLOW:   Capture → SQL → JSON → AI → Fix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;Code: &lt;a href="https://github.com/umangsh28/perfetto-ai-blog" rel="noopener noreferrer"&gt;github.com/umangsh28/perfetto-ai-blog&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/umangsh28/perfetto-ai-blog
&lt;span class="nb"&gt;cd &lt;/span&gt;perfetto-ai-blog

&lt;span class="c"&gt;# Build &amp;amp; install demo app, then:&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'...'&lt;/span&gt; | adb shell perfetto &lt;span class="nt"&gt;-c&lt;/span&gt; - &lt;span class="nt"&gt;--txt&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; /data/misc/perfetto-traces/trace &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;3 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adb shell am start &lt;span class="nt"&gt;-n&lt;/span&gt; com.example.slowstart/.MainActivity &lt;span class="nt"&gt;-W&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;15 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adb pull /data/misc/perfetto-traces/trace slowstart.perfetto-trace

pip &lt;span class="nb"&gt;install &lt;/span&gt;perfetto pandas
python3 scripts/extract_for_ai.py slowstart.perfetto-trace
&lt;span class="c"&gt;# Upload report.json to Claude — done.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Follow me for more Android performance + AI content. All code is open source — drop a comment if you want help debugging your traces.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>performance</category>
      <category>ai</category>
      <category>claude</category>
    </item>
  </channel>
</rss>
