Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eliminate dependency on Swing and call to invokeLater #345

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,24 @@ public final class HeapProgress {

public static final int PROGRESS_MAX = 1000;
private static ThreadLocal<ModelInfo> progressThreadLocal = new ThreadLocal();
static {
Progress.register(new Progress.Listener() {
@Override
public void started(Progress.Handle h) {
progressStart();
}

@Override
public void progress(Progress.Handle h) {
HeapProgress.progress(h.getValue(), h.getEndOffset(), h.getStartOffset());
}

@Override
public void finished(Progress.Handle h) {
progressFinish();
}
});
}

private HeapProgress() {
}
Expand All @@ -51,17 +69,6 @@ public static BoundedRangeModel getProgress() {
return info.model;
}

static void progress(long counter, long startOffset, long value, long endOffset) {
// keep this method short so that it can be inlined
if (counter % 100000 == 0) {
progress(value, endOffset, startOffset);
}
}

static void progress(long value, long endValue) {
progress(value,0,value,endValue);
}

private static void progress(final long value, final long endOffset, final long startOffset) {
ModelInfo info = progressThreadLocal.get();
if (info != null) {
Expand All @@ -79,14 +86,14 @@ private static int levelAdd(ModelInfo info, int diff) {
return info.level;
}

static void progressStart() {
private static void progressStart() {
ModelInfo info = progressThreadLocal.get();
if (info != null) {
levelAdd(info, 1);
}
}

static void progressFinish() {
private static void progressFinish() {
ModelInfo info = progressThreadLocal.get();
if (info != null) {
int level = levelAdd(info, -1);
Expand All @@ -98,7 +105,7 @@ static void progressFinish() {
info.offset = info.model.getValue();
}
}

private static void setValue(final BoundedRangeModel model, final int val) {
if (SwingUtilities.isEventDispatchThread()) {
model.setValue(val);
Expand All @@ -108,7 +115,7 @@ private static void setValue(final BoundedRangeModel model, final int val) {
});
}
}

private static class ModelInfo {
private BoundedRangeModel model;
private int level;
Expand All @@ -117,6 +124,6 @@ private static class ModelInfo {

private ModelInfo() {
model = new DefaultBoundedRangeModel(0,0,0,PROGRESS_MAX);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -523,7 +523,7 @@ void computeInstances() {
return;
}

HeapProgress.progressStart();
Progress.Handle handle = Progress.COMPUTE_INSTANCES.start();
cacheDirectory.setDirty(true);
ClassDumpSegment classDumpBounds = getClassDumpSegment();
int idSize = dumpBuffer.getIDSize();
Expand Down Expand Up @@ -565,12 +565,12 @@ void computeInstances() {
instanceEntry.setIndex(classDump.getInstancesCount());
classDumpBounds.addInstanceSize(classDump, tag, start);
}
HeapProgress.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
handle.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
}
instancesCountComputed = true;
writeToFile();
handle.close();
}
HeapProgress.progressFinish();
}

List findReferencesFor(long instanceId) {
Expand Down Expand Up @@ -638,7 +638,7 @@ void computeReferences() {
return;
}

HeapProgress.progressStart();
Progress.Handle handle = Progress.COMPUTE_INSTANCES.start();
ClassDumpSegment classDumpBounds = getClassDumpSegment();
int idSize = dumpBuffer.getIDSize();
long[] offset = new long[] { allInstanceDumpBounds.startOffset };
Expand Down Expand Up @@ -693,7 +693,7 @@ void computeReferences() {
}
}
}
HeapProgress.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
handle.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
}

for (JavaClass cls : getClassDumpSegment().createClassCollection()) {
Expand All @@ -715,16 +715,16 @@ void computeReferences() {
idToOffsetMap.flush();
referencesComputed = true;
writeToFile();
handle.close();
}
HeapProgress.progressFinish();
}

void computeRetainedSize() {
synchronized (retainedSizeLock) {
if (retainedSizeComputed) {
return;
}
HeapProgress.progressStart();
Progress.Handle handle = Progress.COMPUTE_RETAINED_SIZE.start();
LongBuffer leaves = nearestGCRoot.getLeaves();
cacheDirectory.setDirty(true);
new TreeObject(this,leaves).computeTrees();
Expand Down Expand Up @@ -779,12 +779,12 @@ void computeRetainedSize() {
entry.setRetainedSize(retainedSize+size);
}
}
HeapProgress.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
handle.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
}
retainedSizeComputed = true;
writeToFile();
handle.close();
}
HeapProgress.progressFinish();
}

void computeRetainedSizeByClass() {
Expand All @@ -794,7 +794,7 @@ void computeRetainedSizeByClass() {
}
computeRetainedSize();
cacheDirectory.setDirty(true);
HeapProgress.progressStart();
Progress.Handle handle = Progress.COMPUTE_RETAINED_SIZE_BY_CLASS.start();
long[] offset = new long[] { allInstanceDumpBounds.startOffset };

for (long counter=0; offset[0] < allInstanceDumpBounds.endOffset; counter++) {
Expand All @@ -810,14 +810,14 @@ void computeRetainedSizeByClass() {
}
}
}
HeapProgress.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
handle.progress(counter,allInstanceDumpBounds.startOffset,start,allInstanceDumpBounds.endOffset);
}
// all done, release domTree
domTree = null;
retainedSizeByClassComputed = true;
writeToFile();
handle.close();
}
HeapProgress.progressFinish();
}

