src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
changeset 58863 c16ac7a2eba4
parent 58132 caa25ab47aca
child 59226 a0f39cc47387
equal deleted inserted replaced
58861:2c3cc4b01880 58863:c16ac7a2eba4
    21  * questions.
    21  * questions.
    22  *
    22  *
    23  */
    23  */
    24 
    24 
    25 #include "precompiled.hpp"
    25 #include "precompiled.hpp"
    26 #include "jfr/recorder/repository/jfrChunkState.hpp"
    26 #include "jfr/recorder/repository/jfrChunk.hpp"
    27 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
    27 #include "jfr/recorder/repository/jfrChunkWriter.hpp"
    28 #include "jfr/recorder/service/jfrOptionSet.hpp"
       
    29 #include "jfr/utilities/jfrTime.hpp"
    28 #include "jfr/utilities/jfrTime.hpp"
    30 #include "jfr/utilities/jfrTypes.hpp"
       
    31 #include "runtime/mutexLocker.hpp"
    29 #include "runtime/mutexLocker.hpp"
    32 #include "runtime/os.hpp"
       
    33 #include "runtime/os.inline.hpp"
    30 #include "runtime/os.inline.hpp"
    34 
    31 
    35 static const u2 JFR_VERSION_MAJOR = 2;
    32 static const int64_t MAGIC_OFFSET = 0;
    36 static const u2 JFR_VERSION_MINOR = 0;
    33 static const int64_t MAGIC_LEN = 4;
    37 static const size_t MAGIC_LEN = 4;
    34 static const int64_t VERSION_OFFSET = MAGIC_LEN;
    38 static const size_t FILEHEADER_SLOT_SIZE = 8;
    35 static const int64_t SIZE_OFFSET = 8;
    39 static const size_t CHUNK_SIZE_OFFSET = 8;
    36 static const int64_t SLOT_SIZE = 8;
    40 
    37 static const int64_t CHECKPOINT_OFFSET = SIZE_OFFSET + SLOT_SIZE;
    41 JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunkstate(NULL) {}
    38 static const int64_t METADATA_OFFSET = CHECKPOINT_OFFSET + SLOT_SIZE;
    42 
    39 static const int64_t START_NANOS_OFFSET = METADATA_OFFSET + SLOT_SIZE;
    43 bool JfrChunkWriter::initialize() {
    40 static const int64_t DURATION_NANOS_OFFSET = START_NANOS_OFFSET + SLOT_SIZE;
    44   assert(_chunkstate == NULL, "invariant");
    41 static const int64_t START_TICKS_OFFSET = DURATION_NANOS_OFFSET + SLOT_SIZE;
    45   _chunkstate = new JfrChunkState();
    42 static const int64_t CPU_FREQUENCY_OFFSET = START_TICKS_OFFSET + SLOT_SIZE;
    46   return _chunkstate != NULL;
    43 static const int64_t GENERATION_OFFSET = CPU_FREQUENCY_OFFSET + SLOT_SIZE;
    47 }
    44 static const int64_t CAPABILITY_OFFSET = GENERATION_OFFSET + 2;
       
    45 static const int64_t HEADER_SIZE = CAPABILITY_OFFSET + 2;
    48 
    46 
    49 static fio_fd open_chunk(const char* path) {
    47 static fio_fd open_chunk(const char* path) {
    50   assert(JfrStream_lock->owned_by_self(), "invariant");
       
    51   return path != NULL ? os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE) : invalid_fd;
    48   return path != NULL ? os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE) : invalid_fd;
    52 }
    49 }
    53 
    50 
       
    51 #ifdef ASSERT
       
    52 static void assert_writer_position(JfrChunkWriter* writer, int64_t offset) {
       
    53   assert(writer != NULL, "invariant");
       
    54   assert(offset == writer->current_offset(), "invariant");
       
    55 }
       
    56 #endif
       
    57 
       
    58 class JfrChunkHeadWriter : public StackObj {
       
    59  private:
       
    60   JfrChunkWriter* _writer;
       
    61   JfrChunk* _chunk;
       
    62  public:
       
    63   void write_magic() {
       
    64     _writer->bytes(_chunk->magic(), MAGIC_LEN);
       
    65   }
       
    66 
       
    67   void write_version() {
       
    68     _writer->be_write(_chunk->major_version());
       
    69     _writer->be_write(_chunk->minor_version());
       
    70   }
       
    71 
       
    72   void write_size(int64_t size) {
       
    73     _writer->be_write(size);
       
    74   }
       
    75 
       
    76   void write_checkpoint() {
       
    77     _writer->be_write(_chunk->last_checkpoint_offset());
       
    78   }
       
    79 
       
    80   void write_metadata() {
       
    81     _writer->be_write(_chunk->last_metadata_offset());
       
    82   }
       
    83 
       
    84   void write_time(bool finalize) {
       
    85     if (finalize) {
       
    86       _writer->be_write(_chunk->previous_start_nanos());
       
    87       _writer->be_write(_chunk->last_chunk_duration());
       
    88       _writer->be_write(_chunk->previous_start_ticks());
       
    89       return;
       
    90     }
       
    91     _writer->be_write(_chunk->start_nanos());
       
    92     _writer->be_write(_chunk->duration());
       
    93     _writer->be_write(_chunk->start_ticks());
       
    94   }
       
    95 
       
    96   void write_cpu_frequency() {
       
    97     _writer->be_write(_chunk->cpu_frequency());
       
    98   }
       
    99 
       
   100   void write_generation(bool finalize) {
       
   101     _writer->be_write(finalize ? COMPLETE : _chunk->generation());
       
   102     _writer->be_write(PAD);
       
   103   }
       
   104 
       
   105   void write_next_generation() {
       
   106     _writer->be_write(_chunk->next_generation());
       
   107     _writer->be_write(PAD);
       
   108   }
       
   109 
       
   110   void write_guard() {
       
   111     _writer->be_write(GUARD);
       
   112     _writer->be_write(PAD);
       
   113   }
       
   114 
       
   115   void write_guard_flush() {
       
   116     write_guard();
       
   117     _writer->flush();
       
   118   }
       
   119 
       
   120   void write_capabilities() {
       
   121     _writer->be_write(_chunk->capabilities());
       
   122   }
       
   123 
       
   124   void write_size_to_generation(int64_t size, bool finalize) {
       
   125     write_size(size);
       
   126     write_checkpoint();
       
   127     write_metadata();
       
   128     write_time(finalize);
       
   129     write_cpu_frequency();
       
   130     write_generation(finalize);
       
   131   }
       
   132 
       
   133   void flush(int64_t size, bool finalize) {
       
   134     assert(_writer->is_valid(), "invariant");
       
   135     assert(_chunk != NULL, "invariant");
       
   136     DEBUG_ONLY(assert_writer_position(_writer, SIZE_OFFSET);)
       
   137     write_size_to_generation(size, finalize);
       
   138     // no need to write capabilities
       
   139     _writer->seek(size); // implicit flush
       
   140   }
       
   141 
       
   142   void initialize() {
       
   143     assert(_writer->is_valid(), "invariant");
       
   144     assert(_chunk != NULL, "invariant");
       
   145     DEBUG_ONLY(assert_writer_position(_writer, 0);)
       
   146     write_magic();
       
   147     write_version();
       
   148     write_size_to_generation(HEADER_SIZE, false);
       
   149     write_capabilities();
       
   150     DEBUG_ONLY(assert_writer_position(_writer, HEADER_SIZE);)
       
   151     _writer->flush();
       
   152   }
       
   153 
       
   154   JfrChunkHeadWriter(JfrChunkWriter* writer, int64_t offset, bool guard = true) : _writer(writer), _chunk(writer->_chunk) {
       
   155     assert(_writer != NULL, "invariant");
       
   156     assert(_writer->is_valid(), "invariant");
       
   157     assert(_chunk != NULL, "invariant");
       
   158     if (0 == _writer->current_offset()) {
       
   159       assert(HEADER_SIZE == offset, "invariant");
       
   160       initialize();
       
   161     } else {
       
   162       if (guard) {
       
   163         _writer->seek(GENERATION_OFFSET);
       
   164         write_guard();
       
   165         _writer->seek(offset);
       
   166       } else {
       
   167         _chunk->update_current_nanos();
       
   168       }
       
   169     }
       
   170     DEBUG_ONLY(assert_writer_position(_writer, offset);)
       
   171   }
       
   172 };
       
   173 
       
   174 static int64_t prepare_chunk_header_constant_pool(JfrChunkWriter& cw, int64_t event_offset, bool flushpoint) {
       
   175   const int64_t delta = cw.last_checkpoint_offset() == 0 ? 0 : cw.last_checkpoint_offset() - event_offset;
       
   176   const u4 checkpoint_type = flushpoint ? (u4)(FLUSH | HEADER) : (u4)HEADER;
       
   177   cw.reserve(sizeof(u4));
       
   178   cw.write<u8>(EVENT_CHECKPOINT);
       
   179   cw.write<u8>(JfrTicks::now().value());
       
   180   cw.write<u8>(0); // duration
       
   181   cw.write<u8>(delta); // to previous checkpoint
       
   182   cw.write<u4>(checkpoint_type);
       
   183   cw.write<u4>(1); // pool count
       
   184   cw.write<u8>(TYPE_CHUNKHEADER);
       
   185   cw.write<u4>(1); // count
       
   186   cw.write<u8>(1); // key
       
   187   cw.write<u4>(HEADER_SIZE); // length of byte array
       
   188   return cw.current_offset();
       
   189 }
       
   190 
       
   191 int64_t JfrChunkWriter::write_chunk_header_checkpoint(bool flushpoint) {
       
   192   assert(this->has_valid_fd(), "invariant");
       
   193   const int64_t event_size_offset = current_offset();
       
   194   const int64_t header_content_pos = prepare_chunk_header_constant_pool(*this, event_size_offset, flushpoint);
       
   195   JfrChunkHeadWriter head(this, header_content_pos, false);
       
   196   head.write_magic();
       
   197   head.write_version();
       
   198   const int64_t chunk_size_offset = reserve(sizeof(int64_t)); // size to be decided when we are done
       
   199   be_write(event_size_offset); // last checkpoint offset will be this checkpoint
       
   200   head.write_metadata();
       
   201   head.write_time(false);
       
   202   head.write_cpu_frequency();
       
   203   head.write_next_generation();
       
   204   head.write_capabilities();
       
   205   assert(current_offset() - header_content_pos == HEADER_SIZE, "invariant");
       
   206   const u4 checkpoint_size = current_offset() - event_size_offset;
       
   207   write_padded_at_offset<u4>(checkpoint_size, event_size_offset);
       
   208   set_last_checkpoint_offset(event_size_offset);
       
   209   const size_t sz_written = size_written();
       
   210   write_be_at_offset(sz_written, chunk_size_offset);
       
   211   return sz_written;
       
   212 }
       
   213 
       
   214 int64_t JfrChunkWriter::flush_chunk(bool flushpoint) {
       
   215   assert(_chunk != NULL, "invariant");
       
   216   const int64_t sz_written = write_chunk_header_checkpoint(flushpoint);
       
   217   assert(size_written() == sz_written, "invariant");
       
   218   JfrChunkHeadWriter head(this, SIZE_OFFSET);
       
   219   head.flush(sz_written, !flushpoint);
       
   220   return sz_written;
       
   221 }
       
   222 
       
   223 JfrChunkWriter::JfrChunkWriter() : JfrChunkWriterBase(NULL), _chunk(new JfrChunk()) {}
       
   224 
       
   225 JfrChunkWriter::~JfrChunkWriter() {
       
   226   assert(_chunk != NULL, "invariant");
       
   227   delete _chunk;
       
   228 }
       
   229 
       
   230 void JfrChunkWriter::set_path(const char* path) {
       
   231   assert(_chunk != NULL, "invariant");
       
   232   _chunk->set_path(path);
       
   233 }
       
   234 
       
   235 void JfrChunkWriter::set_time_stamp() {
       
   236   assert(_chunk != NULL, "invariant");
       
   237   _chunk->set_time_stamp();
       
   238 }
       
   239 
       
   240 int64_t JfrChunkWriter::size_written() const {
       
   241   return this->is_valid() ? this->current_offset() : 0;
       
   242 }
       
   243 
       
   244 int64_t JfrChunkWriter::last_checkpoint_offset() const {
       
   245   assert(_chunk != NULL, "invariant");
       
   246   return _chunk->last_checkpoint_offset();
       
   247 }
       
   248 
       
   249 int64_t JfrChunkWriter::current_chunk_start_nanos() const {
       
   250   assert(_chunk != NULL, "invariant");
       
   251   return this->is_valid() ? _chunk->start_nanos() : invalid_time;
       
   252 }
       
   253 
       
   254 void JfrChunkWriter::set_last_checkpoint_offset(int64_t offset) {
       
   255   assert(_chunk != NULL, "invariant");
       
   256   _chunk->set_last_checkpoint_offset(offset);
       
   257 }
       
   258 
       
   259 void JfrChunkWriter::set_last_metadata_offset(int64_t offset) {
       
   260   assert(_chunk != NULL, "invariant");
       
   261   _chunk->set_last_metadata_offset(offset);
       
   262 }
       
   263 
       
   264 bool JfrChunkWriter::has_metadata() const {
       
   265   assert(_chunk != NULL, "invariant");
       
   266   return _chunk->has_metadata();
       
   267 }
       
   268 
    54 bool JfrChunkWriter::open() {
   269 bool JfrChunkWriter::open() {
    55   assert(_chunkstate != NULL, "invariant");
   270   assert(_chunk != NULL, "invariant");
    56   JfrChunkWriterBase::reset(open_chunk(_chunkstate->path()));
   271   JfrChunkWriterBase::reset(open_chunk(_chunk->path()));
    57   const bool is_open = this->has_valid_fd();
   272   const bool is_open = this->has_valid_fd();
    58   if (is_open) {
   273   if (is_open) {
    59     this->bytes("FLR", MAGIC_LEN);
   274     assert(0 == this->current_offset(), "invariant");
    60     this->be_write((u2)JFR_VERSION_MAJOR);
   275     _chunk->reset();
    61     this->be_write((u2)JFR_VERSION_MINOR);
   276     JfrChunkHeadWriter head(this, HEADER_SIZE);
    62     this->reserve(6 * FILEHEADER_SLOT_SIZE);
       
    63     // u8 chunk_size
       
    64     // u8 initial checkpoint offset
       
    65     // u8 metadata section offset
       
    66     // u8 chunk start nanos
       
    67     // u8 chunk duration nanos
       
    68     // u8 chunk start ticks
       
    69     this->be_write(JfrTime::frequency());
       
    70     // chunk capabilities, CompressedIntegers etc
       
    71     this->be_write((u4)JfrOptionSet::compressed_integers() ? 1 : 0);
       
    72     _chunkstate->reset();
       
    73   }
   277   }
    74   return is_open;
   278   return is_open;
    75 }
   279 }
    76 
   280 
    77 size_t JfrChunkWriter::close(int64_t metadata_offset) {
   281 int64_t JfrChunkWriter::close() {
    78   write_header(metadata_offset);
   282   assert(this->has_valid_fd(), "invariant");
    79   this->flush();
   283   const int64_t size_written = flush_chunk(false);
    80   this->close_fd();
   284   this->close_fd();
    81   return (size_t)size_written();
   285   assert(!this->is_valid(), "invariant");
    82 }
   286   return size_written;
    83 
   287 }
    84 void JfrChunkWriter::write_header(int64_t metadata_offset) {
       
    85   assert(this->is_valid(), "invariant");
       
    86   // Chunk size
       
    87   this->write_be_at_offset(size_written(), CHUNK_SIZE_OFFSET);
       
    88   // initial checkpoint event offset
       
    89   this->write_be_at_offset(_chunkstate->last_checkpoint_offset(), CHUNK_SIZE_OFFSET + (1 * FILEHEADER_SLOT_SIZE));
       
    90   // metadata event offset
       
    91   this->write_be_at_offset(metadata_offset, CHUNK_SIZE_OFFSET + (2 * FILEHEADER_SLOT_SIZE));
       
    92   // start of chunk in nanos since epoch
       
    93   this->write_be_at_offset(_chunkstate->previous_start_nanos(), CHUNK_SIZE_OFFSET + (3 * FILEHEADER_SLOT_SIZE));
       
    94   // duration of chunk in nanos
       
    95   this->write_be_at_offset(_chunkstate->last_chunk_duration(), CHUNK_SIZE_OFFSET + (4 * FILEHEADER_SLOT_SIZE));
       
    96   // start of chunk in ticks
       
    97   this->write_be_at_offset(_chunkstate->previous_start_ticks(), CHUNK_SIZE_OFFSET + (5 * FILEHEADER_SLOT_SIZE));
       
    98 }
       
    99 
       
   100 void JfrChunkWriter::set_chunk_path(const char* chunk_path) {
       
   101   _chunkstate->set_path(chunk_path);
       
   102 }
       
   103 
       
   104 int64_t JfrChunkWriter::size_written() const {
       
   105   return this->is_valid() ? this->current_offset() : 0;
       
   106 }
       
   107 
       
   108 int64_t JfrChunkWriter::last_checkpoint_offset() const {
       
   109   return _chunkstate->last_checkpoint_offset();
       
   110 }
       
   111 
       
   112 void JfrChunkWriter::set_last_checkpoint_offset(int64_t offset) {
       
   113   _chunkstate->set_last_checkpoint_offset(offset);
       
   114 }
       
   115 
       
   116 void JfrChunkWriter::time_stamp_chunk_now() {
       
   117   _chunkstate->update_time_to_now();
       
   118 }