CN

loading
What I Am Building

This page brings together the projects I maintain, am developing, have made public, or have not yet released. They include Android performance analysis, Perfetto tools, AI automation, iOS apps, Android demos, test suites, blog series, communities, and my accounts on other platforms.

If this is your first visit, start with what you need: the Perfetto and Systrace series for Android performance analysis; SmartPerfetto, TraceFix, and Android App Memory Analysis for tools; OpenClaw and AI Field Notes for AI-assisted knowledge management and everyday work; or the links at the end to contact me.

The projects fall into four areas. Performance analysis includes tools such as SmartPerfetto, Android App Memory Analysis, TraceFix, and Perfetto Auto-Pin, alongside the High Performance Friends Circle test platform. AI and automation includes OpenClaw, AI Field Notes, Gracker Skills, and Open Design. Personal apps include the iOS projects 100Years and iBattery, and the Android project Juju. The main content projects are this blog and Android Weekly. The entries below describe their status, including ongoing maintenance, current development, and paused work.

Android Perfetto Series 18: Response Latency in Practice, from Input Events to First-Frame Feedback

This article addresses a topic easily overshadowed by startup speed and smoothness: first-frame interaction response. It asks how long the screen takes to provide the first frame of feedback after a user action. Complete page loading and stability later in an animation require other metrics.

After tapping a button, how long until its pressed state appears? After tapping a WeChat conversation, how long until the first frame of the conversation page starts moving? After swiping a list, how long until its content follows the finger? These questions relate to slow startup and dropped frames, but need their own measurement definitions.

We use Perfetto to break down this interval: from InputReader read_time, through the App receiving the event, to an associated frame’s present. This gives a candidate internal delay, estimated_input_to_present_ms. Only after confirming the target layer and that the business state visibly changed on that frame should a report call it input_to_present_ms. Neither value covers touch IC latency, delays before driver reporting, display scanning, or panel response. By the end, you should be able to define a start, endpoint, capture configuration, SQL metrics, and supplementary App markers for a tap or scroll scenario.

The article examines response latency through four independent measurements—read/dispatch, handling, ACK→first frame, and scroll responsiveness. Each comes with capture configuration, the first tracks to inspect in the UI, and SQL. It then covers five common attribution paths and the respective boundaries of high-speed cameras and Perfetto.

Android Perfetto Series 17: Domain Automation, Issue Checklists, and Platform Infrastructure

For slow camera opens, audio underruns, a stalled WebView first screen, or dropped frames in Flutter and games, the evidence is scattered across the app, system_server, cameraserver/audioserver, HAL, SurfaceFlinger, and scheduling tracks. Simply inspecting a few more tracks in the UI can easily leave critical timestamps unnoticed.

Using Camera and Audio as examples, this article describes a reusable method for domain-specific analysis: capture the right data, identify the objects, calculate stages and blocking, and preserve timestamps in the report so that reviewers can return to the UI. Camera and Audio are examples; the core is a domain schema and collaboration with platform tracing. By the end, you should at least be able to break a slow camera open into reviewable stages and an audio underrun into cycle anomalies, rather than delivering only a table of the longest slices.

Android Perfetto Series 16: GPU, Power Counters, and Hardware Bottleneck Analysis

When FrameTimeline marks a late frame but the main thread and RenderThread show no obvious long tasks, GPU work and fences are useful next checks. GPU frequency, battery current, and power rails describe hardware state in that window; they do not establish on their own why an app frame presented late.

Parts 07 and 08 covered the rendering path from the App to SurfaceFlinger; Parts 06 and 09 covered refresh rates and CPU scheduling/frequency. This article adds an often-skipped step without repeating those topics: when a problem appears to have reached the hardware resource layer, how should GPU, devfreq, battery counters, and power rails enter the analysis of the same trace interval?

These counters are difficult because not every device provides them, and different GPU vendors use different counter names. A conclusion cannot simply say “a high GPU value means a GPU bottleneck.” FrameTimeline, RenderThread, SurfaceFlinger, the GPU timeline, frequency, and power data must be examined over the same interval.

Android Perfetto Series 15: Boot Traces, Long-Running Field Traces, and Capturing Intermittent Problems

