Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2102,7 +2102,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {

void TemplateInterpreterGenerator::count_bytecode() {
__ mov(r10, (address) &BytecodeCounter::_counter_value);
__ atomic_addw(noreg, 1, r10);
__ atomic_add(noreg, 1, r10);
}

void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
Expand Down Expand Up @@ -2150,7 +2150,7 @@ void TemplateInterpreterGenerator::stop_interpreter_at() {
__ mov(rscratch1, (address) &BytecodeCounter::_counter_value);
__ ldr(rscratch1, Address(rscratch1));
__ mov(rscratch2, StopInterpreterAt);
__ cmpw(rscratch1, rscratch2);
__ cmp(rscratch1, rscratch2);
__ br(Assembler::NE, L);
__ brk(0);
__ bind(L);
Expand Down
12 changes: 6 additions & 6 deletions src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2316,11 +2316,11 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
// Support short-cut for TraceBytecodesAt.
// Don't call into the VM if we don't want to trace to speed up things.
Label Lskip_vm_call;
if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
if (TraceBytecodesAt > 0) {
int offs1 = __ load_const_optimized(R11_scratch1, (address) &TraceBytecodesAt, R0, true);
int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
__ ld(R11_scratch1, offs1, R11_scratch1);
__ lwa(R12_scratch2, offs2, R12_scratch2);
__ ld(R12_scratch2, offs2, R12_scratch2);
__ cmpd(CR0, R12_scratch2, R11_scratch1);
__ blt(CR0, Lskip_vm_call);
}
Expand All @@ -2334,7 +2334,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
__ mtlr(R31);
__ pop(state);

if (TraceBytecodesAt > 0 && TraceBytecodesAt < max_intx) {
if (TraceBytecodesAt > 0) {
__ bind(Lskip_vm_call);
}
__ blr();
Expand All @@ -2344,9 +2344,9 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {

void TemplateInterpreterGenerator::count_bytecode() {
int offs = __ load_const_optimized(R11_scratch1, (address) &BytecodeCounter::_counter_value, R12_scratch2, true);
__ lwz(R12_scratch2, offs, R11_scratch1);
__ ld(R12_scratch2, offs, R11_scratch1);
__ addi(R12_scratch2, R12_scratch2, 1);
__ stw(R12_scratch2, offs, R11_scratch1);
__ std(R12_scratch2, offs, R11_scratch1);
}

void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
Expand Down Expand Up @@ -2395,7 +2395,7 @@ void TemplateInterpreterGenerator::stop_interpreter_at() {
int offs1 = __ load_const_optimized(R11_scratch1, (address) &StopInterpreterAt, R0, true);
int offs2 = __ load_const_optimized(R12_scratch2, (address) &BytecodeCounter::_counter_value, R0, true);
__ ld(R11_scratch1, offs1, R11_scratch1);
__ lwa(R12_scratch2, offs2, R12_scratch2);
__ ld(R12_scratch2, offs2, R12_scratch2);
__ cmpd(CR0, R12_scratch2, R11_scratch1);
__ bne(CR0, L);
__ illtrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1846,7 +1846,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {

void TemplateInterpreterGenerator::count_bytecode() {
__ mv(x7, (address) &BytecodeCounter::_counter_value);
__ atomic_addw(noreg, 1, x7);
__ atomic_add(noreg, 1, x7);
}

void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2329,7 +2329,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
// Skip runtime call, if the trace threshold is not yet reached.
__ load_absolute_address(Z_tmp_1, (address)&BytecodeCounter::_counter_value);
__ load_absolute_address(Z_tmp_2, (address)&TraceBytecodesAt);
__ load_sized_value(Z_tmp_1, Address(Z_tmp_1), 4, false /*signed*/);
__ load_sized_value(Z_tmp_1, Address(Z_tmp_1), 8, false /*signed*/);
__ load_sized_value(Z_tmp_2, Address(Z_tmp_2), 8, false /*signed*/);
__ compareU64_and_branch(Z_tmp_1, Z_tmp_2, Assembler::bcondLow, counter_below_trace_threshold);
}
Expand Down Expand Up @@ -2359,7 +2359,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
// Make feasible for old CPUs.
void TemplateInterpreterGenerator::count_bytecode() {
__ load_absolute_address(Z_R1_scratch, (address) &BytecodeCounter::_counter_value);
__ add2mem_32(Address(Z_R1_scratch), 1, Z_R0_scratch);
__ add2mem_64(Address(Z_R1_scratch), 1, Z_R0_scratch);
}

void TemplateInterpreterGenerator::histogram_bytecode(Template * t) {
Expand Down Expand Up @@ -2406,7 +2406,7 @@ void TemplateInterpreterGenerator::stop_interpreter_at() {

__ load_absolute_address(Z_tmp_1, (address)&BytecodeCounter::_counter_value);
__ load_absolute_address(Z_tmp_2, (address)&StopInterpreterAt);
__ load_sized_value(Z_tmp_1, Address(Z_tmp_1), 4, false /*signed*/);
__ load_sized_value(Z_tmp_1, Address(Z_tmp_1), 8, false /*signed*/);
__ load_sized_value(Z_tmp_2, Address(Z_tmp_2), 8, false /*signed*/);
__ compareU64_and_branch(Z_tmp_1, Z_tmp_2, Assembler::bcondLow, L);
assert(Z_tmp_1->is_nonvolatile(), "must be nonvolatile to preserve Z_tos");
Expand Down
9 changes: 9 additions & 0 deletions src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1874,7 +1874,11 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
}

void TemplateInterpreterGenerator::count_bytecode() {
#ifndef _LP64
__ incrementl(ExternalAddress((address) &BytecodeCounter::_counter_value), rscratch1);
#else
__ incrementq(ExternalAddress((address) &BytecodeCounter::_counter_value), rscratch1);
#endif
}

void TemplateInterpreterGenerator::histogram_bytecode(Template* t) {
Expand Down Expand Up @@ -1914,9 +1918,14 @@ void TemplateInterpreterGenerator::trace_bytecode(Template* t) {

void TemplateInterpreterGenerator::stop_interpreter_at() {
Label L;
#ifndef _LP64
__ cmp32(ExternalAddress((address) &BytecodeCounter::_counter_value),
StopInterpreterAt,
rscratch1);
#else
__ mov64(rscratch1, StopInterpreterAt);
__ cmp64(rscratch1, ExternalAddress((address) &BytecodeCounter::_counter_value), rscratch2);
#endif
__ jcc(Assembler::notEqual, L);
__ int3();
__ bind(L);
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/interpreter/bytecodeHistogram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@

// Implementation of BytecodeCounter

int BytecodeCounter::_counter_value = 0;
uintx BytecodeCounter::_counter_value = 0;
jlong BytecodeCounter::_reset_time = 0;


Expand All @@ -55,7 +55,7 @@ double BytecodeCounter::frequency() {

void BytecodeCounter::print() {
tty->print_cr(
"%d bytecodes executed in %.1fs (%.3fMHz)",
"%zu bytecodes executed in %.1fs (%.3fMHz)",
counter_value(),
elapsed_time(),
frequency() / 1000000.0
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/interpreter/bytecodeHistogram.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

class BytecodeCounter: AllStatic {
private:
NOT_PRODUCT(static int _counter_value;)
NOT_PRODUCT(static uintx _counter_value;)
NOT_PRODUCT(static jlong _reset_time;)

friend class TemplateInterpreterGenerator;
Expand All @@ -43,7 +43,7 @@ class BytecodeCounter: AllStatic {
static void reset() PRODUCT_RETURN;

// Counter info (all info since last reset)
static int counter_value() PRODUCT_RETURN0 NOT_PRODUCT({ return _counter_value; });
static uintx counter_value() PRODUCT_RETURN0 NOT_PRODUCT({ return _counter_value; });
static double elapsed_time() PRODUCT_RETURN0; // in seconds
static double frequency() PRODUCT_RETURN0; // bytecodes/seconds

Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/interpreter/bytecodeTracer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ class BytecodePrinter {
int bci = (int)(bcp - method->code_base());
st->print("[%zu] ", Thread::current()->osthread()->thread_id_for_printing());
if (Verbose) {
st->print("%8d %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s",
st->print("%8zu %4d " INTPTR_FORMAT " " INTPTR_FORMAT " %s",
Copy link
Member

Choose a reason for hiding this comment

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

Sounds like there are more than 8 digits now?

Copy link
Contributor

Choose a reason for hiding this comment

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

I thought about this, too, but I don't think it's a problem because the width is specified like this: "Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger." [https://cplusplus.com/reference/cstdio/printf/].
Do we want a larger fixed number of digits?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, it is not about the correctness. It is more about readability: if we expect more than 8 digits, then the "table" we are printing here would be a bit ragged. UINT64_MAX is about 20 digits. In practice we would probably never do this for longer than 1 hour, and with (ballparking) 100M/sec bytecodes, this gives us a practical upper limit of 12 digits or so? My math might be off a digit or two.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, nevermind. I don't think this is useful to adjust. The bytecode counter is global, so it is not a per-bytecode printout like I initially thought.

BytecodeCounter::counter_value(), bci, tos, tos2, Bytecodes::name(code));
} else {
st->print("%8d %4d %s",
st->print("%8zu %4d %s",
BytecodeCounter::counter_value(), bci, Bytecodes::name(code));
}
print_attributes(bci, st);
Expand Down
6 changes: 3 additions & 3 deletions src/hotspot/share/runtime/globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1566,13 +1566,13 @@ const int ObjectAlignmentInBytes = 8;
"Minimal number of lookupswitch entries for rewriting to binary " \
"switch") \
\
develop(intx, StopInterpreterAt, 0, \
develop(uintx, StopInterpreterAt, 0, \
"Stop interpreter execution at specified bytecode number") \
\
develop(intx, TraceBytecodesAt, 0, \
develop(uintx, TraceBytecodesAt, 0, \
"Trace bytecodes starting with specified bytecode number") \
\
develop(intx, TraceBytecodesStopAt, 0, \
develop(uintx, TraceBytecodesStopAt, 0, \
"Stop bytecode tracing at the specified bytecode number") \
\
/* Priorities */ \
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/runtime/java.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ static void print_method_invocation_histogram() {

static void print_bytecode_count() {
if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
tty->print_cr("[BytecodeCounter::counter_value = %d]", BytecodeCounter::counter_value());
tty->print_cr("[BytecodeCounter::counter_value = %zu]", BytecodeCounter::counter_value());
}
}

Expand Down
1 change: 1 addition & 0 deletions test/hotspot/jtreg/TEST.groups
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ tier1_runtime = \
-runtime/ErrorHandling/ReattemptErrorTest.java \
-runtime/ErrorHandling/TestHeapDumpOnOutOfMemoryError.java \
-runtime/ErrorHandling/TimeoutInErrorHandlingTest.java \
-runtime/interpreter/CountBytecodesTest.java \
-runtime/InvocationTests \
-runtime/logging/MonitorMismatchTest.java \
-runtime/memory/ReserveMemory.java \
Expand Down
77 changes: 77 additions & 0 deletions test/hotspot/jtreg/runtime/interpreter/CountBytecodesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

/*
* @test
* @bug 8350642
* @requires vm.debug & vm.bits == "64"
* @summary Test the output for CountBytecodes and validate that the counter
* does not overflow for more than 2^32 bytecodes counted.
* @library /test/lib
* @run main/othervm/timeout=300 CountBytecodesTest
Copy link
Member

Choose a reason for hiding this comment

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

The long tests should be excluded from tier1. Please update TEST.groups.

Copy link
Member Author

Choose a reason for hiding this comment

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

I excluded the test from the tier1_runtime tests. To my understanding it should now run in tier4. Could you please verify? Thanks.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, this should work. In current definition, tier4 is "catch-all" group that handles all the tests that are not explicitly in tier{1,2,3}.

*/

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import jdk.test.lib.Asserts;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;

public class CountBytecodesTest {
private final static long iterations = (1L << 32) / 9;

public static void main(String args[]) throws Exception {
if (args.length == 1 && args[0].equals("test")) {
for (long i = 0; i < iterations; i++) {
// Just iterating is enough to execute and count bytecodes.
// According to javap -c this loop translates to the following 9 bytecodes:
// 19: lload_1
// 20: ldc2_w #17
// 23: lcmp
// 24: ifge 34
// 27: lload_1
// 28: lconst_1
// 29: ladd
// 30: lstore_1
// 31: goto 19
//
// Thus we can divide the 2^32 by 9 to set the minimum number of iterations
// while maintaining execution of more than 2^32 bytecodes.
}
} else {
OutputAnalyzer output = ProcessTools.executeTestJava("-Xint", "-XX:+CountBytecodes", "CountBytecodesTest", "test");
output.shouldHaveExitValue(0);

// Output format: [BytecodeCounter::counter_value = 38676232802]
output.stdoutShouldContain("BytecodeCounter::counter_value");
String bytecodesStr = output.firstMatch("BytecodeCounter::counter_value\s*=\s*(\\d+)", 1);
long bytecodes = Long.parseLong(bytecodesStr);

System.out.println("Executed bytecodes: " + bytecodes);

Asserts.assertGTE(bytecodes, 4294967296L);
}
}
}