src/share/vm/services/heapDumper.cpp

changeset 1063
7bb995fbd3c0
parent 1014
0fbdb4381b99
parent 1050
c6c601a0f2d6
child 1481
72a6752ac432
     1.1 --- a/src/share/vm/services/heapDumper.cpp	Mon Mar 09 13:34:00 2009 -0700
     1.2 +++ b/src/share/vm/services/heapDumper.cpp	Thu Mar 12 18:16:36 2009 -0700
     1.3 @@ -347,7 +347,6 @@
     1.4    INITIAL_CLASS_COUNT = 200
     1.5  };
     1.6  
     1.7 -
     1.8  // Supports I/O operations on a dump file
     1.9  
    1.10  class DumpWriter : public StackObj {
    1.11 @@ -1303,7 +1302,9 @@
    1.12  // The VM operation that performs the heap dump
    1.13  class VM_HeapDumper : public VM_GC_Operation {
    1.14   private:
    1.15 -  DumpWriter* _writer;
    1.16 +  static VM_HeapDumper* _global_dumper;
    1.17 +  static DumpWriter*    _global_writer;
    1.18 +  DumpWriter*           _local_writer;
    1.19    bool _gc_before_heap_dump;
    1.20    bool _is_segmented_dump;
    1.21    jlong _dump_start;
    1.22 @@ -1311,8 +1312,20 @@
    1.23    ThreadStackTrace** _stack_traces;
    1.24    int _num_threads;
    1.25  
    1.26 -  // accessors
    1.27 -  DumpWriter* writer() const                    { return _writer; }
    1.28 +  // accessors and setters
    1.29 +  static VM_HeapDumper* dumper()         {  assert(_global_dumper != NULL, "Error"); return _global_dumper; }
    1.30 +  static DumpWriter* writer()            {  assert(_global_writer != NULL, "Error"); return _global_writer; }
    1.31 +  void set_global_dumper() {
    1.32 +    assert(_global_dumper == NULL, "Error");
    1.33 +    _global_dumper = this;
    1.34 +  }
    1.35 +  void set_global_writer() {
    1.36 +    assert(_global_writer == NULL, "Error");
    1.37 +    _global_writer = _local_writer;
    1.38 +  }
    1.39 +  void clear_global_dumper() { _global_dumper = NULL; }
    1.40 +  void clear_global_writer() { _global_writer = NULL; }
    1.41 +
    1.42    bool is_segmented_dump() const                { return _is_segmented_dump; }
    1.43    void set_segmented_dump()                     { _is_segmented_dump = true; }
    1.44    jlong dump_start() const                      { return _dump_start; }
    1.45 @@ -1357,7 +1370,7 @@
    1.46      VM_GC_Operation(0 /* total collections,      dummy, ignored */,
    1.47                      0 /* total full collections, dummy, ignored */,
    1.48                      gc_before_heap_dump) {
    1.49 -    _writer = writer;
    1.50 +    _local_writer = writer;
    1.51      _gc_before_heap_dump = gc_before_heap_dump;
    1.52      _is_segmented_dump = false;
    1.53      _dump_start = (jlong)-1;
    1.54 @@ -1381,6 +1394,9 @@
    1.55    void doit();
    1.56  };
    1.57  
    1.58 +VM_HeapDumper* VM_HeapDumper::_global_dumper = NULL;
    1.59 +DumpWriter*    VM_HeapDumper::_global_writer = NULL;
    1.60 +
    1.61  bool VM_HeapDumper::skip_operation() const {
    1.62    return false;
    1.63  }
    1.64 @@ -1479,31 +1495,28 @@
    1.65  void VM_HeapDumper::do_load_class(klassOop k) {
    1.66    static u4 class_serial_num = 0;
    1.67  
    1.68 -  VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
    1.69 -  DumpWriter* writer = dumper->writer();
    1.70 -
    1.71    // len of HPROF_LOAD_CLASS record
    1.72    u4 remaining = 2*oopSize + 2*sizeof(u4);
    1.73  
    1.74    // write a HPROF_LOAD_CLASS for the class and each array class
    1.75    do {
    1.76 -    DumperSupport::write_header(writer, HPROF_LOAD_CLASS, remaining);
    1.77 +    DumperSupport::write_header(writer(), HPROF_LOAD_CLASS, remaining);
    1.78  
    1.79      // class serial number is just a number
    1.80 -    writer->write_u4(++class_serial_num);
    1.81 +    writer()->write_u4(++class_serial_num);
    1.82  
    1.83      // class ID
    1.84      Klass* klass = Klass::cast(k);
    1.85 -    writer->write_classID(klass);
    1.86 +    writer()->write_classID(klass);
    1.87  
    1.88      // add the klassOop and class serial number pair
    1.89 -    dumper->add_class_serial_number(klass, class_serial_num);
    1.90 +    dumper()->add_class_serial_number(klass, class_serial_num);
    1.91  
    1.92 -    writer->write_u4(STACK_TRACE_ID);
    1.93 +    writer()->write_u4(STACK_TRACE_ID);
    1.94  
    1.95      // class name ID
    1.96      symbolOop name = klass->name();
    1.97 -    writer->write_objectID(name);
    1.98 +    writer()->write_objectID(name);
    1.99  
   1.100      // write a LOAD_CLASS record for the array type (if it exists)
   1.101      k = klass->array_klass_or_null();
   1.102 @@ -1512,17 +1525,13 @@
   1.103  
   1.104  // writes a HPROF_GC_CLASS_DUMP record for the given class
   1.105  void VM_HeapDumper::do_class_dump(klassOop k) {
   1.106 -  VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
   1.107 -  DumpWriter* writer = dumper->writer();
   1.108 -  DumperSupport::dump_class_and_array_classes(writer, k);
   1.109 +  DumperSupport::dump_class_and_array_classes(writer(), k);
   1.110  }
   1.111  
   1.112  // writes a HPROF_GC_CLASS_DUMP records for a given basic type
   1.113  // array (and each multi-dimensional array too)
   1.114  void VM_HeapDumper::do_basic_type_array_class_dump(klassOop k) {
   1.115 -  VM_HeapDumper* dumper = ((VM_HeapDumper*)VMThread::vm_operation());
   1.116 -  DumpWriter* writer = dumper->writer();
   1.117 -  DumperSupport::dump_basic_type_array_class(writer, k);
   1.118 +  DumperSupport::dump_basic_type_array_class(writer(), k);
   1.119  }
   1.120  
   1.121  // Walk the stack of the given thread.
   1.122 @@ -1658,6 +1667,11 @@
   1.123      ch->ensure_parsability(false);
   1.124    }
   1.125  
   1.126 +  // At this point we should be the only dumper active, so
   1.127 +  // the following should be safe.
   1.128 +  set_global_dumper();
   1.129 +  set_global_writer();
   1.130 +
   1.131    // Write the file header - use 1.0.2 for large heaps, otherwise 1.0.1
   1.132    size_t used = ch->used();
   1.133    const char* header;
   1.134 @@ -1667,6 +1681,7 @@
   1.135    } else {
   1.136      header = "JAVA PROFILE 1.0.1";
   1.137    }
   1.138 +
   1.139    // header is few bytes long - no chance to overflow int
   1.140    writer()->write_raw((void*)header, (int)strlen(header));
   1.141    writer()->write_u1(0); // terminator
   1.142 @@ -1723,6 +1738,10 @@
   1.143    // fixes up the length of the dump record. In the case of a segmented
   1.144    // heap then the HPROF_HEAP_DUMP_END record is also written.
   1.145    end_of_dump();
   1.146 +
   1.147 +  // Now we clear the global variables, so that a future dumper might run.
   1.148 +  clear_global_dumper();
   1.149 +  clear_global_writer();
   1.150  }
   1.151  
   1.152  void VM_HeapDumper::dump_stack_traces() {
   1.153 @@ -1790,7 +1809,12 @@
   1.154  
   1.155    // generate the dump
   1.156    VM_HeapDumper dumper(&writer, _gc_before_heap_dump);
   1.157 -  VMThread::execute(&dumper);
   1.158 +  if (Thread::current()->is_VM_thread()) {
   1.159 +    assert(SafepointSynchronize::is_at_safepoint(), "Expected to be called at a safepoint");
   1.160 +    dumper.doit();
   1.161 +  } else {
   1.162 +    VMThread::execute(&dumper);
   1.163 +  }
   1.164  
   1.165    // close dump file and record any error that the writer may have encountered
   1.166    writer.close();
   1.167 @@ -1845,49 +1869,68 @@
   1.168    }
   1.169  }
   1.170  
   1.171 -
   1.172 -// Called by error reporting
   1.173 +// Called by error reporting by a single Java thread outside of a JVM safepoint,
   1.174 +// or by heap dumping by the VM thread during a (GC) safepoint. Thus, these various
   1.175 +// callers are strictly serialized and guaranteed not to interfere below. For more
   1.176 +// general use, however, this method will need modification to prevent
   1.177 +// inteference when updating the static variables base_path and dump_file_seq below.
   1.178  void HeapDumper::dump_heap() {
   1.179 -  static char path[JVM_MAXPATHLEN];
   1.180 +  static char base_path[JVM_MAXPATHLEN] = {'\0'};
   1.181 +  static uint dump_file_seq = 0;
   1.182 +  char   my_path[JVM_MAXPATHLEN] = {'\0'};
   1.183  
   1.184    // The dump file defaults to java_pid<pid>.hprof in the current working
   1.185    // directory. HeapDumpPath=<file> can be used to specify an alternative
   1.186    // dump file name or a directory where dump file is created.
   1.187 -  bool use_default_filename = true;
   1.188 -  if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
   1.189 -    path[0] = '\0'; // HeapDumpPath=<file> not specified
   1.190 -  } else {
   1.191 -    assert(strlen(HeapDumpPath) < sizeof(path), "HeapDumpPath too long");
   1.192 -    strcpy(path, HeapDumpPath);
   1.193 -    // check if the path is a directory (must exist)
   1.194 -    DIR* dir = os::opendir(path);
   1.195 -    if (dir == NULL) {
   1.196 -      use_default_filename = false;
   1.197 +  if (dump_file_seq == 0) { // first time in, we initialize base_path
   1.198 +    bool use_default_filename = true;
   1.199 +    if (HeapDumpPath == NULL || HeapDumpPath[0] == '\0') {
   1.200 +      // HeapDumpPath=<file> not specified
   1.201      } else {
   1.202 -      // HeapDumpPath specified a directory. We append a file separator
   1.203 -      // (if needed).
   1.204 -      os::closedir(dir);
   1.205 -      size_t fs_len = strlen(os::file_separator());
   1.206 -      if (strlen(path) >= fs_len) {
   1.207 -        char* end = path;
   1.208 -        end += (strlen(path) - fs_len);
   1.209 -        if (strcmp(end, os::file_separator()) != 0) {
   1.210 -          assert(strlen(path) + strlen(os::file_separator()) < sizeof(path),
   1.211 -            "HeapDumpPath too long");
   1.212 -          strcat(path, os::file_separator());
   1.213 +      assert(strlen(HeapDumpPath) < sizeof(base_path), "HeapDumpPath too long");
   1.214 +      strcpy(base_path, HeapDumpPath);
   1.215 +      // check if the path is a directory (must exist)
   1.216 +      DIR* dir = os::opendir(base_path);
   1.217 +      if (dir == NULL) {
   1.218 +        use_default_filename = false;
   1.219 +      } else {
   1.220 +        // HeapDumpPath specified a directory. We append a file separator
   1.221 +        // (if needed).
   1.222 +        os::closedir(dir);
   1.223 +        size_t fs_len = strlen(os::file_separator());
   1.224 +        if (strlen(base_path) >= fs_len) {
   1.225 +          char* end = base_path;
   1.226 +          end += (strlen(base_path) - fs_len);
   1.227 +          if (strcmp(end, os::file_separator()) != 0) {
   1.228 +            assert(strlen(base_path) + strlen(os::file_separator()) < sizeof(base_path),
   1.229 +              "HeapDumpPath too long");
   1.230 +            strcat(base_path, os::file_separator());
   1.231 +          }
   1.232          }
   1.233        }
   1.234      }
   1.235 +    // If HeapDumpPath wasn't a file name then we append the default name
   1.236 +    if (use_default_filename) {
   1.237 +      char fn[32];
   1.238 +      sprintf(fn, "java_pid%d", os::current_process_id());
   1.239 +      assert(strlen(base_path) + strlen(fn) < sizeof(base_path), "HeapDumpPath too long");
   1.240 +      strcat(base_path, fn);
   1.241 +    }
   1.242 +    assert(strlen(base_path) < sizeof(my_path), "Buffer too small");
   1.243 +    strcpy(my_path, base_path);
   1.244 +  } else {
   1.245 +    // Append a sequence number id for dumps following the first
   1.246 +    char fn[33];
   1.247 +    sprintf(fn, ".%d", dump_file_seq);
   1.248 +    assert(strlen(base_path) + strlen(fn) < sizeof(my_path), "HeapDumpPath too long");
   1.249 +    strcpy(my_path, base_path);
   1.250 +    strcat(my_path, fn);
   1.251    }
   1.252 -  // If HeapDumpPath wasn't a file name then we append the default name
   1.253 -  if (use_default_filename) {
   1.254 -    char fn[32];
   1.255 -    sprintf(fn, "java_pid%d.hprof", os::current_process_id());
   1.256 -    assert(strlen(path) + strlen(fn) < sizeof(path), "HeapDumpPath too long");
   1.257 -    strcat(path, fn);
   1.258 -  }
   1.259 +  dump_file_seq++;   // increment seq number for next time we dump
   1.260 +  assert(strlen(".hprof") + strlen(my_path) < sizeof(my_path), "HeapDumpPath too long");
   1.261 +  strcat(my_path, ".hprof");
   1.262  
   1.263    HeapDumper dumper(false /* no GC before heap dump */,
   1.264                      true  /* send to tty */);
   1.265 -  dumper.dump(path);
   1.266 +  dumper.dump(my_path);
   1.267  }

mercurial