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/recorder/jfrRecorder.hpp"
  27 #include "jfr/recorder/checkpoint/constant/traceid/jfrTraceId.inline.hpp"
  28 #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp"
  29 #include "jfr/recorder/stacktrace/jfrStackTraceRepository.hpp"
  30 #include "jfr/leakprofiler/chains/edgeStore.hpp"
  31 #include "jfr/leakprofiler/chains/objectSampleMarker.hpp"
  32 #include "jfr/leakprofiler/checkpoint/objectSampleCheckpoint.hpp"
  33 #include "jfr/leakprofiler/checkpoint/objectSampleWriter.hpp"
  34 #include "jfr/leakprofiler/leakProfiler.hpp"
  35 #include "jfr/leakprofiler/sampling/objectSample.hpp"
  36 #include "jfr/leakprofiler/sampling/objectSampler.hpp"
  37 #include "jfr/leakprofiler/utilities/rootType.hpp"
  38 #include "jfr/metadata/jfrConstantSerializer.hpp"
  39 #include "runtime/interfaceSupport.inline.hpp"
  40 #include "runtime/mutexLocker.hpp"
  41 #include "runtime/thread.inline.hpp"
  42 // to get CONTENT_TYPE defines
  43 #include "tracefiles/traceTypes.hpp"
  44 
  45 template <typename SampleProcessor>
  46 static void do_samples(ObjectSample* sample, const ObjectSample* const end, SampleProcessor& processor) {
  47   assert(sample != NULL, "invariant");
  48   while (sample != end) {
  49     processor.sample_do(sample);
  50     sample = sample->next();
  51   }
  52 }
  53 
  54 class ConstantTypeRootSystem : public JfrConstantSerializer {
  55  public:
  56   void write_constants(JfrCheckpointWriter& writer) {
  57     const u4 nof_root_systems = OldObjectRoot::_number_of_systems;
  58     writer.write_number_of_constants(nof_root_systems);
  59     for (u4 i = 0; i < nof_root_systems; ++i) {
  60       writer.write_key(i);
  61       writer.write(OldObjectRoot::system_description((OldObjectRoot::System)i));
  62     }
  63   }
  64 };
  65 
  66 class ConstantRootType : public JfrConstantSerializer {
  67  public:
  68   void write_constants(JfrCheckpointWriter& writer) {
  69     const u4 nof_root_types = OldObjectRoot::_number_of_types;
  70     writer.write_number_of_constants(nof_root_types);
  71     for (u4 i = 0; i < nof_root_types; ++i) {
  72       writer.write_key(i);
  73       writer.write(OldObjectRoot::type_description((OldObjectRoot::Type)i));
  74     }
  75   }
  76 };
  77 
  78 class CheckpointInstall {
  79  private:
  80   const JfrCheckpointBlobHandle& _cp;
  81  public:
  82   CheckpointInstall(const JfrCheckpointBlobHandle& cp) : _cp(cp) {}
  83   void sample_do(ObjectSample* sample) {
  84     assert(sample != NULL, "invariant");
  85     if (!sample->is_dead()) {
  86       sample->set_klass_checkpoint(_cp);
  87     }
  88   }
  89 };
  90 
  91 class CheckpointWrite {
  92  private:
  93   JfrCheckpointWriter& _writer;
  94   const jlong _last_sweep;
  95  public:
  96   CheckpointWrite(JfrCheckpointWriter& writer, jlong last_sweep) : _writer(writer), _last_sweep(last_sweep) {}
  97   void sample_do(ObjectSample* sample) {
  98     assert(sample != NULL, "invariant");
  99     if (sample->is_alive_and_older_than(_last_sweep)) {
 100       if (sample->has_thread_checkpoint()) {
 101         const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
 102         thread_cp->exclusive_write(_writer);
 103       }
 104       if (sample->has_klass_checkpoint()) {
 105         const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
 106         klass_cp->exclusive_write(_writer);
 107       }
 108     }
 109   }
 110 };
 111 
 112 class CheckpointStateReset {
 113  private:
 114   const jlong _last_sweep;
 115  public:
 116   CheckpointStateReset(jlong last_sweep) : _last_sweep(last_sweep) {}
 117   void sample_do(ObjectSample* sample) {
 118     assert(sample != NULL, "invariant");
 119     if (sample->is_alive_and_older_than(_last_sweep)) {
 120       if (sample->has_thread_checkpoint()) {
 121         const JfrCheckpointBlobHandle& thread_cp = sample->thread_checkpoint();
 122         thread_cp->reset_write_state();
 123       }
 124       if (sample->has_klass_checkpoint()) {
 125         const JfrCheckpointBlobHandle& klass_cp = sample->klass_checkpoint();
 126         klass_cp->reset_write_state();
 127       }
 128     }
 129   }
 130 };
 131 
 132 class StackTraceWrite {
 133  private:
 134   JfrStackTraceRepository& _stack_trace_repo;
 135   JfrCheckpointWriter& _writer;
 136   int _count;
 137  public:
 138   StackTraceWrite(JfrStackTraceRepository& stack_trace_repo, JfrCheckpointWriter& writer) :
 139     _stack_trace_repo(stack_trace_repo), _writer(writer), _count(0) {
 140     JfrStacktrace_lock->lock();
 141   }
 142   ~StackTraceWrite() {
 143     assert(JfrStacktrace_lock->owned_by_self(), "invariant");
 144     JfrStacktrace_lock->unlock();
 145   }
 146 
 147   void sample_do(ObjectSample* sample) {
 148     assert(sample != NULL, "invariant");
 149     if (!sample->is_dead()) {
 150       if (sample->has_stack_trace()) {
 151         JfrTraceId::use(sample->klass(), true);
 152         _stack_trace_repo.write(_writer, sample->stack_trace_id(), sample->stack_trace_hash());
 153         ++_count;
 154       }
 155     }
 156   }
 157 
 158   int count() const {
 159     return _count;
 160   }
 161 };
 162 
 163 class SampleMark {
 164  private:
 165   ObjectSampleMarker& _marker;
 166   jlong _last_sweep;
 167   int _count;
 168  public:
 169   SampleMark(ObjectSampleMarker& marker, jlong last_sweep) : _marker(marker),
 170                                                              _last_sweep(last_sweep),
 171                                                              _count(0) {}
 172   void sample_do(ObjectSample* sample) {
 173     assert(sample != NULL, "invariant");
 174     if (sample->is_alive_and_older_than(_last_sweep)) {
 175       _marker.mark(sample->object());
 176       ++_count;
 177     }
 178   }
 179 
 180   int count() const {
 181     return _count;
 182   }
 183 };
 184 
 185 void ObjectSampleCheckpoint::install(JfrCheckpointWriter& writer, bool class_unload, bool resume) {
 186   assert(class_unload ? SafepointSynchronize::is_at_safepoint() : LeakProfiler::is_suspended(), "invariant");
 187 
 188   if (!writer.has_data()) {
 189     if (!class_unload) {
 190       LeakProfiler::resume();
 191     }
 192     assert(LeakProfiler::is_running(), "invariant");
 193     return;
 194   }
 195 
 196   assert(writer.has_data(), "invariant");
 197   const JfrCheckpointBlobHandle h_cp = writer.checkpoint_blob();
 198 
 199   const ObjectSampler* const object_sampler = LeakProfiler::object_sampler();
 200   assert(object_sampler != NULL, "invariant");
 201 
 202   ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
 203   const ObjectSample* const last_resolved = object_sampler->last_resolved();
 204   CheckpointInstall install(h_cp);
 205 
 206   if (class_unload) {
 207     if (last != NULL) {
 208       // all samples need the class unload information
 209       do_samples(last, NULL, install);
 210     }
 211     assert(LeakProfiler::is_running(), "invariant");
 212     return;
 213   }
 214 
 215   // only new samples since last resolved checkpoint
 216   if (last != last_resolved) {
 217     do_samples(last, last_resolved, install);
 218     if (resume) {
 219       const_cast<ObjectSampler*>(object_sampler)->set_last_resolved(last);
 220     }
 221   }
 222   assert(LeakProfiler::is_suspended(), "invariant");
 223   if (resume) {
 224     LeakProfiler::resume();
 225     assert(LeakProfiler::is_running(), "invariant");
 226   }
 227 }
 228 
 229 void ObjectSampleCheckpoint::write(const EdgeStore* edge_store, bool emit_all, Thread* thread) {
 230   assert(edge_store != NULL, "invariant");
 231   assert(thread != NULL, "invariant");
 232   static bool constant_types_registered = false;
 233   if (!constant_types_registered) {
 234     JfrConstantSerializer::register_serializer(CONSTANT_TYPE_OLDOBJECTROOTSYSTEM, false, true, new ConstantTypeRootSystem());
 235     JfrConstantSerializer::register_serializer(CONSTANT_TYPE_OLDOBJECTROOTTYPE, false, true, new ConstantRootType());
 236     constant_types_registered = true;
 237   }
 238   const ObjectSampler* const object_sampler = LeakProfiler::object_sampler();
 239   assert(object_sampler != NULL, "invariant");
 240   const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
 241   ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
 242   {
 243     JfrCheckpointWriter writer(false, false, thread);
 244     CheckpointWrite checkpoint_write(writer, last_sweep);
 245     do_samples(last, NULL, checkpoint_write);
 246   }
 247   CheckpointStateReset state_reset(last_sweep);
 248   do_samples(last, NULL, state_reset);
 249   if (!edge_store->is_empty()) {
 250     // java object and chain representations
 251     JfrCheckpointWriter writer(false, true, thread);
 252     ObjectSampleWriter osw(writer, edge_store);
 253     edge_store->iterate_edges(osw);
 254   }
 255 }
 256 
 257 WriteObjectSampleStacktrace::WriteObjectSampleStacktrace(JfrStackTraceRepository& repo) :
 258   _stack_trace_repo(repo) {
 259 }
 260 
 261 bool WriteObjectSampleStacktrace::process() {
 262   assert(SafepointSynchronize::is_at_safepoint(), "invariant");
 263   if (!LeakProfiler::is_running()) {
 264     return true;
 265   }
 266   // Suspend the LeakProfiler subsystem
 267   // to ensure stable samples even
 268   // after we return from the safepoint.
 269   LeakProfiler::suspend();
 270   assert(!LeakProfiler::is_running(), "invariant");
 271   assert(LeakProfiler::is_suspended(), "invariant");
 272 
 273   const ObjectSampler* object_sampler = LeakProfiler::object_sampler();
 274   assert(object_sampler != NULL, "invariant");
 275   assert(LeakProfiler::is_suspended(), "invariant");
 276 
 277   ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
 278   const ObjectSample* const last_resolved = object_sampler->last_resolved();
 279   if (last == last_resolved) {
 280     assert(LeakProfiler::is_suspended(), "invariant");
 281     return true;
 282   }
 283 
 284   JfrCheckpointWriter writer(false, true, Thread::current());
 285   const JfrCheckpointContext ctx = writer.context();
 286 
 287   writer.write_constant_type(CONSTANT_TYPE_STACKTRACE);
 288   const jlong count_offset = writer.reserve(sizeof(u4));
 289 
 290   int count = 0;
 291   {
 292     StackTraceWrite stack_trace_write(_stack_trace_repo, writer); // JfrStacktrace_lock
 293     do_samples(last, last_resolved, stack_trace_write);
 294     count = stack_trace_write.count();
 295   }
 296   if (count == 0) {
 297     writer.set_context(ctx);
 298     assert(LeakProfiler::is_suspended(), "invariant");
 299     return true;
 300   }
 301   assert(count > 0, "invariant");
 302   writer.write_number_of_constants((u4)count, count_offset);
 303   JfrStackTraceRepository::write_metadata(writer);
 304 
 305   ObjectSampleCheckpoint::install(writer, false, false);
 306   assert(LeakProfiler::is_suspended(), "invariant");
 307   return true;
 308 }
 309 
 310 int ObjectSampleCheckpoint::mark(ObjectSampleMarker& marker, bool emit_all) {
 311   const ObjectSampler* object_sampler = LeakProfiler::object_sampler();
 312   assert(object_sampler != NULL, "invariant");
 313   ObjectSample* const last = const_cast<ObjectSample*>(object_sampler->last());
 314   if (last == NULL) {
 315     return 0;
 316   }
 317   const jlong last_sweep = emit_all ? max_jlong : object_sampler->last_sweep().value();
 318   SampleMark mark(marker, last_sweep);
 319   do_samples(last, NULL, mark);
 320   return mark.count();
 321 }