src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
branchJEP-349-branch
changeset 57870 00860d9caf4d
parent 57360 5d043a159d5c
child 57882 562f598d303c
equal deleted inserted replaced
57862:84ef29ccac56 57870:00860d9caf4d
    30 #include "jfr/utilities/jfrTimeConverter.hpp"
    30 #include "jfr/utilities/jfrTimeConverter.hpp"
    31 #include "jfr/utilities/jfrTypes.hpp"
    31 #include "jfr/utilities/jfrTypes.hpp"
    32 #include "runtime/mutexLocker.hpp"
    32 #include "runtime/mutexLocker.hpp"
    33 #include "runtime/os.hpp"
    33 #include "runtime/os.hpp"
    34 #include "runtime/os.inline.hpp"
    34 #include "runtime/os.inline.hpp"
    35 
       
    36 static const u2 JFR_VERSION_MAJOR = 2;
       
    37 static const u2 JFR_VERSION_MINOR = 0;
       
    38 
    35 
    39 static const int64_t MAGIC_OFFSET = 0;
    36 static const int64_t MAGIC_OFFSET = 0;
    40 static const int64_t MAGIC_LEN = 4;
    37 static const int64_t MAGIC_LEN = 4;
    41 static const int64_t VERSION_OFFSET = MAGIC_LEN;
    38 static const int64_t VERSION_OFFSET = MAGIC_LEN;
    42 static const int64_t SIZE_OFFSET = 8;
    39 static const int64_t SIZE_OFFSET = 8;
    49 static const int64_t CPU_FREQUENCY_OFFSET = START_TICKS_OFFSET + SLOT_SIZE;
    46 static const int64_t CPU_FREQUENCY_OFFSET = START_TICKS_OFFSET + SLOT_SIZE;
    50 static const int64_t GENERATION_OFFSET = CPU_FREQUENCY_OFFSET + SLOT_SIZE;
    47 static const int64_t GENERATION_OFFSET = CPU_FREQUENCY_OFFSET + SLOT_SIZE;
    51 static const int64_t CAPABILITY_OFFSET = GENERATION_OFFSET + 2;
    48 static const int64_t CAPABILITY_OFFSET = GENERATION_OFFSET + 2;
    52 static const int64_t HEADER_SIZE = CAPABILITY_OFFSET + 2;
    49 static const int64_t HEADER_SIZE = CAPABILITY_OFFSET + 2;
    53 static const int64_t RESERVE_SIZE = GENERATION_OFFSET - (4 * SIZE_OFFSET);
    50 static const int64_t RESERVE_SIZE = GENERATION_OFFSET - (4 * SIZE_OFFSET);
    54 static const int64_t VOLATILE_FIELD_SIZE = SLOT_SIZE * 2;
       
    55 
    51 
    56 static const u1 COMPLETE = 0;
    52 static const u1 COMPLETE = 0;
    57 static const u1 GUARD = 0xff;
    53 static const u1 GUARD = 0xff;
    58 static const u1 PAD = 0;
    54 static const u1 PAD = 0;
    59 static const size_t GENERATION_SIZE = sizeof(u2);
       
    60 static const size_t HEAD_BUFFER_SIZE = HEADER_SIZE + SLOT_SIZE;
       
    61 
    55 
    62 typedef NoOwnershipAdapter JfrHeadBuffer; // stack local array as buffer
    56 typedef NoOwnershipAdapter JfrHeadBuffer; // stack local array as buffer
    63 typedef StreamWriterHost<JfrHeadBuffer, StackObj> JfrBufferedHeadWriter;
    57 typedef StreamWriterHost<JfrHeadBuffer, StackObj> JfrBufferedHeadWriter;
    64 typedef WriterHost<BigEndianEncoder, BigEndianEncoder, JfrBufferedHeadWriter> JfrHeadWriterBase;
    58 typedef WriterHost<BigEndianEncoder, BigEndianEncoder, JfrBufferedHeadWriter> JfrHeadWriterBase;
    65 
    59 
    66 static uint8_t head_buffer[HEAD_BUFFER_SIZE] = {0};
       
    67 
    60 
    68 static fio_fd open_chunk(const char* path) {
    61 static fio_fd open_chunk(const char* path) {
    69   return path != NULL ? os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE) : invalid_fd;
    62   return path != NULL ? os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE) : invalid_fd;
    70 }
    63 }
    71 
    64 
       
    65 #ifdef ASSERT
       
    66 static void assert_writer_position(JfrChunkWriter* writer, int64_t offset) {
       
    67   assert(writer != NULL, "invariant");
       
    68   assert(offset == writer->current_offset(), "invariant");
       
    69 }
       
    70 #endif
       
    71 
    72 class JfrChunkHeadWriter : public StackObj {
    72 class JfrChunkHeadWriter : public StackObj {
    73   friend class JfrChunkWriter;
       
    74  private:
    73  private:
    75   JfrChunkWriter* _writer;
    74   JfrChunkWriter* _writer;
    76   JfrChunk* _chunk;
    75   JfrChunk* _chunk;
    77 
    76  public:
    78   void write_magic() {
    77   void write_magic() {
    79     assert(MAGIC_OFFSET == _writer->current_offset(), "invariant");
    78     _writer->bytes(_chunk->magic(), MAGIC_LEN);
    80     _writer->bytes("FLR", MAGIC_LEN);
       
    81   }
    79   }
    82 
    80 
    83   void write_version() {
    81   void write_version() {
    84     assert(VERSION_OFFSET == _writer->current_offset(), "invariant");
    82     _writer->be_write(_chunk->major_version());
    85     _writer->be_write((u2)JFR_VERSION_MAJOR);
    83     _writer->be_write(_chunk->minor_version());
    86     _writer->be_write((u2)JFR_VERSION_MINOR);
       
    87   }
    84   }
    88 
    85 
    89   void write_size(int64_t size) {
    86   void write_size(int64_t size) {
    90     assert(SIZE_OFFSET == _writer->current_offset(), "invariant");
       
    91     _writer->be_write(size);
    87     _writer->be_write(size);
    92   }
    88   }
    93 
    89 
    94   void write_checkpoint() {
    90   void write_checkpoint() {
    95     assert(CHECKPOINT_OFFSET == _writer->current_offset(), "invariant");
       
    96     _writer->be_write(_chunk->last_checkpoint_offset());
    91     _writer->be_write(_chunk->last_checkpoint_offset());
    97   }
    92   }
    98 
    93 
    99   void write_metadata() {
    94   void write_metadata() {
   100     assert(METADATA_OFFSET == _writer->current_offset(), "invariant");
       
   101     _writer->be_write(_chunk->last_metadata_offset());
    95     _writer->be_write(_chunk->last_metadata_offset());
   102   }
    96   }
   103 
    97 
   104   void write_time(bool finalize) {
    98   void write_time(bool finalize) {
   105     assert(_writer->is_valid(), "invariant");
       
   106     assert(_chunk != NULL, "invariant");
       
   107     assert(START_NANOS_OFFSET == _writer->current_offset(), "invariant");
       
   108     if (finalize) {
    99     if (finalize) {
   109       _writer->be_write(_chunk->previous_start_nanos());
   100       _writer->be_write(_chunk->previous_start_nanos());
   110       _writer->be_write(_chunk->last_chunk_duration());
   101       _writer->be_write(_chunk->last_chunk_duration());
   111       _writer->be_write(_chunk->previous_start_ticks());
   102       _writer->be_write(_chunk->previous_start_ticks());
   112       return;
   103       return;
   115     _writer->be_write(_chunk->duration());
   106     _writer->be_write(_chunk->duration());
   116     _writer->be_write(_chunk->start_ticks());
   107     _writer->be_write(_chunk->start_ticks());
   117   }
   108   }
   118 
   109 
   119   void write_cpu_frequency() {
   110   void write_cpu_frequency() {
   120     assert(CPU_FREQUENCY_OFFSET == _writer->current_offset(), "invariant");
   111     _writer->be_write(_chunk->cpu_frequency());
   121     static const jlong frequency = JfrTime::frequency();
       
   122     _writer->be_write(frequency);
       
   123   }
       
   124 
       
   125   void write_capabilities() {
       
   126     assert(CAPABILITY_OFFSET == _writer->current_offset(), "invariant");
       
   127     // chunk capabilities, CompressedIntegers etc
       
   128     static bool compressed_integers = JfrOptionSet::compressed_integers();
       
   129     _writer->be_write(compressed_integers ? (u2)1 : (u2)0);
       
   130   }
   112   }
   131 
   113 
   132   void write_generation(bool finalize) {
   114   void write_generation(bool finalize) {
   133     assert(GENERATION_OFFSET == _writer->current_offset(), "invariant");
       
   134     _writer->be_write(finalize ? COMPLETE : _chunk->generation());
   115     _writer->be_write(finalize ? COMPLETE : _chunk->generation());
   135     _writer->be_write(PAD);
   116     _writer->be_write(PAD);
   136   }
   117   }
   137 
   118 
       
   119   void write_next_generation() {
       
   120     _writer->be_write(_chunk->next_generation());
       
   121     _writer->be_write(PAD);
       
   122   }
       
   123 
   138   void write_guard() {
   124   void write_guard() {
   139     assert(GENERATION_OFFSET == _writer->current_offset(), "invariant");
       
   140     _writer->be_write(GUARD);
   125     _writer->be_write(GUARD);
   141     _writer->be_write(PAD);
   126     _writer->be_write(PAD);
   142   }
   127   }
   143 
   128 
   144   void write_guard_flush() {
   129   void write_guard_flush() {
   145     assert(GENERATION_OFFSET == _writer->current_offset(), "invariant");
       
   146     write_guard();
   130     write_guard();
   147     _writer->flush();
   131     _writer->flush();
   148   }
   132   }
   149 
   133 
   150   void initialize() {
   134   void write_capabilities() {
   151     assert(_writer->is_valid(), "invariant");
   135     _writer->be_write(_chunk->capabilities());
   152     assert(_chunk != NULL, "invariant");
   136   }
   153     assert(0 == _writer->current_offset(), "invariant");
   137 
   154     write_magic();
   138   void write_size_to_generation(int64_t size, bool finalize) {
   155     write_version();
       
   156     write_size(HEADER_SIZE);
       
   157     write_checkpoint();
       
   158     write_metadata();
       
   159     write_time(false);
       
   160     write_cpu_frequency();
       
   161     write_generation(false);
       
   162     write_capabilities();
       
   163     assert(HEADER_SIZE == _writer->current_offset(), "invariant");
       
   164     _writer->flush();
       
   165   }
       
   166 
       
   167   void flush(int64_t size, bool finalize) {
       
   168     assert(_writer->is_valid(), "invariant");
       
   169     assert(_chunk != NULL, "invariant");
       
   170     assert(SIZE_OFFSET == _writer->current_offset(), "invariant");
       
   171     write_size(size);
   139     write_size(size);
   172     write_checkpoint();
   140     write_checkpoint();
   173     write_metadata();
   141     write_metadata();
   174     write_time(finalize);
   142     write_time(finalize);
   175     write_cpu_frequency();
   143     write_cpu_frequency();
   176     write_generation(finalize);
   144     write_generation(finalize);
       
   145   }
       
   146 
       
   147   void flush(int64_t size, bool finalize) {
       
   148     assert(_writer->is_valid(), "invariant");
       
   149     assert(_chunk != NULL, "invariant");
       
   150     DEBUG_ONLY(assert_writer_position(_writer, SIZE_OFFSET);)
       
   151     write_size_to_generation(size, finalize);
   177     // no need to write capabilities
   152     // no need to write capabilities
   178     _writer->seek(size); // implicit flush
   153     _writer->seek(size); // implicit flush
   179   }
   154   }
   180 
   155 
   181   JfrChunkHeadWriter(JfrChunkWriter* writer, int64_t offset) : _writer(writer), _chunk(writer->_chunk) {
   156   void initialize() {
       
   157     assert(_writer->is_valid(), "invariant");
       
   158     assert(_chunk != NULL, "invariant");
       
   159     DEBUG_ONLY(assert_writer_position(_writer, 0);)
       
   160     write_magic();
       
   161     write_version();
       
   162     write_size_to_generation(HEADER_SIZE, false);
       
   163     write_capabilities();
       
   164     DEBUG_ONLY(assert_writer_position(_writer, HEADER_SIZE);)
       
   165     _writer->flush();
       
   166   }
       
   167 
       
   168   JfrChunkHeadWriter(JfrChunkWriter* writer, int64_t offset, bool head = true) : _writer(writer), _chunk(writer->_chunk) {
   182     assert(_writer != NULL, "invariant");
   169     assert(_writer != NULL, "invariant");
   183     assert(_writer->is_valid(), "invariant");
   170     assert(_writer->is_valid(), "invariant");
   184     assert(_chunk != NULL, "invariant");
   171     assert(_chunk != NULL, "invariant");
   185     if (0 == _writer->current_offset()) {
   172     if (0 == _writer->current_offset()) {
   186       assert(HEADER_SIZE == offset, "invariant");
   173       assert(HEADER_SIZE == offset, "invariant");
   187       initialize();
   174       initialize();
   188     } else {
   175     } else {
   189       _writer->seek(GENERATION_OFFSET);
   176       if (head) {
   190       write_guard();
   177         _writer->seek(GENERATION_OFFSET);
   191       _writer->seek(offset);
   178         write_guard();
       
   179         _writer->seek(offset);
       
   180       }
   192     }
   181     }
   193     assert(offset == _writer->current_offset(), "invariant");
   182     DEBUG_ONLY(assert_writer_position(_writer, offset);)
   194   }
   183   }
   195 };
   184 };
   196 
   185 
       
   186 static void write_checkpoint_header(JfrChunkWriter& cw, int64_t event_offset, bool flushpoint) {
       
   187   const int64_t delta = cw.last_checkpoint_offset() == 0 ? 0 : cw.last_checkpoint_offset() - event_offset;
       
   188   cw.reserve(sizeof(u4));
       
   189   cw.write<u8>(EVENT_CHECKPOINT);
       
   190   cw.write<u8>(JfrTicks::now().value());
       
   191   cw.write<u8>(0); // duration
       
   192   cw.write<u8>(delta); // to previous checkpoint
       
   193   cw.write<bool>(flushpoint);
       
   194   cw.write<u4>(1); // pool count
       
   195   cw.write<u8>(TYPE_CHUNKHEADER);
       
   196   cw.write<u4>(1); // count
       
   197   cw.write<u8>(1); // key
       
   198   cw.write<u4>(HEADER_SIZE); // length of byte array
       
   199 }
       
   200 
       
   201 int64_t JfrChunkWriter::write_chunk_header_checkpoint(bool flushpoint) {
       
   202   assert(this->has_valid_fd(), "invariant");
       
   203   const int64_t event_size_offset = current_offset();
       
   204   write_checkpoint_header(*this, event_size_offset, flushpoint);
       
   205   const int64_t start_offset = current_offset();
       
   206   JfrChunkHeadWriter head(this, start_offset, false);
       
   207   head.write_magic();
       
   208   head.write_version();
       
   209   const int64_t size_offset = reserve(sizeof(int64_t));
       
   210   be_write(event_size_offset); // last checkpoint offset will be this checkpoint
       
   211   head.write_metadata();
       
   212   head.write_time(false);
       
   213   head.write_cpu_frequency();
       
   214   head.write_next_generation();
       
   215   head.write_capabilities();
       
   216   assert(current_offset() - start_offset == HEADER_SIZE, "invariant");
       
   217   const u4 checkpoint_size = current_offset() - event_size_offset;
       
   218   write_padded_at_offset<u4>(checkpoint_size, event_size_offset);
       
   219   set_last_checkpoint_offset(event_size_offset);
       
   220   const size_t sz_written = size_written();
       
   221   write_be_at_offset(sz_written, size_offset);
       
   222   return sz_written;
       
   223 }
       
   224 
       
   225 int64_t JfrChunkWriter::flushpoint(bool flushpoint) {
       
   226   assert(_chunk != NULL, "invariant");
       
   227   if (flushpoint) {
       
   228     _chunk->update();
       
   229   }
       
   230   const int64_t sz_written = write_chunk_header_checkpoint(flushpoint);
       
   231   assert(size_written() == sz_written, "invariant");
       
   232   JfrChunkHeadWriter head(this, SIZE_OFFSET);
       
   233   head.flush(sz_written, !flushpoint);
       
   234   return sz_written;
       
   235 }
       
   236 
   197 JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunk(new JfrChunk()) {}
   237 JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunk(new JfrChunk()) {}
   198 
   238 
   199 JfrChunkWriter::~JfrChunkWriter() {
   239 JfrChunkWriter::~JfrChunkWriter() {
   200   assert(_chunk != NULL, "invariant");
   240   assert(_chunk != NULL, "invariant");
   201   delete _chunk;
   241   delete _chunk;
   207 }
   247 }
   208 
   248 
   209 void JfrChunkWriter::time_stamp_chunk_now() {
   249 void JfrChunkWriter::time_stamp_chunk_now() {
   210   assert(_chunk != NULL, "invariant");
   250   assert(_chunk != NULL, "invariant");
   211   _chunk->update_time_to_now();
   251   _chunk->update_time_to_now();
   212 }
       
   213 
       
   214 int64_t JfrChunkWriter::flushpoint(bool finalize) {
       
   215   assert(_chunk != NULL, "invariant");
       
   216   const int64_t sz_written = size_written();
       
   217   if (!finalize) {
       
   218     _chunk->update();
       
   219   }
       
   220   JfrChunkHeadWriter head(this, SIZE_OFFSET);
       
   221   head.flush(sz_written, finalize);
       
   222   return sz_written;
       
   223 }
   252 }
   224 
   253 
   225 int64_t JfrChunkWriter::size_written() const {
   254 int64_t JfrChunkWriter::size_written() const {
   226   return this->is_valid() ? this->current_offset() : 0;
   255   return this->is_valid() ? this->current_offset() : 0;
   227 }
   256 }
   270   return is_open;
   299   return is_open;
   271 }
   300 }
   272 
   301 
   273 int64_t JfrChunkWriter::close() {
   302 int64_t JfrChunkWriter::close() {
   274   assert(this->has_valid_fd(), "invariant");
   303   assert(this->has_valid_fd(), "invariant");
   275   const int64_t size_written = flushpoint(true);
   304   const int64_t size_written = flushpoint(false);
   276   this->close_fd();
   305   this->close_fd();
   277   assert(!this->is_valid(), "invariant");
   306   assert(!this->is_valid(), "invariant");
   278   return size_written;
   307   return size_written;
   279 }
   308 }