31 #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" |
31 #include "jfr/recorder/storage/jfrStorageUtils.inline.hpp" |
32 #include "jfr/recorder/stringpool/jfrStringPool.hpp" |
32 #include "jfr/recorder/stringpool/jfrStringPool.hpp" |
33 #include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp" |
33 #include "jfr/recorder/stringpool/jfrStringPoolWriter.hpp" |
34 #include "jfr/utilities/jfrTypes.hpp" |
34 #include "jfr/utilities/jfrTypes.hpp" |
35 #include "logging/log.hpp" |
35 #include "logging/log.hpp" |
36 #include "runtime/atomic.hpp" |
|
37 #include "runtime/mutexLocker.hpp" |
36 #include "runtime/mutexLocker.hpp" |
38 #include "runtime/orderAccess.hpp" |
37 #include "runtime/orderAccess.hpp" |
39 #include "runtime/safepoint.hpp" |
38 #include "runtime/safepoint.hpp" |
40 #include "runtime/thread.inline.hpp" |
39 #include "runtime/thread.inline.hpp" |
41 |
40 |
42 typedef JfrStringPool::Buffer* BufferPtr; |
41 typedef JfrStringPool::Buffer* BufferPtr; |
43 |
42 |
44 static JfrStringPool* _instance = NULL; |
43 static JfrStringPool* _instance = NULL; |
45 |
44 static uint64_t store_generation = 0; |
|
45 static uint64_t serialized_generation = 0; |
|
46 |
|
47 inline void set_value(uint64_t value, uint64_t* const dest) { |
|
48 assert(dest != NULL, "invariant"); |
|
49 const uint64_t current = OrderAccess::load_acquire(dest); |
|
50 if (value != current) { |
|
51 OrderAccess::release_store(dest, value); |
|
52 } |
|
53 } |
|
54 static void inc_store_generation() { |
|
55 set_value(OrderAccess::load_acquire(&serialized_generation) + 1, &store_generation); |
|
56 } |
|
57 static void set_serialized_generation() { |
|
58 set_value(OrderAccess::load_acquire(&store_generation), &serialized_generation); |
|
59 } |
|
60 bool JfrStringPool::modified() { |
|
61 return serialized_generation != OrderAccess::load_acquire(&store_generation); |
|
62 } |
46 JfrStringPool& JfrStringPool::instance() { |
63 JfrStringPool& JfrStringPool::instance() { |
47 return *_instance; |
64 return *_instance; |
48 } |
65 } |
49 |
66 |
50 JfrStringPool* JfrStringPool::create(JfrChunkWriter& cw) { |
67 JfrStringPool* JfrStringPool::create(JfrChunkWriter& cw) { |
|
68 store_generation = 0; |
|
69 serialized_generation = 0; |
51 assert(_instance == NULL, "invariant"); |
70 assert(_instance == NULL, "invariant"); |
52 _instance = new JfrStringPool(cw); |
71 _instance = new JfrStringPool(cw); |
53 return _instance; |
72 return _instance; |
54 } |
73 } |
55 |
74 |
134 if (current_epoch == epoch) { |
153 if (current_epoch == epoch) { |
135 JfrStringPoolWriter writer(jt); |
154 JfrStringPoolWriter writer(jt); |
136 writer.write(id); |
155 writer.write(id); |
137 writer.write(string); |
156 writer.write(string); |
138 writer.inc_nof_strings(); |
157 writer.inc_nof_strings(); |
|
158 inc_store_generation(); |
139 } |
159 } |
140 return current_epoch; |
160 return current_epoch; |
141 } |
161 } |
142 |
162 |
143 class StringPoolWriteOp { |
163 template <template <typename> class Operation> |
|
164 class StringPoolOp { |
144 public: |
165 public: |
145 typedef JfrStringPoolBuffer Type; |
166 typedef JfrStringPoolBuffer Type; |
146 private: |
167 private: |
147 UnBufferedWriteToChunk<Type> _writer; |
168 Operation<Type> _op; |
148 Thread* _thread; |
169 Thread* _thread; |
149 size_t _strings_processed; |
170 size_t _strings_processed; |
150 public: |
171 public: |
151 StringPoolWriteOp(JfrChunkWriter& writer, Thread* thread) : _writer(writer), _thread(thread), _strings_processed(0) {} |
172 StringPoolOp() : _op(), _thread(Thread::current()), _strings_processed(0) {} |
|
173 StringPoolOp(JfrChunkWriter& writer, Thread* thread) : _op(writer), _thread(thread), _strings_processed(0) {} |
152 bool write(Type* buffer, const u1* data, size_t size) { |
174 bool write(Type* buffer, const u1* data, size_t size) { |
153 buffer->acquire(_thread); // blocking |
175 assert(buffer->acquired_by(_thread) || buffer->retired(), "invariant"); |
154 const uint64_t nof_strings_used = buffer->string_count(); |
176 const uint64_t nof_strings_used = buffer->string_count(); |
155 assert(nof_strings_used > 0, "invariant"); |
177 assert(nof_strings_used > 0, "invariant"); |
156 buffer->set_string_top(buffer->string_top() + nof_strings_used); |
178 buffer->set_string_top(buffer->string_top() + nof_strings_used); |
157 // "size processed" for string pool buffers is the number of processed string elements |
179 // "size processed" for string pool buffers is the number of processed string elements |
158 _strings_processed += nof_strings_used; |
180 _strings_processed += nof_strings_used; |
159 const bool ret = _writer.write(buffer, data, size); |
181 return _op.write(buffer, data, size); |
160 buffer->release(); |
|
161 return ret; |
|
162 } |
182 } |
163 size_t processed() { return _strings_processed; } |
183 size_t processed() { return _strings_processed; } |
164 }; |
184 }; |
165 |
185 |
166 typedef StringPoolWriteOp WriteOperation; |
186 template <typename Type> |
167 typedef ConcurrentWriteOp<WriteOperation> ConcurrentWriteOperation; |
187 class StringPoolDiscarderStub { |
|
188 public: |
|
189 bool write(Type* buffer, const u1* data, size_t size) { |
|
190 // stub only, discard happens at higher level |
|
191 return true; |
|
192 } |
|
193 }; |
|
194 |
|
195 typedef StringPoolOp<UnBufferedWriteToChunk> WriteOperation; |
|
196 typedef StringPoolOp<StringPoolDiscarderStub> DiscardOperation; |
|
197 typedef ExclusiveOp<WriteOperation> ExclusiveWriteOperation; |
|
198 typedef ExclusiveOp<DiscardOperation> ExclusiveDiscardOperation; |
|
199 typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation; |
|
200 typedef CompositeOperation<ExclusiveWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation; |
|
201 typedef CompositeOperation<ExclusiveDiscardOperation, StringPoolReleaseOperation> StringPoolDiscardOperation; |
168 |
202 |
169 size_t JfrStringPool::write() { |
203 size_t JfrStringPool::write() { |
|
204 set_serialized_generation(); |
170 Thread* const thread = Thread::current(); |
205 Thread* const thread = Thread::current(); |
171 WriteOperation wo(_chunkwriter, thread); |
206 WriteOperation wo(_chunkwriter, thread); |
172 ConcurrentWriteOperation cwo(wo); |
207 ExclusiveWriteOperation ewo(wo); |
173 assert(_free_list_mspace->is_full_empty(), "invariant"); |
|
174 process_free_list(cwo, _free_list_mspace); |
|
175 return wo.processed(); |
|
176 } |
|
177 |
|
178 typedef MutexedWriteOp<WriteOperation> MutexedWriteOperation; |
|
179 typedef ReleaseOp<JfrStringPoolMspace> StringPoolReleaseOperation; |
|
180 typedef CompositeOperation<MutexedWriteOperation, StringPoolReleaseOperation> StringPoolWriteOperation; |
|
181 |
|
182 size_t JfrStringPool::write_at_safepoint() { |
|
183 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
|
184 Thread* const thread = Thread::current(); |
|
185 WriteOperation wo(_chunkwriter, thread); |
|
186 MutexedWriteOperation mwo(wo); |
|
187 StringPoolReleaseOperation spro(_free_list_mspace, thread, false); |
208 StringPoolReleaseOperation spro(_free_list_mspace, thread, false); |
188 StringPoolWriteOperation spwo(&mwo, &spro); |
209 StringPoolWriteOperation spwo(&ewo, &spro); |
189 assert(_free_list_mspace->is_full_empty(), "invariant"); |
210 assert(_free_list_mspace->is_full_empty(), "invariant"); |
190 process_free_list(spwo, _free_list_mspace); |
211 process_free_list(spwo, _free_list_mspace); |
191 return wo.processed(); |
212 return wo.processed(); |
192 } |
213 } |
193 |
214 |
194 class StringPoolBufferDiscarder { |
215 size_t JfrStringPool::write_at_safepoint() { |
195 private: |
216 assert(SafepointSynchronize::is_at_safepoint(), "invariant"); |
196 Thread* _thread; |
217 return write(); |
197 size_t _processed; |
218 } |
198 public: |
|
199 typedef JfrStringPoolBuffer Type; |
|
200 StringPoolBufferDiscarder() : _thread(Thread::current()), _processed(0) {} |
|
201 bool process(Type* buffer) { |
|
202 buffer->acquire(_thread); // serialized access |
|
203 const u1* const current_top = buffer->top(); |
|
204 const size_t unflushed_size = buffer->pos() - current_top; |
|
205 if (unflushed_size == 0) { |
|
206 assert(buffer->string_count() == 0, "invariant"); |
|
207 buffer->release(); |
|
208 return true; |
|
209 } |
|
210 buffer->set_top(current_top + unflushed_size); |
|
211 const uint64_t nof_strings_used = buffer->string_count(); |
|
212 buffer->set_string_top(buffer->string_top() + nof_strings_used); |
|
213 // "size processed" for string pool buffers is the number of string elements |
|
214 _processed += (size_t)nof_strings_used; |
|
215 buffer->release(); |
|
216 return true; |
|
217 } |
|
218 size_t processed() const { return _processed; } |
|
219 }; |
|
220 |
219 |
221 size_t JfrStringPool::clear() { |
220 size_t JfrStringPool::clear() { |
222 StringPoolBufferDiscarder discard_operation; |
221 set_serialized_generation(); |
|
222 DiscardOperation discard_operation; |
|
223 ExclusiveDiscardOperation edo(discard_operation); |
|
224 StringPoolReleaseOperation spro(_free_list_mspace, Thread::current(), false); |
|
225 StringPoolDiscardOperation spdo(&edo, &spro); |
223 assert(_free_list_mspace->is_full_empty(), "invariant"); |
226 assert(_free_list_mspace->is_full_empty(), "invariant"); |
224 process_free_list(discard_operation, _free_list_mspace); |
227 process_free_list(spdo, _free_list_mspace); |
225 return discard_operation.processed(); |
228 return discard_operation.processed(); |
226 } |
229 } |
227 |
230 |
228 void JfrStringPool::register_full(BufferPtr t, Thread* thread) { |
231 void JfrStringPool::register_full(BufferPtr t, Thread* thread) { |
229 // nothing here at the moment |
232 // nothing here at the moment |
|
233 assert(t != NULL, "invariant"); |
|
234 assert(t->acquired_by(thread), "invariant"); |
230 assert(t->retired(), "invariant"); |
235 assert(t->retired(), "invariant"); |
231 } |
236 } |
232 |
237 |
233 void JfrStringPool::lock() { |
238 void JfrStringPool::lock() { |
234 assert(!_lock->owned_by_self(), "invariant"); |
239 assert(!_lock->owned_by_self(), "invariant"); |