Skip to content

Upgrade async-profiler to 4.5 - #3267

Open
hengyunabc wants to merge 2 commits into
masterfrom
codex/upgrade-async-profiler-4.5
Open

hengyunabc wants to merge 2 commits into
masterfrom
codex/upgrade-async-profiler-4.5

Conversation

@hengyunabc

@hengyunabc hengyunabc commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Upgrade the bundled async-profiler from 4.4 to 4.5, which includes the upstream essential-library parsing fix for profiler loading.

  • Replace the Linux x64, Linux arm64, and universal macOS native libraries with the official non-debug release artifacts.
  • Sync the Java API with upstream commit 11aaea310cb75843f0e7532365d8cedc8d0e14c8, including dumpOtlp(Counter), while intentionally omitting the new Recording and Span classes.
  • Explain this integration choice in core/src/main/java/one/profiler/package-info.java and update the Chinese/English profiler version references.

In 4.5, loading the native library can bind Recording and retain its defining ClassLoader through a JNI global reference, even if the Span API is never called. Stopping profiling does not release that reference; see async-profiler #1811. Arthas does not use the Java Span API, and the native library skips this optional binding when Recording is absent. Ordinary sampling, HTML flame graphs, and JFR output remain available. Span is omitted together with its Recording dependency. Reconsider these classes when upstream addresses the reference lifecycle and Arthas needs the Span API.

Validation:

  • Java 8: ./mvnw -B -ntp -pl core -am test -DargLine=-XX:+StartAttachListener — 331 tests passed, with no failures, errors, or skips. In the fresh worktree, first generated the vmtool dependency JAR with ./mvnw -B -ntp -pl arthas-vmtool -am package -DskipTests.
  • Java 8: ./mvnw -B -ntp -pl core jar:jar — passed; verified that the core JAR contains the remaining Java 8 profiler API classes and no Recording or Span classes.
  • macOS arm64, JDK 8 and 21: loaded that core JAR through the real ArthasClassloader; version/status, CPU/HTML, CPU JFR, and wall/allocation/monitor-lock JFR checks passed. JDK 21 jfrsync also passed. Parsed all generated JFR files and checked the expected event counts.
  • Isolated ClassLoader probes on JDK 8 and 21: the loader was collected after both version-only and start/stop runs.
  • git diff --check passed.

Linux native runtime and cold-cache/many-library scenarios were not tested locally. Full distribution packaging was not rerun for the class-omission follow-up.

Closes #3266.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-08T03:52:52.971717Z 260d990 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 260d990e6d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

