src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 50714 2230bb152a9f
child 57872 7aa1b3d6ff8f
equal deleted inserted replaced
57359:4cab5edc2950 57360:5d043a159d5c
     1 /*
     1 /*
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    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");