src/hotspot/share/jfr/leakprofiler/checkpoint/objectSampleCheckpoint.cpp
branchJEP-349-branch
changeset 57997 8dea18a54031
parent 57993 dc5746ce3b92
child 58154 060d9d139109
equal deleted inserted replaced
57993:dc5746ce3b92 57997:8dea18a54031
   108 
   108 
   109 static void add_to_unloaded_klass_set(traceid klass_id) {
   109 static void add_to_unloaded_klass_set(traceid klass_id) {
   110   if (unloaded_klass_set == NULL) {
   110   if (unloaded_klass_set == NULL) {
   111     unloaded_klass_set = c_heap_allocate_array<traceid>();
   111     unloaded_klass_set = c_heap_allocate_array<traceid>();
   112   }
   112   }
   113   add(unloaded_klass_set, klass_id);
   113   unloaded_klass_set->append(klass_id);
       
   114 }
       
   115 
       
   116 static void sort_unloaded_klass_set() {
       
   117   if (unloaded_klass_set != NULL && unloaded_klass_set->length() > 1) {
       
   118     unloaded_klass_set->sort(sort_traceid);
       
   119   }
   114 }
   120 }
   115 
   121 
   116 void ObjectSampleCheckpoint::on_klass_unload(const Klass* k) {
   122 void ObjectSampleCheckpoint::on_klass_unload(const Klass* k) {
   117   assert(k != NULL, "invariant");
   123   assert(k != NULL, "invariant");
   118   add_to_unloaded_klass_set(TRACE_ID(k));
   124   add_to_unloaded_klass_set(TRACE_ID(k));
   210 
   216 
   211 inline void BlobCache::unlink(BlobEntry* entry) const {
   217 inline void BlobCache::unlink(BlobEntry* entry) const {
   212   assert(entry != NULL, "invariant");
   218   assert(entry != NULL, "invariant");
   213 }
   219 }
   214 
   220 
       
   221 static GrowableArray<traceid>* id_set = NULL;
       
   222 
       
   223 static void prepare_for_resolution() {
       
   224   id_set = new GrowableArray<traceid>(JfrOptionSet::old_object_queue_size());
       
   225   sort_unloaded_klass_set();
       
   226 }
       
   227 
   215 static bool stack_trace_precondition(const ObjectSample* sample) {
   228 static bool stack_trace_precondition(const ObjectSample* sample) {
   216   assert(sample != NULL, "invariant");
   229   assert(sample != NULL, "invariant");
   217   return sample->has_stack_trace_id() && !sample->is_dead();
   230   return sample->has_stack_trace_id() && !sample->is_dead();
   218 }
   231 }
   219 
   232 
   222   const JfrStackTraceRepository& _stack_trace_repo;
   235   const JfrStackTraceRepository& _stack_trace_repo;
   223   BlobCache _cache;
   236   BlobCache _cache;
   224   const JfrStackTrace* resolve(const ObjectSample* sample);
   237   const JfrStackTrace* resolve(const ObjectSample* sample);
   225   void install(ObjectSample* sample);
   238   void install(ObjectSample* sample);
   226  public:
   239  public:
   227   StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo) :
   240   StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo);
   228     _stack_trace_repo(stack_trace_repo),
       
   229     _cache(JfrOptionSet::old_object_queue_size()) {}
       
   230   void sample_do(ObjectSample* sample) {
   241   void sample_do(ObjectSample* sample) {
   231     if (stack_trace_precondition(sample)) {
   242     if (stack_trace_precondition(sample)) {
   232       install(sample);
   243       install(sample);
   233     }
   244     }
   234   }
   245   }
   235 };
   246 };
       
   247 
       
   248 StackTraceBlobInstaller::StackTraceBlobInstaller(const JfrStackTraceRepository& stack_trace_repo) :
       
   249   _stack_trace_repo(stack_trace_repo), _cache(JfrOptionSet::old_object_queue_size()) {
       
   250   prepare_for_resolution();
       
   251 }
   236 
   252 
   237 const JfrStackTrace* StackTraceBlobInstaller::resolve(const ObjectSample* sample) {
   253 const JfrStackTrace* StackTraceBlobInstaller::resolve(const ObjectSample* sample) {
   238   return _stack_trace_repo.lookup(sample->stack_trace_hash(), sample->stack_trace_id());
   254   return _stack_trace_repo.lookup(sample->stack_trace_hash(), sample->stack_trace_id());
   239 }
   255 }
   240 
   256 
   262   blob = writer.move();
   278   blob = writer.move();
   263   _cache.put(sample, blob);
   279   _cache.put(sample, blob);
   264   sample->set_stacktrace(blob);
   280   sample->set_stacktrace(blob);
   265 }
   281 }
   266 
   282 
   267 static GrowableArray<traceid>* id_set = NULL;
   283 static void install_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
   268 
       
   269 static void allocate_traceid_working_set() {
       
   270   id_set = new GrowableArray<traceid>(JfrOptionSet::old_object_queue_size());
       
   271 }
       
   272 
       
   273 static void resolve_stack_traces(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
       
   274   assert(sampler != NULL, "invariant");
   284   assert(sampler != NULL, "invariant");
   275   const ObjectSample* const last = sampler->last();
   285   const ObjectSample* const last = sampler->last();
   276   if (last != sampler->last_resolved()) {
   286   if (last != sampler->last_resolved()) {
   277     allocate_traceid_working_set();
       
   278     StackTraceBlobInstaller installer(stack_trace_repo);
   287     StackTraceBlobInstaller installer(stack_trace_repo);
   279     iterate_samples(installer);
   288     iterate_samples(installer);
   280   }
   289   }
   281 }
   290 }
   282 
   291 
   283 // caller needs ResourceMark
   292 // caller needs ResourceMark
   284 void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
   293 void ObjectSampleCheckpoint::on_rotation(const ObjectSampler* sampler, JfrStackTraceRepository& stack_trace_repo) {
   285   assert(sampler != NULL, "invariant");
   294   assert(sampler != NULL, "invariant");
   286   assert(LeakProfiler::is_running(), "invariant");
   295   assert(LeakProfiler::is_running(), "invariant");
   287   resolve_stack_traces(sampler, stack_trace_repo);
   296   install_stack_traces(sampler, stack_trace_repo);
   288 }
   297 }
   289 
   298 
   290 static traceid get_klass_id(traceid method_id) {
   299 static traceid get_klass_id(traceid method_id) {
   291   assert(method_id != 0, "invariant");
   300   assert(method_id != 0, "invariant");
   292   return method_id >> TRACE_ID_SHIFT;
   301   return method_id >> TRACE_ID_SHIFT;
   398     ObjectSampleWriter osw(writer, edge_store);
   407     ObjectSampleWriter osw(writer, edge_store);
   399     edge_store->iterate(osw);
   408     edge_store->iterate(osw);
   400   }
   409   }
   401 }
   410 }
   402 
   411 
   403 class BlobInstaller {
       
   404  private:
       
   405   const JfrBlobHandle& _blob;
       
   406  public:
       
   407   BlobInstaller(const JfrBlobHandle& blob) : _blob(blob) {}
       
   408   void sample_do(ObjectSample* sample) {
       
   409     if (!sample->is_dead()) {
       
   410       sample->set_type_set(_blob);
       
   411     }
       
   412   }
       
   413 };
       
   414 
       
   415 static void clear_unloaded_klass_set() {
   412 static void clear_unloaded_klass_set() {
   416   if (unloaded_klass_set != NULL && unloaded_klass_set->is_nonempty()) {
   413   if (unloaded_klass_set != NULL && unloaded_klass_set->is_nonempty()) {
   417     unloaded_klass_set->clear();
   414     unloaded_klass_set->clear();
   418   }
   415   }
   419 }
   416 }
   420 
   417 
   421 static void install_blob(JfrCheckpointWriter& writer, bool copy = false) {
   418 // A linked list of saved type set blobs for the epoch.
       
   419 // The link consist of a reference counted handle.
       
   420 static JfrBlobHandle saved_type_set_blobs;
       
   421 
       
   422 static void release_state_for_previous_epoch() {
       
   423   // decrements the reference count and the list is reinitialized
       
   424   saved_type_set_blobs = JfrBlobHandle();
       
   425   clear_unloaded_klass_set();
       
   426 }
       
   427 
       
   428 class BlobInstaller {
       
   429  public:
       
   430   ~BlobInstaller() {
       
   431     release_state_for_previous_epoch();
       
   432   }
       
   433   void sample_do(ObjectSample* sample) {
       
   434     if (!sample->is_dead()) {
       
   435       sample->set_type_set(saved_type_set_blobs);
       
   436     }
       
   437   }
       
   438 };
       
   439 
       
   440 static void install_type_set_blobs() {
       
   441   BlobInstaller installer;
       
   442   iterate_samples(installer);
       
   443 }
       
   444 
       
   445 static void save_type_set_blob(JfrCheckpointWriter& writer, bool copy = false) {
   422   assert(writer.has_data(), "invariant");
   446   assert(writer.has_data(), "invariant");
   423   const JfrBlobHandle blob = copy ? writer.copy() : writer.move();
   447   const JfrBlobHandle blob = copy ? writer.copy() : writer.move();
   424   BlobInstaller installer(blob);
   448   if (saved_type_set_blobs.valid()) {
   425   iterate_samples(installer);
   449     saved_type_set_blobs->set_next(blob);
       
   450   } else {
       
   451     saved_type_set_blobs = blob;
       
   452   }
   426 }
   453 }
   427 
   454 
   428 void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
   455 void ObjectSampleCheckpoint::on_type_set(JfrCheckpointWriter& writer) {
   429   assert(LeakProfiler::is_running(), "invariant");
   456   assert(LeakProfiler::is_running(), "invariant");
   430   const ObjectSample* last = ObjectSampler::sampler()->last();
   457   const ObjectSample* last = ObjectSampler::sampler()->last();
   431   if (writer.has_data() && last != NULL) {
   458   if (writer.has_data() && last != NULL) {
   432     install_blob(writer);
   459     save_type_set_blob(writer);
       
   460     install_type_set_blobs();
   433     ObjectSampler::sampler()->set_last_resolved(last);
   461     ObjectSampler::sampler()->set_last_resolved(last);
   434   }
   462   }
   435   // Only happens post chunk rotation and we would not have hit another class unload safepoint.
       
   436   // Therefore it is safe to release the set of unloaded classes tracked during the previous epoch.
       
   437   clear_unloaded_klass_set();
       
   438 }
   463 }
   439 
   464 
   440 void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
   465 void ObjectSampleCheckpoint::on_type_set_unload(JfrCheckpointWriter& writer) {
   441   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   466   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
   442   assert(LeakProfiler::is_running(), "invariant");
   467   assert(LeakProfiler::is_running(), "invariant");
   443   if (writer.has_data() && ObjectSampler::sampler()->last() != NULL) {
   468   if (writer.has_data() && ObjectSampler::sampler()->last() != NULL) {
   444     install_blob(writer, true);
   469     save_type_set_blob(writer, true);
   445   }
   470   }
   446 }
   471 }