Instance getNearestGCRootPointer(Instance instance) {
Expand Down Expand Up @@ -1283,7 +1283,7 @@ private void fillHeapTagBounds() {
return;
}

HeapProgress.progressStart();
Progress.Handle handle = Progress.FILL_HEAP_TAG_BOUNDS.start();
heapTagBounds = new TagBounds[0x100];

long[] offset = new long[] { heapDumpSegment.startOffset + 1 + 4 + 4 };
Expand Down Expand Up @@ -1311,15 +1311,15 @@ private void fillHeapTagBounds() {
if ((tag == CLASS_DUMP) || (tag == INSTANCE_DUMP) || (tag == OBJECT_ARRAY_DUMP) || (tag == PRIMITIVE_ARRAY_DUMP)) {
idMapSize++;
}
HeapProgress.progress(counter,heapDumpSegment.startOffset,start,heapDumpSegment.endOffset);
handle.progress(counter,heapDumpSegment.startOffset,start,heapDumpSegment.endOffset);
}

TagBounds instanceDumpBounds = heapTagBounds[INSTANCE_DUMP];
TagBounds objArrayDumpBounds = heapTagBounds[OBJECT_ARRAY_DUMP];
TagBounds primArrayDumpBounds = heapTagBounds[PRIMITIVE_ARRAY_DUMP];
allInstanceDumpBounds = instanceDumpBounds.union(objArrayDumpBounds);
allInstanceDumpBounds = allInstanceDumpBounds.union(primArrayDumpBounds);
HeapProgress.progressFinish();
handle.close();
}

private void fillTagBounds(long tagStart) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private synchronized void computeGCRoots() {
if (gcRootsComputed) {
return;
}
HeapProgress.progressStart();
Progress.Handle handle = Progress.COMPUTE_GC_ROOTS.start();
if (!initHotSpotReference()) {
if (!initSVMReference()) {
throw new IllegalArgumentException("reference field not found"); // NOI18N
Expand All @@ -114,7 +114,7 @@ private synchronized void computeGCRoots() {

do {
switchBuffers();
computeOneLevel(processedClasses);
computeOneLevel(processedClasses, handle);
} while (hasMoreLevels());
} catch (IOException ex) {
ex.printStackTrace();
Expand All @@ -124,7 +124,7 @@ private synchronized void computeGCRoots() {
heap.idToOffsetMap.flush();
gcRootsComputed = true;
heap.writeToFile();
HeapProgress.progressFinish();
handle.close();
}

private boolean initHotSpotReference() {
Expand Down Expand Up @@ -159,7 +159,7 @@ private boolean initSVMReference() {
return false;
}

private void computeOneLevel(Set processedClasses) throws IOException {
private void computeOneLevel(Set processedClasses, Progress.Handle handle) throws IOException {
int idSize = heap.dumpBuffer.getIDSize();
for (;;) {
Instance instance;
Expand All @@ -170,7 +170,7 @@ private void computeOneLevel(Set processedClasses) throws IOException {
if (instanceOffset == 0L) { // end of level
break;
}
HeapProgress.progress(processedInstances++,allInstances);
handle.progress(processedInstances++,allInstances);
instance = heap.getInstanceByOffset(new long[] {instanceOffset});
if (instance instanceof ObjectArrayInstance) {
ObjectArrayDump array = (ObjectArrayDump) instance;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 1997, 2021, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package org.graalvm.visualvm.lib.jfluid.heap;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

enum Progress {
COMPUTE_INSTANCES,
COMPUTE_REFERENCES,
FILL_HEAP_TAG_BOUNDS,
COMPUTE_GC_ROOTS,
COMPUTE_RETAINED_SIZE,
COMPUTE_RETAINED_SIZE_BY_CLASS;

Handle start() {
return new Handle(this);
}

private static List<Listener> listeners = Collections.emptyList();
synchronized static void register(Listener onChange) {
if (listeners.isEmpty()) {
listeners = Collections.singletonList(onChange);
} else {
List<Listener> copy = new ArrayList<>(listeners);
copy.add(onChange);
listeners = copy;
}
}

private synchronized static void notifyUpdates(Handle h, Type type) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how bout ?

private synchronized static void notifyUpdates(Handle h, BiConsumer<Listener, Handle> c) {
    for (Listener onChange : listeners) {
         c.accept(onChange, h);
     }
}

and then call it like

    @Override
    public void close() {
        notifyUpdates(this, 2);
        notifyUpdates(this, Listener::finished);
    }

for (Listener onChange : listeners) {
switch (type) {
case STARTED: onChange.started(h); break;
case PROGRESS: onChange.progress(h); break;
default: onChange.finished(h);
}
}
}

private enum Type {
STARTED, PROGRESS, FINISHED;
}

static interface Listener {
void started(Handle h);
void progress(Handle h);
void finished(Handle h);
}

static final class Handle implements AutoCloseable {
final Progress type;
private long value;
private long startOffset;
private long endOffset;

private Handle(Progress type) {
this.type = type;
notifyUpdates(this, Type.STARTED);
}

void progress(long value, long endValue) {
progress(value, 0, value, endValue);
}

void progress(long counter, long startOffset, long value, long endOffset) {
// keep this method short so that it can be inlined
if (counter % 100000 == 0) {
doProgress(value, startOffset, endOffset);
}
}

@Override
public void close() {
notifyUpdates(this, Type.FINISHED);
}

private void doProgress(long value, long startOffset, long endOffset) {
this.value = value;
this.endOffset = endOffset;
this.startOffset = startOffset;
notifyUpdates(this, Type.PROGRESS);
}

long getValue() {
return value;
}

long getStartOffset() {
return startOffset;
}

long getEndOffset() {
return endOffset;
}
}
}