mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-27 18:50:07 +00:00
8298129: Let checkpoint event sizes grow beyond u4 limit
Reviewed-by: egahlin
This commit is contained in:
parent
165dcdd27d
commit
ea108f504c
@ -300,75 +300,72 @@ BufferPtr JfrCheckpointManager::flush(BufferPtr old, size_t used, size_t request
|
||||
}
|
||||
|
||||
// offsets into the JfrCheckpointEntry
|
||||
static const juint starttime_offset = sizeof(jlong);
|
||||
static const juint duration_offset = starttime_offset + sizeof(jlong);
|
||||
static const juint checkpoint_type_offset = duration_offset + sizeof(jlong);
|
||||
static const juint types_offset = checkpoint_type_offset + sizeof(juint);
|
||||
static const juint payload_offset = types_offset + sizeof(juint);
|
||||
static const size_t starttime_offset = sizeof(int64_t);
|
||||
static const size_t duration_offset = starttime_offset + sizeof(int64_t);
|
||||
static const size_t checkpoint_type_offset = duration_offset + sizeof(int64_t);
|
||||
static const size_t types_offset = checkpoint_type_offset + sizeof(uint32_t);
|
||||
static const size_t payload_offset = types_offset + sizeof(uint32_t);
|
||||
|
||||
template <typename Return>
|
||||
static Return read_data(const u1* data) {
|
||||
return JfrBigEndian::read<Return>(data);
|
||||
}
|
||||
|
||||
static jlong total_size(const u1* data) {
|
||||
return read_data<jlong>(data);
|
||||
static size_t total_size(const u1* data) {
|
||||
const int64_t size = read_data<int64_t>(data);
|
||||
assert(size > 0, "invariant");
|
||||
return static_cast<size_t>(size);
|
||||
}
|
||||
|
||||
static jlong starttime(const u1* data) {
|
||||
return read_data<jlong>(data + starttime_offset);
|
||||
static int64_t starttime(const u1* data) {
|
||||
return read_data<int64_t>(data + starttime_offset);
|
||||
}
|
||||
|
||||
static jlong duration(const u1* data) {
|
||||
return read_data<jlong>(data + duration_offset);
|
||||
static int64_t duration(const u1* data) {
|
||||
return read_data<int64_t>(data + duration_offset);
|
||||
}
|
||||
|
||||
static juint checkpoint_type(const u1* data) {
|
||||
return read_data<juint>(data + checkpoint_type_offset);
|
||||
static int32_t checkpoint_type(const u1* data) {
|
||||
return read_data<int32_t>(data + checkpoint_type_offset);
|
||||
}
|
||||
|
||||
static juint number_of_types(const u1* data) {
|
||||
return read_data<juint>(data + types_offset);
|
||||
static uint32_t number_of_types(const u1* data) {
|
||||
return read_data<uint32_t>(data + types_offset);
|
||||
}
|
||||
|
||||
static void write_checkpoint_header(JfrChunkWriter& cw, int64_t delta_to_last_checkpoint, const u1* data) {
|
||||
cw.reserve(sizeof(u4));
|
||||
cw.write<u8>(EVENT_CHECKPOINT);
|
||||
cw.write(starttime(data));
|
||||
cw.write(duration(data));
|
||||
cw.write(delta_to_last_checkpoint);
|
||||
cw.write(checkpoint_type(data));
|
||||
cw.write(number_of_types(data));
|
||||
static size_t payload_size(const u1* data) {
|
||||
return total_size(data) - sizeof(JfrCheckpointEntry);
|
||||
}
|
||||
|
||||
static void write_checkpoint_content(JfrChunkWriter& cw, const u1* data, size_t size) {
|
||||
assert(data != NULL, "invariant");
|
||||
cw.write_unbuffered(data + payload_offset, size - sizeof(JfrCheckpointEntry));
|
||||
}
|
||||
|
||||
static size_t write_thread_checkpoint_content(JfrChunkWriter& cw, const u1* data) {
|
||||
assert(data != NULL, "invariant");
|
||||
const size_t size = total_size(data);
|
||||
assert(size > sizeof(JfrCheckpointEntry), "invariant");
|
||||
assert(checkpoint_type(data) == THREADS, "invariant");
|
||||
assert(number_of_types(data) == 1, "invariant");
|
||||
// Thread checkpoints are small so write them buffered to cache as much as possible before flush.
|
||||
cw.write_buffered(data + payload_offset, size - sizeof(JfrCheckpointEntry));
|
||||
return size;
|
||||
static uint64_t calculate_event_size_bytes(JfrChunkWriter& cw, const u1* data, int64_t event_begin, int64_t delta_to_last_checkpoint) {
|
||||
assert(data != nullptr, "invariant");
|
||||
size_t bytes = cw.size_in_bytes(EVENT_CHECKPOINT);
|
||||
bytes += cw.size_in_bytes(starttime(data));
|
||||
bytes += cw.size_in_bytes(duration(data));
|
||||
bytes += cw.size_in_bytes(delta_to_last_checkpoint);
|
||||
bytes += cw.size_in_bytes(checkpoint_type(data));
|
||||
bytes += cw.size_in_bytes(number_of_types(data));
|
||||
bytes += payload_size(data); // in bytes already.
|
||||
return bytes + cw.size_in_bytes(bytes + cw.size_in_bytes(bytes));
|
||||
}
|
||||
|
||||
static size_t write_checkpoint_event(JfrChunkWriter& cw, const u1* data) {
|
||||
assert(data != NULL, "invariant");
|
||||
const int64_t event_begin = cw.current_offset();
|
||||
const int64_t last_checkpoint_event = cw.last_checkpoint_offset();
|
||||
const int64_t delta_to_last_checkpoint = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin;
|
||||
const int64_t checkpoint_size = total_size(data);
|
||||
write_checkpoint_header(cw, delta_to_last_checkpoint, data);
|
||||
write_checkpoint_content(cw, data, checkpoint_size);
|
||||
const int64_t event_size = cw.current_offset() - event_begin;
|
||||
cw.write_padded_at_offset<u4>(event_size, event_begin);
|
||||
cw.set_last_checkpoint_offset(event_begin);
|
||||
return (size_t)checkpoint_size;
|
||||
const int64_t delta_to_last_checkpoint = last_checkpoint_event == 0 ? 0 : last_checkpoint_event - event_begin;
|
||||
const uint64_t event_size = calculate_event_size_bytes(cw, data, event_begin, delta_to_last_checkpoint);
|
||||
cw.write(event_size);
|
||||
cw.write(EVENT_CHECKPOINT);
|
||||
cw.write(starttime(data));
|
||||
cw.write(duration(data));
|
||||
cw.write(delta_to_last_checkpoint);
|
||||
cw.write(checkpoint_type(data));
|
||||
cw.write(number_of_types(data));
|
||||
cw.write_unbuffered(data + payload_offset, payload_size(data));
|
||||
assert(static_cast<uint64_t>(cw.current_offset() - event_begin) == event_size, "invariant");
|
||||
return total_size(data);
|
||||
}
|
||||
|
||||
static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size) {
|
||||
@ -387,6 +384,17 @@ static size_t write_checkpoints(JfrChunkWriter& cw, const u1* data, size_t size)
|
||||
return processed;
|
||||
}
|
||||
|
||||
static size_t write_thread_checkpoint_content(JfrChunkWriter& cw, const u1* data) {
|
||||
assert(data != NULL, "invariant");
|
||||
const size_t size = total_size(data);
|
||||
assert(size > 0, "invariant");
|
||||
assert(checkpoint_type(data) == THREADS, "invariant");
|
||||
assert(number_of_types(data) == 1, "invariant");
|
||||
// Thread checkpoints are small so write them buffered to cache as much as possible before flush.
|
||||
cw.write_buffered(data + payload_offset, payload_size(data));
|
||||
return size;
|
||||
}
|
||||
|
||||
static size_t write_thread_checkpoint_payloads(JfrChunkWriter& cw, const u1* data, size_t size, u4& elements) {
|
||||
assert(cw.is_valid(), "invariant");
|
||||
assert(data != NULL, "invariant");
|
||||
@ -419,7 +427,6 @@ class CheckpointWriteOp {
|
||||
size_t processed() const { return _processed; }
|
||||
};
|
||||
|
||||
|
||||
// This op will collapse all individual vthread checkpoints into a single checkpoint.
|
||||
template <typename T>
|
||||
class VirtualThreadLocalCheckpointWriteOp {
|
||||
@ -428,14 +435,14 @@ class VirtualThreadLocalCheckpointWriteOp {
|
||||
int64_t _begin_offset;
|
||||
int64_t _elements_offset;
|
||||
size_t _processed;
|
||||
u4 _elements;
|
||||
uint32_t _elements;
|
||||
public:
|
||||
typedef T Type;
|
||||
VirtualThreadLocalCheckpointWriteOp(JfrChunkWriter& cw) : _cw(cw), _begin_offset(cw.current_offset()), _elements_offset(0), _processed(0), _elements(0) {
|
||||
const int64_t last_checkpoint = cw.last_checkpoint_offset();
|
||||
const int64_t delta = last_checkpoint == 0 ? 0 : last_checkpoint - _begin_offset;
|
||||
cw.reserve(sizeof(u4));
|
||||
cw.write<u8>(EVENT_CHECKPOINT);
|
||||
cw.reserve(sizeof(uint64_t));
|
||||
cw.write(EVENT_CHECKPOINT);
|
||||
cw.write(JfrTicks::now().value());
|
||||
cw.write(0);
|
||||
cw.write(delta);
|
||||
@ -443,7 +450,7 @@ class VirtualThreadLocalCheckpointWriteOp {
|
||||
cw.write(1); // Number of types in this checkpoint, only one, TYPE_THREAD.
|
||||
cw.write(TYPE_THREAD); // Constant pool type.
|
||||
_elements_offset = cw.current_offset(); // Offset for the number of entries in the TYPE_THREAD constant pool.
|
||||
cw.reserve(sizeof(u4));
|
||||
cw.reserve(sizeof(uint32_t));
|
||||
}
|
||||
|
||||
~VirtualThreadLocalCheckpointWriteOp() {
|
||||
@ -453,8 +460,8 @@ class VirtualThreadLocalCheckpointWriteOp {
|
||||
return;
|
||||
}
|
||||
const int64_t event_size = _cw.current_offset() - _begin_offset;
|
||||
_cw.write_padded_at_offset<u4>(_elements, _elements_offset);
|
||||
_cw.write_padded_at_offset<u4>(event_size, _begin_offset);
|
||||
_cw.write_padded_at_offset(_elements, _elements_offset);
|
||||
_cw.write_padded_at_offset(event_size, _begin_offset);
|
||||
_cw.set_last_checkpoint_offset(_begin_offset);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2022, Oracle and/or its affiliates. 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
|
||||
@ -63,6 +63,9 @@ class BigEndianEncoderImpl {
|
||||
template <typename T>
|
||||
static size_t encode_padded(const T* src, size_t len, u1* dest);
|
||||
|
||||
template <typename T>
|
||||
static size_t size_in_bytes(T value);
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -129,6 +132,17 @@ inline size_t BigEndianEncoderImpl::encode_padded(const T* src, size_t len, u1*
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t BigEndianEncoderImpl::size_in_bytes(T value) {
|
||||
switch (sizeof(T)) {
|
||||
case 1: return 1;
|
||||
case 2: return 2;
|
||||
case 4: return 4;
|
||||
case 8:return 8;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The Varint128 encoder implements encoding according to
|
||||
// msb(it) 128bit encoding (1 encode bit | 7 value bits),
|
||||
@ -160,6 +174,9 @@ class Varint128EncoderImpl {
|
||||
template <typename T>
|
||||
static size_t encode_padded(const T* src, size_t len, u1* dest);
|
||||
|
||||
template <typename T>
|
||||
static size_t size_in_bytes(T value);
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -295,4 +312,34 @@ inline size_t Varint128EncoderImpl::encode_padded(const T* src, size_t len, u1*
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline size_t Varint128EncoderImpl::size_in_bytes(T value) {
|
||||
const u8 v = to_u8(value);
|
||||
if (LESS_THAN_128(v)) {
|
||||
return 1;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 7)) {
|
||||
return 2;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 14)) {
|
||||
return 3;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 21)) {
|
||||
return 4;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 28)) {
|
||||
return 5;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 35)) {
|
||||
return 6;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 42)) {
|
||||
return 7;
|
||||
}
|
||||
if (LESS_THAN_128(v >> 49)) {
|
||||
return 8;
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
|
||||
#endif // SHARE_JFR_WRITERS_JFRENCODERS_HPP
|
||||
|
||||
@ -69,6 +69,11 @@ class EncoderHost : public AllStatic {
|
||||
return pos + IntegerEncoder::encode_padded(value, len, pos);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static size_t size_in_bytes(T value) {
|
||||
return IntegerEncoder::size_in_bytes(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static u1* write(T value, u1* pos) {
|
||||
return write(&value, 1, pos);
|
||||
|
||||
@ -98,6 +98,8 @@ class WriterHost : public WriterPolicyImpl {
|
||||
template <typename T>
|
||||
void write_be_at_offset(T value, int64_t offset);
|
||||
int64_t reserve(size_t size);
|
||||
template <typename T>
|
||||
size_t size_in_bytes(T value);
|
||||
};
|
||||
|
||||
#endif // SHARE_JFR_WRITERS_JFRWRITERHOST_HPP
|
||||
|
||||
@ -363,4 +363,10 @@ inline void WriterHost<BE, IE, WriterPolicyImpl>::write_be_at_offset(T value, in
|
||||
}
|
||||
}
|
||||
|
||||
template <typename BE, typename IE, typename WriterPolicyImpl>
|
||||
template <typename T>
|
||||
inline size_t WriterHost<BE, IE, WriterPolicyImpl>::size_in_bytes(T value) {
|
||||
return IE::size_in_bytes(value);
|
||||
}
|
||||
|
||||
#endif // SHARE_JFR_WRITERS_JFRWRITERHOST_INLINE_HPP
|
||||
|
||||
@ -228,7 +228,7 @@ public final class ChunkParser {
|
||||
long absoluteChunkEnd = chunkHeader.getEnd();
|
||||
while (input.position() < absoluteChunkEnd) {
|
||||
long pos = input.position();
|
||||
int size = input.readInt();
|
||||
long size = input.readLong();
|
||||
if (size == 0) {
|
||||
throw new IOException("Event can't have zero size");
|
||||
}
|
||||
@ -243,7 +243,7 @@ public final class ChunkParser {
|
||||
if (chunkWriter.accept(event)) {
|
||||
chunkWriter.writeEvent(pos, input.position());
|
||||
input.position(pos);
|
||||
input.readInt(); // size
|
||||
input.readLong(); // size
|
||||
input.readLong(); // type
|
||||
chunkWriter.touch(ep.parseReferences(input));
|
||||
}
|
||||
@ -310,7 +310,7 @@ public final class ChunkParser {
|
||||
}
|
||||
input.position(thisCP);
|
||||
lastCP = thisCP;
|
||||
int size = input.readInt(); // size
|
||||
long size = input.readLong(); // size
|
||||
long typeId = input.readLong();
|
||||
if (typeId != CONSTANT_POOL_TYPE_ID) {
|
||||
throw new IOException("Expected check point event (id = 1) at position " + lastCP + ", but found type id = " + typeId);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user