Mercurial > hg > truffle
diff src/share/vm/services/memTrackWorker.cpp @ 6197:d2a62e0f25eb
6995781: Native Memory Tracking (Phase 1)
7151532: DCmd for hotspot native memory tracking
Summary: Implementation of native memory tracking phase 1, which tracks VM native memory usage, and related DCmd
Reviewed-by: acorn, coleenp, fparain
author | zgu |
---|---|
date | Thu, 28 Jun 2012 17:03:16 -0400 |
parents | |
children | 4acebbe310e1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/memTrackWorker.cpp Thu Jun 28 17:03:16 2012 -0400 @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/threadCritical.hpp" +#include "services/memTracker.hpp" +#include "services/memTrackWorker.hpp" +#include "utilities/decoder.hpp" +#include "utilities/vmError.hpp" + +MemTrackWorker::MemTrackWorker() { + // create thread uses cgc thread type for now. We should revisit + // the option, or create new thread type. + _has_error = !os::create_thread(this, os::cgc_thread); + set_name("MemTrackWorker", 0); + + // initial generation circuit buffer + if (!has_error()) { + _head = _tail = 0; + for(int index = 0; index < MAX_GENERATIONS; index ++) { + _gen[index] = NULL; + } + } + NOT_PRODUCT(_sync_point_count = 0;) + NOT_PRODUCT(_merge_count = 0;) + NOT_PRODUCT(_last_gen_in_use = 0;) +} + +MemTrackWorker::~MemTrackWorker() { + for (int index = 0; index < MAX_GENERATIONS; index ++) { + MemRecorder* rc = _gen[index]; + if (rc != NULL) { + delete rc; + } + } +} + +void* MemTrackWorker::operator new(size_t size) { + assert(false, "use nothrow version"); + return NULL; +} + +void* MemTrackWorker::operator new(size_t size, const std::nothrow_t& nothrow_constant) { + return allocate(size, false, mtNMT); +} + +void MemTrackWorker::start() { + os::start_thread(this); +} + +/* + * Native memory tracking worker thread loop: + * 1. merge one generation of memory recorders to staging area + * 2. promote staging data to memory snapshot + * + * This thread can run through safepoint. + */ + +void MemTrackWorker::run() { + assert(MemTracker::is_on(), "native memory tracking is off"); + this->initialize_thread_local_storage(); + this->record_stack_base_and_size(); + MemSnapshot* snapshot = MemTracker::get_snapshot(); + assert(snapshot != NULL, "Worker should not be started"); + MemRecorder* rec; + + while (!MemTracker::shutdown_in_progress()) { + NOT_PRODUCT(_last_gen_in_use = generations_in_use();) + { + // take a recorder from earliest generation in buffer + ThreadCritical tc; + rec = _gen[_head]; + if (rec != NULL) { + _gen[_head] = rec->next(); + } + assert(count_recorder(_gen[_head]) <= MemRecorder::_instance_count, + "infinite loop after dequeue"); + } + if (rec != NULL) { + // merge the recorder into staging area + bool result = snapshot->merge(rec); + assert(result, "merge failed"); + debug_only(_merge_count ++;) + MemTracker::release_thread_recorder(rec); + } else { + // no more recorder to merge, promote staging area + // to snapshot + if (_head != _tail) { + { + ThreadCritical tc; + if (_gen[_head] != NULL || _head == _tail) { + continue; + } + // done with this generation, increment _head pointer + _head = (_head + 1) % MAX_GENERATIONS; + } + // promote this generation data to snapshot + snapshot->promote(); + } else { + snapshot->wait(1000); + ThreadCritical tc; + // check if more data arrived + if (_gen[_head] == NULL) { + _gen[_head] = MemTracker::get_pending_recorders(); + } + } + } + } + assert(MemTracker::shutdown_in_progress(), "just check"); + + // transites to final shutdown + MemTracker::final_shutdown(); +} + +// at synchronization point, where 'safepoint visible' Java threads are blocked +// at a safepoint, and the rest of threads are blocked on ThreadCritical lock. +// The caller MemTracker::sync() already takes ThreadCritical before calling this +// method. +// +// Following tasks are performed: +// 1. add all recorders in pending queue to current generation +// 2. increase generation + +void MemTrackWorker::at_sync_point(MemRecorder* rec) { + NOT_PRODUCT(_sync_point_count ++;) + assert(count_recorder(rec) <= MemRecorder::_instance_count, + "pending queue has infinite loop"); + + bool out_of_generation_buffer = false; + // check shutdown state inside ThreadCritical + if (MemTracker::shutdown_in_progress()) return; + // append the recorders to the end of the generation + if( rec != NULL) { + MemRecorder* cur_head = _gen[_tail]; + if (cur_head == NULL) { + _gen[_tail] = rec; + } else { + while (cur_head->next() != NULL) { + cur_head = cur_head->next(); + } + cur_head->set_next(rec); + } + } + assert(count_recorder(rec) <= MemRecorder::_instance_count, + "after add to current generation has infinite loop"); + // we have collected all recorders for this generation. If there is data, + // we need to increment _tail to start a new generation. + if (_gen[_tail] != NULL || _head == _tail) { + _tail = (_tail + 1) % MAX_GENERATIONS; + out_of_generation_buffer = (_tail == _head); + } + + if (out_of_generation_buffer) { + MemTracker::shutdown(MemTracker::NMT_out_of_generation); + } +} + +#ifndef PRODUCT +int MemTrackWorker::count_recorder(const MemRecorder* head) { + int count = 0; + while(head != NULL) { + count ++; + head = head->next(); + } + return count; +} + +int MemTrackWorker::count_pending_recorders() const { + int count = 0; + for (int index = 0; index < MAX_GENERATIONS; index ++) { + MemRecorder* head = _gen[index]; + if (head != NULL) { + count += count_recorder(head); + } + } + return count; +} +#endif