hotspot/src/share/vm/services/memTrackWorker.cpp
changeset 25962 8f95d0407e21
parent 25940 6a6c91ccc0bc
parent 25961 983a1ebcc848
child 25963 fabe6090d37a
child 26185 f179c0827318
equal deleted inserted replaced
25940:6a6c91ccc0bc 25962:8f95d0407e21
     1 /*
       
     2  * Copyright (c) 2013, 2014, 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 "runtime/threadCritical.hpp"
       
    27 #include "services/memTracker.hpp"
       
    28 #include "services/memTrackWorker.hpp"
       
    29 #include "utilities/decoder.hpp"
       
    30 #include "utilities/vmError.hpp"
       
    31 
       
    32 
       
    33 void GenerationData::reset() {
       
    34   _number_of_classes = 0;
       
    35   while (_recorder_list != NULL) {
       
    36     MemRecorder* tmp = _recorder_list;
       
    37     _recorder_list = _recorder_list->next();
       
    38     MemTracker::release_thread_recorder(tmp);
       
    39   }
       
    40 }
       
    41 
       
    42 MemTrackWorker::MemTrackWorker(MemSnapshot* snapshot): _snapshot(snapshot) {
       
    43   // create thread uses cgc thread type for now. We should revisit
       
    44   // the option, or create new thread type.
       
    45   _has_error = !os::create_thread(this, os::cgc_thread);
       
    46   set_name("MemTrackWorker");
       
    47 
       
    48   // initial generation circuit buffer
       
    49   if (!has_error()) {
       
    50     _head = _tail = 0;
       
    51     for(int index = 0; index < MAX_GENERATIONS; index ++) {
       
    52       ::new ((void*)&_gen[index]) GenerationData();
       
    53     }
       
    54   }
       
    55   NOT_PRODUCT(_sync_point_count = 0;)
       
    56   NOT_PRODUCT(_merge_count = 0;)
       
    57   NOT_PRODUCT(_last_gen_in_use = 0;)
       
    58 }
       
    59 
       
    60 MemTrackWorker::~MemTrackWorker() {
       
    61   for (int index = 0; index < MAX_GENERATIONS; index ++) {
       
    62     _gen[index].reset();
       
    63   }
       
    64 }
       
    65 
       
    66 void* MemTrackWorker::operator new(size_t size) throw() {
       
    67   assert(false, "use nothrow version");
       
    68   return NULL;
       
    69 }
       
    70 
       
    71 void* MemTrackWorker::operator new(size_t size, const std::nothrow_t& nothrow_constant) throw() {
       
    72   return allocate(size, false, mtNMT);
       
    73 }
       
    74 
       
    75 void MemTrackWorker::start() {
       
    76   os::start_thread(this);
       
    77 }
       
    78 
       
    79 /*
       
    80  * Native memory tracking worker thread loop:
       
    81  *   1. merge one generation of memory recorders to staging area
       
    82  *   2. promote staging data to memory snapshot
       
    83  *
       
    84  * This thread can run through safepoint.
       
    85  */
       
    86 
       
    87 void MemTrackWorker::run() {
       
    88   assert(MemTracker::is_on(), "native memory tracking is off");
       
    89   this->initialize_thread_local_storage();
       
    90   this->record_stack_base_and_size();
       
    91   assert(_snapshot != NULL, "Worker should not be started");
       
    92   MemRecorder* rec;
       
    93   unsigned long processing_generation = 0;
       
    94   bool          worker_idle = false;
       
    95 
       
    96   while (!MemTracker::shutdown_in_progress()) {
       
    97     NOT_PRODUCT(_last_gen_in_use = generations_in_use();)
       
    98     {
       
    99       // take a recorder from earliest generation in buffer
       
   100       ThreadCritical tc;
       
   101       rec = _gen[_head].next_recorder();
       
   102     }
       
   103     if (rec != NULL) {
       
   104       if (rec->get_generation() != processing_generation || worker_idle) {
       
   105         processing_generation = rec->get_generation();
       
   106         worker_idle = false;
       
   107         MemTracker::set_current_processing_generation(processing_generation);
       
   108       }
       
   109 
       
   110       // merge the recorder into staging area
       
   111       if (!_snapshot->merge(rec)) {
       
   112         MemTracker::shutdown(MemTracker::NMT_out_of_memory);
       
   113       } else {
       
   114         NOT_PRODUCT(_merge_count ++;)
       
   115       }
       
   116       MemTracker::release_thread_recorder(rec);
       
   117     } else {
       
   118       // no more recorder to merge, promote staging area
       
   119       // to snapshot
       
   120       if (_head != _tail) {
       
   121         long number_of_classes;
       
   122         {
       
   123           ThreadCritical tc;
       
   124           if (_gen[_head].has_more_recorder() || _head == _tail) {
       
   125             continue;
       
   126           }
       
   127           number_of_classes = _gen[_head].number_of_classes();
       
   128           _gen[_head].reset();
       
   129 
       
   130           // done with this generation, increment _head pointer
       
   131           _head = (_head + 1) % MAX_GENERATIONS;
       
   132         }
       
   133         // promote this generation data to snapshot
       
   134         if (!_snapshot->promote(number_of_classes)) {
       
   135           // failed to promote, means out of memory
       
   136           MemTracker::shutdown(MemTracker::NMT_out_of_memory);
       
   137         }
       
   138       } else {
       
   139         // worker thread is idle
       
   140         worker_idle = true;
       
   141         MemTracker::report_worker_idle();
       
   142         _snapshot->wait(1000);
       
   143         ThreadCritical tc;
       
   144         // check if more data arrived
       
   145         if (!_gen[_head].has_more_recorder()) {
       
   146           _gen[_head].add_recorders(MemTracker::get_pending_recorders());
       
   147         }
       
   148       }
       
   149     }
       
   150   }
       
   151   assert(MemTracker::shutdown_in_progress(), "just check");
       
   152 
       
   153   // transits to final shutdown
       
   154   MemTracker::final_shutdown();
       
   155 }
       
   156 
       
   157 // at synchronization point, where 'safepoint visible' Java threads are blocked
       
   158 // at a safepoint, and the rest of threads are blocked on ThreadCritical lock.
       
   159 // The caller MemTracker::sync() already takes ThreadCritical before calling this
       
   160 // method.
       
   161 //
       
   162 // Following tasks are performed:
       
   163 //   1. add all recorders in pending queue to current generation
       
   164 //   2. increase generation
       
   165 
       
   166 void MemTrackWorker::at_sync_point(MemRecorder* rec, int number_of_classes) {
       
   167   NOT_PRODUCT(_sync_point_count ++;)
       
   168   assert(count_recorder(rec) <= MemRecorder::_instance_count,
       
   169     "pending queue has infinite loop");
       
   170 
       
   171   bool out_of_generation_buffer = false;
       
   172   // check shutdown state inside ThreadCritical
       
   173   if (MemTracker::shutdown_in_progress()) return;
       
   174 
       
   175   _gen[_tail].set_number_of_classes(number_of_classes);
       
   176   // append the recorders to the end of the generation
       
   177   _gen[_tail].add_recorders(rec);
       
   178   assert(count_recorder(_gen[_tail].peek()) <= MemRecorder::_instance_count,
       
   179     "after add to current generation has infinite loop");
       
   180   // we have collected all recorders for this generation. If there is data,
       
   181   // we need to increment _tail to start a new generation.
       
   182   if (_gen[_tail].has_more_recorder()  || _head == _tail) {
       
   183     _tail = (_tail + 1) % MAX_GENERATIONS;
       
   184     out_of_generation_buffer = (_tail == _head);
       
   185   }
       
   186 
       
   187   if (out_of_generation_buffer) {
       
   188     MemTracker::shutdown(MemTracker::NMT_out_of_generation);
       
   189   }
       
   190 }
       
   191 
       
   192 #ifndef PRODUCT
       
   193 int MemTrackWorker::count_recorder(const MemRecorder* head) {
       
   194   int count = 0;
       
   195   while(head != NULL) {
       
   196     count ++;
       
   197     head = head->next();
       
   198   }
       
   199   return count;
       
   200 }
       
   201 
       
   202 int MemTrackWorker::count_pending_recorders() const {
       
   203   int count = 0;
       
   204   for (int index = 0; index < MAX_GENERATIONS; index ++) {
       
   205     MemRecorder* head = _gen[index].peek();
       
   206     if (head != NULL) {
       
   207       count += count_recorder(head);
       
   208     }
       
   209   }
       
   210   return count;
       
   211 }
       
   212 #endif