RFR: 8178287: AsyncGetCallTrace fails to traverse valid Java stacks

Ludovic Henry luhenry at openjdk.java.net
Wed Jun 9 17:25:52 UTC 2021


When the signal sent for AsyncGetCallTrace or JFR would land on a runtime stub (like arraycopy), a vtable stub, or the prolog of a compiled method,  it wouldn't be able to detect the sender (caller) frame for multiple reasons. This patch fixes these cases through adding CodeBlob-specific frame parser which are in the best position to know how a frame is setup.

The following examples have been profiled with honest-profiler which uses `AsyncGetCallTrace`.

# `Prof1`

public class Prof1 {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 1000000; i++) {
            sb.append("ab");
            sb.delete(0, 1);
        }
        System.out.println(sb.length());
    }
}


- Baseline:

Flat Profile (by method):
        (t 99.4,s 99.4) AGCT::Unknown Java[ERR=-5]
        (t  0.5,s  0.2) Prof1::main
        (t  0.2,s  0.2) java.lang.AbstractStringBuilder::append
        (t  0.1,s  0.1) AGCT::Unknown not Java[ERR=-3]
        (t  0.0,s  0.0) java.lang.AbstractStringBuilder::ensureCapacityInternal
        (t  0.0,s  0.0) java.lang.AbstractStringBuilder::shift
        (t  0.0,s  0.0) java.lang.String::getBytes
        (t  0.0,s  0.0) java.lang.AbstractStringBuilder::putStringAt
        (t  0.0,s  0.0) java.lang.StringBuilder::delete
        (t  0.2,s  0.0) java.lang.StringBuilder::append
        (t  0.0,s  0.0) java.lang.AbstractStringBuilder::delete
        (t  0.0,s  0.0) java.lang.AbstractStringBuilder::putStringAt

- With `StubRoutinesBlob::FrameParser`:

Flat Profile (by method):
        (t 98.7,s 98.7) java.lang.AbstractStringBuilder::ensureCapacityInternal
        (t  0.9,s  0.9) java.lang.AbstractStringBuilder::delete
        (t 99.8,s  0.2) Prof1::main
        (t  0.1,s  0.1) AGCT::Unknown not Java[ERR=-3]
        (t  0.0,s  0.0) AGCT::Unknown Java[ERR=-5]
        (t 98.8,s  0.0) java.lang.AbstractStringBuilder::append
        (t 98.8,s  0.0) java.lang.StringBuilder::append
        (t  0.9,s  0.0) java.lang.StringBuilder::delete


# `Prof2`

import java.util.function.Supplier;

public class Prof2 {

    public static void main(String[] args) {
        var rand = new java.util.Random(0);
        Supplier[] suppliers = {
                () -> 0,
                () -> 1,
                () -> 2,
                () -> 3,
        };

        long sum = 0;
        for (int i = 0; i >= 0; i++) {
            sum += (int)suppliers[i % suppliers.length].get();
        }
    }
}


- Baseline:

Flat Profile (by method):
        (t 60.7,s 60.7) AGCT::Unknown Java[ERR=-5]
        (t 39.2,s 35.2) Prof2::main
        (t  1.4,s  1.4) Prof2::lambda$main$3
        (t  1.0,s  1.0) Prof2::lambda$main$2
        (t  0.9,s  0.9) Prof2::lambda$main$1
        (t  0.7,s  0.7) Prof2::lambda$main$0
        (t  0.1,s  0.1) AGCT::Unknown not Java[ERR=-3]
        (t  0.0,s  0.0) java.lang.Thread::exit
        (t  0.9,s  0.0) Prof2$$Lambda$2.0x0000000800c00c28::get
        (t  1.0,s  0.0) Prof2$$Lambda$3.0x0000000800c01000::get
        (t  1.4,s  0.0) Prof2$$Lambda$4.0x0000000800c01220::get
        (t  0.7,s  0.0) Prof2$$Lambda$1.0x0000000800c00a08::get


- With `VtableBlob::FrameParser` and `nmethod::FrameParser`:

Flat Profile (by method):
        (t 74.1,s 70.3) Prof2::main
        (t  6.5,s  5.5) Prof2$$Lambda$29.0x0000000800081220::get
        (t  6.6,s  5.4) Prof2$$Lambda$28.0x0000000800081000::get
        (t  5.7,s  5.0) Prof2$$Lambda$26.0x0000000800080a08::get
        (t  5.9,s  5.0) Prof2$$Lambda$27.0x0000000800080c28::get
        (t  4.9,s  4.9) AGCT::Unknown Java[ERR=-5]
        (t  1.2,s  1.2) Prof2::lambda$main$2
        (t  0.9,s  0.9) Prof2::lambda$main$3
        (t  0.9,s  0.9) Prof2::lambda$main$1
        (t  0.7,s  0.7) Prof2::lambda$main$0
        (t  0.1,s  0.1) AGCT::Unknown not Java[ERR=-3]

-------------

Commit messages:
 - Disable checks in FrameParser when known to be safe
 - Allow AsyncGetCallTrace and JFR to unwind stack from vtable stub
 - Allow AsyncGetCallTrace and JFR to unwind stack from nmethod's prolog
 - JDK-8267985: Allow AsyncGetCallTrace and JFR to walk a stub frame
 - 8268178: Extract sender frame parsing to CodeBlock::FrameParser

Changes: https://git.openjdk.java.net/jdk/pull/4436/files
 Webrev: https://webrevs.openjdk.java.net/?repo=jdk&pr=4436&range=00
  Issue: https://bugs.openjdk.java.net/browse/JDK-8178287
  Stats: 1303 lines in 26 files changed: 1057 ins; 166 del; 80 mod
  Patch: https://git.openjdk.java.net/jdk/pull/4436.diff
  Fetch: git fetch https://git.openjdk.java.net/jdk pull/4436/head:pull/4436

PR: https://git.openjdk.java.net/jdk/pull/4436


More information about the serviceability-dev mailing list