Skip to content

Commit dc93a17

Browse files
committed
[GR-60806] Truffle profiler CLI calltree fix.
PullRequest: graal/19727
2 parents 419fa40 + acf1d47 commit dc93a17

File tree

2 files changed

+71
-11
lines changed
  • tools/src
    • com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl
    • com.oracle.truffle.tools.profiler.test/src/com/oracle/truffle/tools/profiler/test

2 files changed

+71
-11
lines changed

tools/src/com.oracle.truffle.tools.profiler.test/src/com/oracle/truffle/tools/profiler/test/ProfilerCLITest.java

+62-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -50,8 +50,10 @@
5050
public class ProfilerCLITest {
5151

5252
public static final String SAMPLING_HISTOGRAM_REGEX = "Sampling Histogram. Recorded [0-9]* samples with period [0-9]*ms. Missed [0-9]* samples.";
53+
public static final String SAMPLING_CALLTREE_REGEX = "Sampling Call Tree. Recorded [0-9]* samples with period [0-9]*ms. Missed [0-9]* samples.";
5354
public static final int EXEC_COUNT = 10;
54-
public static final String NAME_REGEX = " [a-z]* +";
55+
public static final int LOOP_COUNT = 10;
56+
public static final String NAME_REGEX = " +[a-z]* +";
5557
public static final String SEPARATOR_REGEX = "\\|";
5658
public static final String TIME_REGEX = " *[0-9]*ms +[0-9]*\\.[0-9]\\% ";
5759
public static final String PERCENT_REGEX = " *[0-9]*\\.[0-9]\\% ";
@@ -66,6 +68,58 @@ protected Source makeSource(String s) {
6668
return Source.newBuilder(InstrumentationTestLanguage.ID, s, "test").buildLiteral();
6769
}
6870

71+
@Test
72+
public void testCallTreeWithTiers() {
73+
Assume.assumeFalse(checkRuntime());
74+
HashMap<String, String> options = new HashMap<>();
75+
options.put("cpusampler", "true");
76+
options.put("cpusampler.Output", "calltree");
77+
options.put("cpusampler.ShowTiers", "true");
78+
options.put("engine.FirstTierCompilationThreshold", Integer.toString(5 * LOOP_COUNT));
79+
options.put("engine.LastTierCompilationThreshold", Integer.toString(7 * LOOP_COUNT));
80+
options.put("engine.BackgroundCompilation", "false");
81+
String[] output = runSampler(options);
82+
// @formatter:off
83+
// OUTPUT IS:
84+
// ----------------------------------------------------------------------------------------------------------------------------------------------------
85+
// Sampling Call Tree. Recorded 120 samples with period 10ms. Missed 6 samples.
86+
Assert.assertTrue(output[1].matches(SAMPLING_CALLTREE_REGEX));
87+
// Self Time: Time spent on the top of the stack.
88+
Assert.assertEquals(SELF_TIME, output[2]);
89+
// Total Time: Time spent somewhere on the stack.
90+
Assert.assertEquals(TOTAL_TIME, output[3]);
91+
// T0: Percent of time spent in interpreter.
92+
Assert.assertEquals(INTERPRETER, output[4]);
93+
// T1: Percent of time spent in code compiled by tier 1 compiler.
94+
Assert.assertEquals(T1, output[5]);
95+
// T2: Percent of time spent in code compiled by tier 2 compiler.
96+
Assert.assertEquals(T2, output[6]);
97+
// ----------------------------------------------------------------------------------------------------------------------------------------------------
98+
// Name || Total Time | T0 | T1 | T2 || Self Time | T0 | T1 | T2 || Location
99+
// ----------------------------------------------------------------------------------------------------------------------------------------------------
100+
Assert.assertEquals(" Name || Total Time | T0 | T1 | T2 || Self Time | T0 | T1 | T2 || Location ", output[8]);
101+
// || 1200ms 100.0% | 100.0% | 0.0% | 0.0% || 0ms 0.0% | 0.0% | 0.0% | 0.0% || test~1:0-161
102+
// baz || 1080ms 90.0% | 72.2% | 27.8% | 0.0% || 0ms 0.0% | 0.0% | 0.0% | 0.0% || test~1:98-139
103+
String lineRegex = NAME_REGEX +
104+
SEPARATOR_REGEX + SEPARATOR_REGEX +
105+
TIME_REGEX + SEPARATOR_REGEX + PERCENT_REGEX + SEPARATOR_REGEX + PERCENT_REGEX + SEPARATOR_REGEX + PERCENT_REGEX +
106+
SEPARATOR_REGEX + SEPARATOR_REGEX +
107+
TIME_REGEX + SEPARATOR_REGEX + PERCENT_REGEX + SEPARATOR_REGEX + PERCENT_REGEX + SEPARATOR_REGEX + PERCENT_REGEX +
108+
SEPARATOR_REGEX + SEPARATOR_REGEX +
109+
LOCATION_REGEX;
110+
Assert.assertTrue(output[10].matches(lineRegex));
111+
Assert.assertTrue(output[11].matches(lineRegex));
112+
// bar || 1080ms 90.0% | 13.0% | 50.9% | 36.1% || 0ms 0.0% | 0.0% | 0.0% | 0.0% || test~1:43-84
113+
Assert.assertTrue(output[12].matches(lineRegex));
114+
// foo || 1080ms 90.0% | 3.7% | 58.3% | 38.0% || 1080ms 90.0% | 3.7% | 58.3% | 38.0% || test~1:16-29
115+
Assert.assertTrue(output[13].matches(lineRegex));
116+
// bar || 120ms 10.0% | 8.3% | 58.3% | 33.3% || 0ms 0.0% | 0.0% | 0.0% | 0.0% || test~1:43-84
117+
Assert.assertTrue(output[14].matches(lineRegex));
118+
// foo || 120ms 10.0% | 0.0% | 58.3% | 41.7% || 120ms 10.0% | 0.0% | 58.3% | 41.7% || test~1:16-29
119+
Assert.assertTrue(output[15].matches(lineRegex));
120+
// @formatter:on
121+
}
122+
69123
@Test
70124
public void testDefaultSampleHistogram() {
71125
Assume.assumeTrue(checkRuntime());
@@ -196,8 +250,8 @@ private String[] runSamplerMultithreaded(Map<String, String> options) {
196250
try (Context context = Context.newBuilder().in(System.in).out(out).err(err).options(options).build()) {
197251
context.eval(makeSource("ROOT(" +
198252
"DEFINE(foo,ROOT(SLEEP(1)))," +
199-
"DEFINE(bar,ROOT(BLOCK(STATEMENT,LOOP(10, CALL(foo)))))," +
200-
"DEFINE(baz,ROOT(BLOCK(STATEMENT,LOOP(10, CALL(bar)))))," +
253+
"DEFINE(bar,ROOT(BLOCK(STATEMENT,LOOP(" + LOOP_COUNT + ", CALL(foo)))))," +
254+
"DEFINE(baz,ROOT(BLOCK(STATEMENT,LOOP(" + LOOP_COUNT + ", CALL(bar)))))," +
201255
")"));
202256
Runnable evalSource1 = new Runnable() {
203257
@Override
@@ -241,8 +295,8 @@ private String[] runSampler(Map<String, String> options) {
241295
try (Context context = Context.newBuilder().in(System.in).out(out).err(err).options(options).build()) {
242296
Source source = makeSource("ROOT(" +
243297
"DEFINE(foo,ROOT(SLEEP(1)))," +
244-
"DEFINE(bar,ROOT(BLOCK(STATEMENT,LOOP(10, CALL(foo)))))," +
245-
"DEFINE(baz,ROOT(BLOCK(STATEMENT,LOOP(10, CALL(bar)))))," +
298+
"DEFINE(bar,ROOT(BLOCK(STATEMENT,LOOP(" + LOOP_COUNT + ", CALL(foo)))))," +
299+
"DEFINE(baz,ROOT(BLOCK(STATEMENT,LOOP(" + LOOP_COUNT + ", CALL(bar)))))," +
246300
"CALL(baz),CALL(bar)" +
247301
")");
248302
for (int i = 0; i < EXEC_COUNT; i++) {
@@ -350,8 +404,8 @@ public void testSamplerJson() {
350404
Context context = Context.newBuilder().in(System.in).out(out).err(err).option("cpusampler", "true").option("cpusampler.Output", "json").build();
351405
Source defaultSourceForSampling = makeSource("ROOT(" +
352406
"DEFINE(foo,ROOT(SLEEP(1)))," +
353-
"DEFINE(bar,ROOT(BLOCK(STATEMENT,LOOP(10, CALL(foo)))))," +
354-
"DEFINE(baz,ROOT(BLOCK(STATEMENT,LOOP(10, CALL(bar)))))," +
407+
"DEFINE(bar,ROOT(BLOCK(STATEMENT,LOOP(" + LOOP_COUNT + ", CALL(foo)))))," +
408+
"DEFINE(baz,ROOT(BLOCK(STATEMENT,LOOP(" + LOOP_COUNT + ", CALL(bar)))))," +
355409
"CALL(baz),CALL(bar)" +
356410
")");
357411
for (int i = 0; i < 10; i++) {

tools/src/com.oracle.truffle.tools.profiler/src/com/oracle/truffle/tools/profiler/impl/CPUSamplerCLI.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -718,7 +718,10 @@ private void calculateMaxValues(Map<Thread, Collection<ProfilerNode<CPUSampler.P
718718

719719
private void calculateMaxValuesRec(ProfilerNode<CPUSampler.Payload> node, int depth) {
720720
maxNameLength = Math.max(maxNameLength, node.getRootName().length() + OutputEntry.computeIndentSize(depth));
721-
tiers.add(node.getPayload().getNumberOfTiers() - 1);
721+
int numberOfTiers = node.getPayload().getNumberOfTiers();
722+
for (int i = 0; i < numberOfTiers; i++) {
723+
tiers.add(i);
724+
}
722725
for (ProfilerNode<CPUSampler.Payload> child : node.getChildren()) {
723726
calculateMaxValuesRec(child, depth + 1);
724727
}
@@ -759,7 +762,10 @@ private void mergeEntry(List<CallTreeOutputEntry> callTreeEntries, ProfilerNode<
759762

760763
private CallTreeOutputEntry makeEntry(ProfilerNode<CPUSampler.Payload> node, int depth) {
761764
maxNameLength = Math.max(maxNameLength, node.getRootName().length() + OutputEntry.computeIndentSize(depth));
762-
tiers.add(node.getPayload().getNumberOfTiers() - 1);
765+
int numberOfTiers = node.getPayload().getNumberOfTiers();
766+
for (int i = 0; i < numberOfTiers; i++) {
767+
tiers.add(i);
768+
}
763769
CallTreeOutputEntry entry = new CallTreeOutputEntry(node);
764770
for (ProfilerNode<CPUSampler.Payload> child : node.getChildren()) {
765771
entry.children.add(makeEntry(child, depth + 1));

0 commit comments

Comments
 (0)