1 /*
   2  * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   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
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "jfr/jfrEvents.hpp"
  27 #include "jfr/recorder/jfrRecorder.hpp"
  28 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
  29 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
  30 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
  31 #include "jfr/leakprofiler/chains/edgeStore.hpp"
  32 #include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
  33 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
  34 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
  35 #include "jfr/leakprofiler/leakProfiler.hpp"
  36 #include "jfr/leakprofiler/sampling/objectSample.hpp"
  37 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
  38 #include "jfr/leakprofiler/utilities/rootType.hpp"
  39 #include "jfr/metadata/jfrSerializer.hpp"
  40 #include "runtime/interfaceSupport.hpp"
  41 #include "runtime/mutexLocker.hpp"
  42 #include "runtime/thread.inline.hpp"
  43 
  44 template <typename SampleProcessor>
  45 static void do_samples(ObjectSample* sample, const ObjectSample* const end, SampleProcessor& processor) {
  46   assert(sample != NULL, "invariant");
  47   while (sample != end) {
  48     processor.sample_do(sample);
  49     sample = sample->next();
  50   }
  51 }
  52 
  53 class RootSystemType : public JfrSerializer {
  54  public:
  55   void serialize(JfrCheckpointWriter& writer) {
  56     const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
  57     writer.write_count(nof_root_systems);
  58     for (u4 i = 0; i < nof_root_systems; ++i) {
  59       writer.write_key(i);
  60       writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
  61     }
  62   }
  63 };
  64 
  65 class RootType : public JfrSerializer {
  66  public:
  67   void serialize(JfrCheckpointWriter& writer) {
  68     const u4 nof_root_types = OldObjectRoot::_number_of_types;
  69     writer.write_count(nof_root_types);
  70     for (u4 i = 0; i < nof_root_types; ++i) {
  71       writer.write_key(i);
  72       writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
  73     }
  74   }
  75 };
  76 
  77 class CheckpointInstall {
  78  private:
  79   const JfrCheckpointBlobHandle& _cp;
  80  public:
  81   CheckpointInstall(const JfrCheckpointBlobHandle& cp) : _cp(cp) {}
  82   void sample_do(ObjectSample* sample) {
  83     assert(sample != NULL, "invariant");
  84     if (!sample->is_dead()) {
  85       sample->set_klass_checkpoint(_cp);
  86     }
  87   }
  88 };
  89 
  90 class CheckpointWrite {
  91  private:
  92   JfrCheckpointWriter& _writer;
  93   const jlong _last_sweep;
  94  public:
  95   CheckpointWrite(JfrCheckpointWriter& writer, jlong last_sweep) : _writer(writer), _last_sweep(last_sweep) {}
  96   void sample_do(ObjectSample* sample) {
  97     assert(sample != NULL, "invariant");
  98     if (sample->is_alive_and_older_than(_last_sweep)) {
  99       if (sample->has_thread_checkpoint()) {
 100         const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
 101         thread_cp->exclusive_write(_writer);
 102       }
 103       if (sample->has_klass_checkpoint()) {
 104         const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
 105         klass_cp->exclusive_write(_writer);
 106       }
 107     }
 108   }
 109 };
 110 
 111 class CheckpointStateReset {
 112  private:
 113   const jlong _last_sweep;
 114  public:
 115   CheckpointStateReset(jlong last_sweep) : _last_sweep(last_sweep) {}
 116   void sample_do(ObjectSample* sample) {
 117     assert(sample != NULL, "invariant");
 118     if (sample->is_alive_and_older_than(_last_sweep)) {
 119       if (sample->has_thread_checkpoint()) {
 120         const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
 121         thread_cp->reset_write_state();
 122       }
 123       if (sample->has_klass_checkpoint()) {
 124         const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
 125         klass_cp->reset_write_state();
 126       }
 127     }
 128   }
 129 };
 130 
 131 class StackTraceWrite {
 132  private:
 133   JfrStackTraceRepository& _stack_trace_repo;
 134   JfrCheckpointWriter& _writer;
 135   int _count;
 136  public:
 137   StackTraceWrite(JfrStackTraceRepository& stack_trace_repo, JfrCheckpointWriter& writer) :
 138     _stack_trace_repo(stack_trace_repo), _writer(writer), _count(0) {
 139     JfrStacktrace_lock->lock();
 140   }
 141   ~StackTraceWrite() {
 142     assert(JfrStacktrace_lock->owned_by_self(), "invariant");
 143     JfrStacktrace_lock->unlock();
 144   }
 145 
 146   void sample_do(ObjectSample* sample) {
 147     assert(sample != NULL, "invariant");
 148     if (!sample->is_dead()) {
 149       if (sample->has_stack_trace()) {
 150         JfrTraceId::use(sample->klass(), true);
 151         _stack_trace_repo.write(_writer, sample->stack_trace_id(), sample->stack_trace_hash());
 152         ++_count;
 153       }
 154     }
 155   }
 156 
 157   int count() const {
 158     return _count;
 159   }
 160 };
 161 
 162 class SampleMark {
 163  private:
 164   ObjectSampleMarker& _marker;
 165   jlong _last_sweep;
 166   int _count;
 167  public:
 168   SampleMark(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker),
 169                                                              _last_sweep(last_sweep),
 170                                                              _count(0) {}
 171   void sample_do(ObjectSample* sample) {
 172     assert(sample != NULL, "invariant");
 173     if (sample->is_alive_and_older_than(_last_sweep)) {
 174       _marker.mark(sample->object());
 175       ++_count;
 176     }
 177   }
 178 
 179   int count() const {
 180     return _count;
 181   }
 182 };
 183 
 184 void ObjectSampleCheckpoint::install(JfrCheckpointWriter& writer, bool class_unload, bool type_set) {
 185   if (!writer.has_data()) {
 186     return;
 187   }
 188 
 189   assert(writer.has_data(), "invariant");
 190   const JfrCheckpointBlobHandle h_cp = writer.checkpoint_blob();
 191   CheckpointInstall install(h_cp);
 192 
 193   // Class unload implies a safepoint.
 194   // Not class unload implies the object sampler is locked, because it was claimed exclusively earlier.
 195   // Therefore: direct access the object sampler instance is safe.
 196   ObjectSampler* const object_sampler = ObjectSampler::sampler();
 197   assert(object_sampler != NULL, "invariant");
 198 
 199   ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
 200   const ObjectSample* const last_resolved = object_sampler->last_resolved();
 201 
 202   // install only to new samples since last resolved checkpoint
 203   if (last != last_resolved) {
 204     do_samples(last, last_resolved, install);
 205     if (class_unload) {
 206       return;
 207     }
 208     if (type_set) {
 209       object_sampler->set_last_resolved(last);
 210     }
 211   }
 212 }
 213 
 214 void ObjectSampleCheckpoint::write(ObjectSampler* sampler, EdgeStore* edge_store, bool emit_all, Thread* thread) {
 215   assert(sampler != NULL, "invariant");
 216   assert(edge_store != NULL, "invariant");
 217   assert(thread != NULL, "invariant");
 218 
 219   static bool types_registered = false;
 220   if (!types_registered) {
 221     JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTSYSTEM, false, true, new RootSystemType());
 222     JfrSerializer::register_serializer(TYPE_OLDOBJECTROOTTYPE, false, true, new RootType());
 223     types_registered = true;
 224   }
 225 
 226   const jlong last_sweep = emit_all ? max_jlong : sampler->last_sweep().value();
 227   ObjectSample* const last = const_cast<ObjectSample*>(sampler->last());
 228   {
 229     JfrCheckpointWriter writer(false, false, thread);
 230     CheckpointWrite checkpoint_write(writer, last_sweep);
 231     do_samples(last, NULL, checkpoint_write);
 232   }
 233 
 234   CheckpointStateReset state_reset(last_sweep);
 235   do_samples(last, NULL, state_reset);
 236 
 237   if (!edge_store->is_empty()) {
 238     // java object and chain representations
 239     JfrCheckpointWriter writer(false, true, thread);
 240     ObjectSampleWriter osw(writer, edge_store);
 241     edge_store->iterate(osw);
 242   }
 243 }
 244 
 245 int ObjectSampleCheckpoint::mark(ObjectSampler* object_sampler, ObjectSampleMarker& marker, bool emit_all) {
 246   assert(object_sampler != NULL, "invariant");
 247   ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
 248   if (last == NULL) {
 249     return 0;
 250   }
 251   const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
 252   SampleMark mark(marker, last_sweep);
 253   do_samples(last, NULL, mark);
 254   return mark.count();
 255 }
 256 
 257 WriteObjectSampleStacktrace::WriteObjectSampleStacktrace(ObjectSampler* sampler, JfrStackTraceRepository& repo) :
 258   _sampler(sampler), _stack_trace_repo(repo) {}
 259 
 260 bool WriteObjectSampleStacktrace::process() {
 261   assert(LeakProfiler::is_running(), "invariant");
 262   assert(_sampler != NULL, "invariant");
 263 
 264   ObjectSample* const last = const_cast<ObjectSample*>(_sampler->last());
 265   const ObjectSample* const last_resolved = _sampler->last_resolved();
 266   if (last == last_resolved) {
 267     return true;
 268   }
 269 
 270   JfrCheckpointWriter writer(false, true, Thread::current());
 271   const JfrCheckpointContext ctx = writer.context();
 272 
 273   writer.write_type(TYPE_STACKTRACE);
 274   const jlong count_offset = writer.reserve(sizeof(u4));
 275 
 276   int count = 0;
 277   {
 278     StackTraceWrite stack_trace_write(_stack_trace_repo, writer); // JfrStacktrace_lock
 279     do_samples(last, last_resolved, stack_trace_write);
 280     count = stack_trace_write.count();
 281   }
 282   if (count == 0) {
 283     writer.set_context(ctx);
 284     return true;
 285   }
 286   assert(count > 0, "invariant");
 287   writer.write_count((u4)count, count_offset);
 288   JfrStackTraceRepository::write_metadata(writer);
 289 
 290   // install the stacktrace checkpoint information to the candidates
 291   ObjectSampleCheckpoint::install(writer, false, false);
 292   return true;
 293 }