/**
* Tracks async-profiler's recording state and provides timestamps aligned with the profiler clock.
*/
public class Recording {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add automated coverage for the new profiler APIs

The commit introduces the JNI-backed Recording state machine and several distinct Span filtering paths, but a repo-wide search of core/src/test finds no tests referencing either type. These branches include normal-thread, virtual-thread, timestamp-boundary, unavailable-library, and recording-state behavior, so relying only on manual smoke tests leaves regressions in newly public APIs undetected; add unit, smoke, and functional coverage as required by the repository.

AGENTS.md reference: AGENTS.md:L258-L258

Useful? React with 👍 / 👎.

Comment on lines +14 to +16
/**
* Tracks async-profiler's recording state and provides timestamps aligned with the profiler clock.
*/

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Translate the newly added code comments to Chinese

Both new profiler classes introduce English Javadocs and inline implementation comments, while the repository explicitly requires all code comments to be written in Chinese; translate the explanatory comments while retaining required license identifiers unchanged.

AGENTS.md reference: AGENTS.md:L243-L243

Useful? React with 👍 / 👎.

Comment on lines +92 to +93
if (isVirtualThread() || hasProfileSamples(startTime)) {
Recording.emitSpan(startTime, Recording.timestamp(), tag);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve conditional filtering for virtual-thread spans

On JDK 21+ virtual threads, isVirtualThread() makes this condition succeed without consulting hasProfileSamples, so endIfProfiled records every span even when no profiling sample occurred; the identical shortcut in emitIfProfiled has the same behavior. High-frequency virtual-thread users choosing the conditional APIs to avoid native calls and JFR growth therefore receive unconditional spans instead, potentially causing substantial recording overhead and misleading results.

Useful? React with 👍 / 👎.

Comment on lines +119 to +120
if (isVirtualThread() || hasProfileSamples(startTime)) {
Recording.emitSpan(startTime, endTime, tag);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the end-time bound when filtering explicit spans

When emitIfProfiled is invoked after its supplied endTime, a newer profiling sample can make hasProfileSamples(startTime) true even though that sample lies outside the documented [startTime, endTime] interval. This produces a false-positive profiler.Span event for delayed or historical intervals; compare the last-sample timestamp against both bounds before emitting.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The dumpOtlp() API removal introduces avoidable binary incompatibility for existing consumers (especially via JMX), and should retain a delegating deprecated overload to prevent runtime NoSuchMethodErrors.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR upgrades the bundled async-profiler integration from v4.4 to v4.5 to pick up upstream fixes (notably the essential-library parsing change to avoid long pauses during profiler loading) and syncs Arthas’ embedded Java API and documentation references with the upstream v4.5 state.

Changes:

  • Updated profiler documentation (EN/ZH) and in-code references to async-profiler v4.5.
  • Synced embedded async-profiler Java API changes, including dumpOtlp(Counter) and adding Recording/Span helpers.
  • Updated source attribution to the upstream v4.5 tag/commit.
File summaries
File Description
site/docs/en/doc/profiler.md Updates upstream reference links and displayed profiler version to v4.5.
site/docs/doc/profiler.md Updates upstream reference links/version and minor wording/formatting adjustments.
core/src/main/java/one/profiler/Span.java Adds span-recording helper API for async-profiler JFR recordings.
core/src/main/java/one/profiler/Recording.java Adds recording state/timestamp utilities aligned with profiler clock.
core/src/main/java/one/profiler/package-info.java Updates upstream attribution to v4.5 tag/commit.
core/src/main/java/one/profiler/AsyncProfilerMXBean.java Updates MXBean API signature for OTLP dumping.
core/src/main/java/one/profiler/AsyncProfiler.java Updates collapsed/OTLP command generation for new counter handling.
core/src/main/java/com/taobao/arthas/core/command/monitor200/ProfilerCommand.java Updates upstream reference link to v4.5.
Review details

Suppressed comments (1)

core/src/main/java/one/profiler/AsyncProfiler.java:252

  • AsyncProfiler.dumpOtlp() was removed, which is a binary-incompatible change for any code compiled against the previous API. Consider keeping a deprecated no-arg overload that delegates to dumpOtlp(Counter.SAMPLES), and also fail fast if the new counter parameter is null to avoid silently defaulting to "total".
    @Override
    public byte[] dumpOtlp(Counter counter) {
        try {
            return execute1("otlp," + (counter == Counter.SAMPLES ? "samples" : "total"));
        } catch (IOException e) {
  • Files reviewed: 8/11 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 31 to +34
String dumpCollapsed(Counter counter);
String dumpTraces(int maxTraces);
String dumpFlat(int maxMethods);
byte[] dumpOtlp();
byte[] dumpOtlp(Counter counter);
Comment on lines 201 to 205
@Override
public String dumpCollapsed(Counter counter) {
try {
return execute0("collapsed," + counter.name().toLowerCase());
return execute0("collapsed," + (counter == Counter.SAMPLES ? "samples" : "total"));
} catch (IOException e) {
@hengyunabc
hengyunabc force-pushed the codex/upgrade-async-profiler-4.5 branch from 1da7d82 to 260d990 Compare September 8, 2026 07:16

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upgrade the bundled async-profiler to v4.5 to fix long JVM pauses when loading/attaching the profiler (async-profiler issue 1406)

2 participants