8298129: Let checkpoint event sizes grow beyond u4 limit

Reviewed-by: egahlin
This commit is contained in:
Markus Grönlund 2022-12-08 12:51:46 +00:00
parent 165dcdd27d
commit ea108f504c
6 changed files with 122 additions and 55 deletions

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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);