Skip to content
Permalink
Browse files
8237354: Add option to jcmd to write a gzipped heap dump
Reviewed-by: rrich, clanger, goetz
  • Loading branch information
schmelter-sap committed Jun 10, 2020
1 parent 2e8356e commit 19be49714356f2f598924c9fefa6358679ab6dbe
Showing 13 changed files with 1,708 additions and 121 deletions.
@@ -94,6 +94,17 @@ void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
}
}

static void run_foreground_task_if_needed(AbstractGangTask* task, uint num_workers,
bool add_foreground_work) {
if (add_foreground_work) {
log_develop_trace(gc, workgang)("Running work gang: %s task: %s worker: foreground",
Thread::current()->name(), task->name());
task->work(num_workers);
log_develop_trace(gc, workgang)("Finished work gang: %s task: %s worker: foreground "
"thread: " PTR_FORMAT, Thread::current()->name(), task->name(), p2i(Thread::current()));
}
}

// WorkGang dispatcher implemented with semaphores.
//
// Semaphores don't require the worker threads to re-claim the lock when they wake up.
@@ -124,14 +135,16 @@ class SemaphoreGangTaskDispatcher : public GangTaskDispatcher {
delete _end_semaphore;
}

void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers, bool add_foreground_work) {
// No workers are allowed to read the state variables until they have been signaled.
_task = task;
_not_finished = num_workers;

// Dispatch 'num_workers' number of tasks.
_start_semaphore->signal(num_workers);

run_foreground_task_if_needed(task, num_workers, add_foreground_work);

// Wait for the last worker to signal the coordinator.
_end_semaphore->wait();

@@ -188,7 +201,7 @@ class MutexGangTaskDispatcher : public GangTaskDispatcher {
delete _monitor;
}

void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) {
void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers, bool add_foreground_work) {
MonitorLocker ml(_monitor, Mutex::_no_safepoint_check_flag);

_task = task;
@@ -197,6 +210,8 @@ class MutexGangTaskDispatcher : public GangTaskDispatcher {
// Tell the workers to get to work.
_monitor->notify_all();

run_foreground_task_if_needed(task, num_workers, add_foreground_work);

// Wait for them to finish.
while (_finished < _num_workers) {
ml.wait();
@@ -263,14 +278,14 @@ void WorkGang::run_task(AbstractGangTask* task) {
run_task(task, active_workers());
}

void WorkGang::run_task(AbstractGangTask* task, uint num_workers) {
void WorkGang::run_task(AbstractGangTask* task, uint num_workers, bool add_foreground_work) {
guarantee(num_workers <= total_workers(),
"Trying to execute task %s with %u workers which is more than the amount of total workers %u.",
task->name(), num_workers, total_workers());
guarantee(num_workers > 0, "Trying to execute task %s with zero workers", task->name());
uint old_num_workers = _active_workers;
update_active_workers(num_workers);
_dispatcher->coordinator_execute_on_workers(task, num_workers);
_dispatcher->coordinator_execute_on_workers(task, num_workers, add_foreground_work);
update_active_workers(old_num_workers);
}

@@ -90,7 +90,8 @@ class GangTaskDispatcher : public CHeapObj<mtGC> {

// Distributes the task out to num_workers workers.
// Returns when the task has been completed by all workers.
virtual void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers) = 0;
virtual void coordinator_execute_on_workers(AbstractGangTask* task, uint num_workers,
bool add_foreground_work) = 0;

// Worker API.

@@ -215,8 +216,9 @@ class WorkGang: public AbstractWorkGang {
// Run a task with the given number of workers, returns
// when the task is done. The number of workers must be at most the number of
// active workers. Additional workers may be created if an insufficient
// number currently exists.
void run_task(AbstractGangTask* task, uint num_workers);
// number currently exists. If the add_foreground_work flag is true, the current thread
// is used to run the task too.
void run_task(AbstractGangTask* task, uint num_workers, bool add_foreground_work = false);

protected:
virtual AbstractGangWorker* allocate_worker(uint which);
@@ -504,17 +504,32 @@ HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
DCmdWithParser(output, heap),
_filename("filename","Name of the dump file", "STRING",true),
_all("-all", "Dump all objects, including unreachable objects",
"BOOLEAN", false, "false") {
"BOOLEAN", false, "false"),
_gzip("-gz", "If specified, the heap dump is written in gzipped format "
"using the given compression level. 1 (recommended) is the fastest, "
"9 the strongest compression.", "INT", false, "1") {
_dcmdparser.add_dcmd_option(&_all);
_dcmdparser.add_dcmd_argument(&_filename);
_dcmdparser.add_dcmd_option(&_gzip);
}

void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
jlong level = -1; // -1 means no compression.

if (_gzip.is_set()) {
level = _gzip.value();

if (level < 1 || level > 9) {
output()->print_cr("Compression level out of range (1-9): " JLONG_FORMAT, level);
return;
}
}

// Request a full GC before heap dump if _all is false
// This helps reduces the amount of unreachable objects in the dump
// and makes it easier to browse.
HeapDumper dumper(!_all.value() /* request GC if _all is false*/);
dumper.dump(_filename.value(), output());
dumper.dump(_filename.value(), output(), (int) level);
}

int HeapDumpDCmd::num_arguments() {
@@ -330,6 +330,7 @@ class HeapDumpDCmd : public DCmdWithParser {
protected:
DCmdArgument<char*> _filename;
DCmdArgument<bool> _all;
DCmdArgument<jlong> _gzip;
public:
HeapDumpDCmd(outputStream* output, bool heap);
static const char* name() {

0 comments on commit 19be497

Please sign in to comment.