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