Many performance problems cannot be reproduced with a single tap. Slow boot, intermittent jank, problems after turning the screen on or off, audio interruptions after several hours, periodic stutters in an automotive system, and performance degradation as temperature rises are all poor fits for a manually recorded 10-second trace.

This article covers long-running field traces: defining the observation window in advance, using triggers to preserve the incident, ensuring the file finishes writing safely, and determining whether the collected data is trustworthy. Boot tracing is covered below as a special observation window. Part 02 already covered basic interactive capture methods—the command line, official scripts, Developer options, and the web interface. Here, we focus on what changes in the field and during long-running recording.

Android Perfetto Series 14: heapprofd and Memory Profiling

The hardest part of a memory problem is that a rising number does not immediately tell you what is growing. dumpsys meminfo provides RSS/PSS, and a Java heap dump reveals object retention relationships. But for JNI/C++, CPU-side Skia/Bitmap allocations, and native wrappers in media players, you often also need to know which call stack issued the malloc/new request.

This article covers heapprofd. Its value is bringing native allocations, frees, and call stacks into a Perfetto trace, where you can inspect them alongside application events, thread scheduling, and Binder on the same timeline.

Use heapprofd after confirming the trend. I would split the growth between native heap, graphics buffers, and other mappings with meminfo or smaps before opening a flamegraph. Otherwise, it is easy to chase a malloc stack when the growth came from GraphicBuffer. This article does not address Java object references or graphics backing memory.

We will cover when to use heapprofd, how to capture a profile, how to read it in the UI and SQL, how to interpret sampling intervals and symbolization, and finally what to check before publishing a report.

Android Perfetto Series 13: Perfetto SDK, Track Event, and App Field Tracing

A system trace can tell you when a thread ran, which CPU core it ran on, and which FrameTimeline frame missed its deadline. With Binder/ftrace/sched evidence enabled, it can also reconstruct Binder calls and clues about waiting. But it does not know which frame ID a player is decoding, which scene a game engine is loading, or how long an application task has spent in a queue.

Track Events can record decoding, texture uploads, queue depth, and cross-thread task IDs. Put them in the same window as the system tracks to find a candidate application phase, then use RenderThread, GPU, and FrameTimeline evidence to check whether it affected a visible frame.

The article follows the practical integration order: decide whether instrumentation is needed and at which layer, define an application-phase dictionary and backend, then build the minimal integration, category controls, combined system capture, and cross-thread flows. Finally, control write volume and define the app-side field tracing protocol.

Android Perfetto Series 12: Trace Dataflow and Data Loss Troubleshooting

A trace can open in the UI and return SQL rows even after data was lost during capture. If thread-state intervals are missing, process names do not line up, or Track Events have IDs but no names, first find which stage lost the data, then decide which parts of the analysis can continue.

SQL can only analyze evidence that still exists in the trace. I would not discard an entire trace just because it reports ftrace loss; first identify whether scheduling, app markers, or frame data were affected.

Part 02 covered capture, and Part 11 covered SQL queries. This article focuses on one question: where did the trace lose data, which conclusions does that affect, and how should the next capture configuration change?

We will follow the data from the kernel to the trace file, locating loss at each stage: ftrace, producer shared memory, the central buffer, incremental state, and flush. Each stage loses data differently and needs a different remedy. At the end, there is a template for explaining how much of a trace remains trustworthy in an analysis report.

Android Perfetto Series 11: PerfettoSQL, Trace Processor, and Regression Detection

Selecting a window in Perfetto UI, inspecting the main thread, RenderThread, and CPU states, then taking screenshots works well for one investigation. When I open another trace or switch devices, I want to know whether I can calculate comparable, checkable numbers for the same kind of problem.

Part 11 covers PerfettoSQL and Trace Processor. The aim is straightforward: turn judgments made in the UI into queries that others can check, then use Python to run them across multiple traces. You do not need to become a SQL expert first. Treat a trace as a set of timestamped tables, and translate your visual assessment into a query you can run repeatedly.

The article follows one path: understand Trace Processor, express an assessment as a query over a defined time window, run it from the command line, process multiple traces with Python, and finally turn the results into stable metrics and Trace Summary output. Each step includes SQL you can reuse.