mirror of
https://github.com/corda/corda.git
synced 2025-05-19 00:43:17 +00:00
name VM-internal classes for heapdump=true builds
This makes heap dumps more useful since these classes are now refered to by name instead of number. This commit also adds a couple of utilities for parsing heap dumps: PrintDump and DumpStats.
This commit is contained in:
parent
8e23893af0
commit
64601e6f3e
3
makefile
3
makefile
@ -315,7 +315,8 @@ generated-code = \
|
|||||||
$(native-build)/type-declarations.cpp \
|
$(native-build)/type-declarations.cpp \
|
||||||
$(native-build)/type-constructors.cpp \
|
$(native-build)/type-constructors.cpp \
|
||||||
$(native-build)/type-initializations.cpp \
|
$(native-build)/type-initializations.cpp \
|
||||||
$(native-build)/type-java-initializations.cpp
|
$(native-build)/type-java-initializations.cpp \
|
||||||
|
$(native-build)/type-name-initializations.cpp
|
||||||
|
|
||||||
vm-depends = \
|
vm-depends = \
|
||||||
$(generated-code) \
|
$(generated-code) \
|
||||||
|
@ -1888,6 +1888,13 @@ bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name,
|
|||||||
hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash);
|
hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nameClass(Thread* t, Machine::Type type, const char* name)
|
||||||
|
{
|
||||||
|
object n = makeByteArray(t, name);
|
||||||
|
set(t, arrayBody(t, t->m->types, type), ClassName, n);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
boot(Thread* t)
|
boot(Thread* t)
|
||||||
{
|
{
|
||||||
@ -1990,6 +1997,10 @@ boot(Thread* t)
|
|||||||
PROTECT(t, bootMethod);
|
PROTECT(t, bootMethod);
|
||||||
|
|
||||||
#include "type-java-initializations.cpp"
|
#include "type-java-initializations.cpp"
|
||||||
|
|
||||||
|
#ifdef AVIAN_HEAPDUMP
|
||||||
|
# include "type-name-initializations.cpp"
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2184,6 +2184,27 @@ writeJavaInitializations(Output* out, Object* declarations)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeNameInitialization(Output* out, Object* type)
|
||||||
|
{
|
||||||
|
out->write("nameClass(t, Machine::");
|
||||||
|
out->write(capitalize(typeName(type)));
|
||||||
|
out->write("Type, \"vm::");
|
||||||
|
out->write(typeName(type));
|
||||||
|
out->write("\");\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
writeNameInitializations(Output* out, Object* declarations)
|
||||||
|
{
|
||||||
|
for (Object* p = declarations; p; p = cdr(p)) {
|
||||||
|
Object* o = car(p);
|
||||||
|
if (o->type == Object::Type and typeJavaName(o) == 0) {
|
||||||
|
writeNameInitialization(out, o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
usageAndExit(const char* command)
|
usageAndExit(const char* command)
|
||||||
{
|
{
|
||||||
@ -2206,7 +2227,8 @@ main(int ac, char** av)
|
|||||||
and not equal(av[2], "declarations")
|
and not equal(av[2], "declarations")
|
||||||
and not equal(av[2], "constructors")
|
and not equal(av[2], "constructors")
|
||||||
and not equal(av[2], "initializations")
|
and not equal(av[2], "initializations")
|
||||||
and not equal(av[2], "java-initializations")))
|
and not equal(av[2], "java-initializations")
|
||||||
|
and not equal(av[2], "name-initializations")))
|
||||||
{
|
{
|
||||||
usageAndExit(av[0]);
|
usageAndExit(av[0]);
|
||||||
}
|
}
|
||||||
@ -2246,5 +2268,9 @@ main(int ac, char** av)
|
|||||||
writeJavaInitializations(&out, declarations);
|
writeJavaInitializations(&out, declarations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ac == 2 or equal(av[2], "name-initializations")) {
|
||||||
|
writeNameInitializations(&out, declarations);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
147
test/extra/DumpStats.java
Normal file
147
test/extra/DumpStats.java
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package extra;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a simple utility to generate and print statistics from a
|
||||||
|
* heap dump generated by Avian's heapdump.cpp. The output is a list
|
||||||
|
* of classes (identified by number in the case of anonymous,
|
||||||
|
* VM-internal classes), each followed by (1) the total memory
|
||||||
|
* footprint of all instances of the class, and (2) the number of
|
||||||
|
* instances. The output is ordered by instance memory footprint.
|
||||||
|
*/
|
||||||
|
public class DumpStats {
|
||||||
|
private static final int Root = 0;
|
||||||
|
private static final int Size = 1;
|
||||||
|
private static final int ClassName = 2;
|
||||||
|
private static final int Push = 3;
|
||||||
|
private static final int Pop = 4;
|
||||||
|
|
||||||
|
private static int readInt(InputStream in) throws IOException {
|
||||||
|
int b1 = in.read();
|
||||||
|
int b2 = in.read();
|
||||||
|
int b3 = in.read();
|
||||||
|
int b4 = in.read();
|
||||||
|
if (b4 == -1) throw new EOFException();
|
||||||
|
return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readString(InputStream in) throws IOException {
|
||||||
|
int count = readInt(in);
|
||||||
|
byte[] b = new byte[count];
|
||||||
|
int offset = 0;
|
||||||
|
int c;
|
||||||
|
while ((c = in.read(b, offset, b.length - offset)) != -1
|
||||||
|
&& offset < b.length)
|
||||||
|
{
|
||||||
|
offset += c;
|
||||||
|
}
|
||||||
|
if (offset != b.length) throw new EOFException();
|
||||||
|
return new String(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Record record(Map<Integer, Record> map, int key) {
|
||||||
|
Record r = map.get(key);
|
||||||
|
if (r == null) {
|
||||||
|
map.put(key, r = new Record(key));
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Integer, Record> read(InputStream in)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
boolean done = false;
|
||||||
|
boolean popped = false;
|
||||||
|
int size = 0;
|
||||||
|
int last = 0;
|
||||||
|
Map<Integer, Record> map = new HashMap();
|
||||||
|
|
||||||
|
while (! done) {
|
||||||
|
int flag = in.read();
|
||||||
|
switch (flag) {
|
||||||
|
case Root: {
|
||||||
|
last = readInt(in);
|
||||||
|
popped = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ClassName: {
|
||||||
|
record(map, last).name = readString(in);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Push: {
|
||||||
|
last = readInt(in);
|
||||||
|
if (! popped) {
|
||||||
|
Record r = record(map, last);
|
||||||
|
r.footprint += size;
|
||||||
|
++ r.count;
|
||||||
|
}
|
||||||
|
popped = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Pop: {
|
||||||
|
popped = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Size: {
|
||||||
|
size = readInt(in);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("bad flag: " + flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
Map<Integer, Record> map = read
|
||||||
|
(new BufferedInputStream(new FileInputStream(args[0])));
|
||||||
|
|
||||||
|
Record[] array = map.values().toArray(new Record[map.size()]);
|
||||||
|
Arrays.sort(array, new Comparator<Record>() {
|
||||||
|
public int compare(Record a, Record b) {
|
||||||
|
return b.footprint - a.footprint;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
int footprint = 0;
|
||||||
|
int count = 0;
|
||||||
|
for (Record r: array) {
|
||||||
|
if (r.name == null) {
|
||||||
|
r.name = String.valueOf(r.key);
|
||||||
|
}
|
||||||
|
System.out.println(r.name + ": " + r.footprint + " " + r.count);
|
||||||
|
footprint += r.footprint;
|
||||||
|
count += r.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println();
|
||||||
|
System.out.println("total: " + footprint + " " + count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Record {
|
||||||
|
public final int key;
|
||||||
|
public String name;
|
||||||
|
public int footprint;
|
||||||
|
public int count;
|
||||||
|
|
||||||
|
public Record(int key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
101
test/extra/PrintDump.java
Normal file
101
test/extra/PrintDump.java
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package extra;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.EOFException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a simple utility to print the contents of a heap dump
|
||||||
|
* generated by Avian's heapdump.cpp in a human-readable format.
|
||||||
|
*/
|
||||||
|
public class PrintDump {
|
||||||
|
private static final int Root = 0;
|
||||||
|
private static final int Size = 1;
|
||||||
|
private static final int ClassName = 2;
|
||||||
|
private static final int Push = 3;
|
||||||
|
private static final int Pop = 4;
|
||||||
|
|
||||||
|
private static void indent(PrintStream out, int level) {
|
||||||
|
for (; level > 0; --level) out.print(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int readInt(InputStream in) throws IOException {
|
||||||
|
int b1 = in.read();
|
||||||
|
int b2 = in.read();
|
||||||
|
int b3 = in.read();
|
||||||
|
int b4 = in.read();
|
||||||
|
if (b4 == -1) throw new EOFException();
|
||||||
|
return (int) ((b1 << 24) | (b2 << 16) | (b3 << 8) | (b4));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readString(InputStream in) throws IOException {
|
||||||
|
int count = readInt(in);
|
||||||
|
byte[] b = new byte[count];
|
||||||
|
int offset = 0;
|
||||||
|
int c;
|
||||||
|
while ((c = in.read(b, offset, b.length - offset)) != -1
|
||||||
|
&& offset < b.length)
|
||||||
|
{
|
||||||
|
offset += c;
|
||||||
|
}
|
||||||
|
if (offset != b.length) throw new EOFException();
|
||||||
|
return new String(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void pipe(InputStream in, PrintStream out)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
boolean done = false;
|
||||||
|
boolean popped = false;
|
||||||
|
int level = 0;
|
||||||
|
while (! done) {
|
||||||
|
int flag = in.read();
|
||||||
|
switch (flag) {
|
||||||
|
case Root: {
|
||||||
|
out.print("\nroot " + readInt(in));
|
||||||
|
popped = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ClassName: {
|
||||||
|
out.print(" class " + readString(in));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Push: {
|
||||||
|
++ level;
|
||||||
|
out.println();
|
||||||
|
indent(out, level);
|
||||||
|
if (! popped) {
|
||||||
|
out.print("first ");
|
||||||
|
}
|
||||||
|
out.print("child " + readInt(in));
|
||||||
|
popped = false;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Pop: {
|
||||||
|
-- level;
|
||||||
|
popped = true;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Size: {
|
||||||
|
out.print(" size " + readInt(in));
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
out.println();
|
||||||
|
out.flush();
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("bad flag: " + flag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
pipe(new BufferedInputStream(new FileInputStream(args[0])), System.out);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user