summaryrefslogtreecommitdiff
path: root/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java')
-rw-r--r--libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java458
1 files changed, 458 insertions, 0 deletions
diff --git a/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java b/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java
new file mode 100644
index 000000000..d56a71da3
--- /dev/null
+++ b/libjava/gnu/gcj/tools/gc_analyze/MemoryAnalyze.java
@@ -0,0 +1,458 @@
+/* MemoryAnalyze.java -- Analyzes a libgcj heap dump.
+ Copyright (C) 2007 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+package gnu.gcj.tools.gc_analyze;
+
+import gnu.classpath.tools.getopt.FileArgumentCallback;
+import gnu.classpath.tools.getopt.Option;
+import gnu.classpath.tools.getopt.OptionException;
+import gnu.classpath.tools.getopt.Parser;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+class MemoryAnalyze
+{
+ public MemoryAnalyze()
+ {
+ }
+
+ private static NumberFormat numberFormat;
+ private static boolean verbose;
+ static String format(long number, int digits)
+ {
+ if (numberFormat == null)
+ {
+ numberFormat = NumberFormat.getNumberInstance();
+ numberFormat.setGroupingUsed(true);
+ }
+ String temp = numberFormat.format(number);
+ int spaces = digits - temp.length();
+ if (spaces < 0)
+ spaces = 0;
+ return " ".substring(0,spaces) + temp;
+ }
+
+ static void sorted_report(String description,
+ int total_space,
+ ArrayList<String> list,
+ Comparator<String> comparator)
+ {
+ System.out.println("*** " + description + " ***");
+ System.out.println();
+ System.out.println(" Total Size Count Size Description");
+ System.out.println("-------------- ----- -------- -----------------------------------");
+ Collections.sort(list, comparator);
+ for (Iterator it = list.iterator(); it.hasNext(); )
+ {
+ String v = (String)it.next();
+ System.out.println(stripend(v));
+ }
+ System.out.println("-------------- ----- -------- -----------------------------------");
+ System.out.println(format(total_space, 14));
+ System.out.println();
+ System.out.println();
+ }
+
+ private static String stripend(String s)
+ {
+ int n = s.lastIndexOf(" /");
+ if (n > 0)
+ return s.substring(0,n);
+ return s;
+ }
+
+ static class SubstringComparator implements Comparator<String>
+ {
+ private int begin, end;
+ private boolean reverse;
+
+ SubstringComparator(int begin, int end, boolean reverse)
+ {
+ this.begin = begin;
+ this.end = end;
+ this.reverse = reverse;
+ }
+
+ public int compare(String s1, String s2)
+ {
+ if (end == 0)
+ s1 = s1.substring(begin);
+ else
+ s1 = s1.substring(begin, end);
+
+ if (end == 0)
+ s2 = s2.substring(begin);
+ else
+ s2 = s2.substring(begin, end);
+ int i = s1.compareTo(s2);
+ if (reverse)
+ return -i;
+ return i;
+ }
+ }
+
+ static class OptionParser extends Parser
+ {
+ int filesFound;
+
+ OptionParser()
+ {
+ super("gc-analyze",
+ "gc-analyze (" + System.getProperty("java.vm.version") + ")");
+
+ add(new Option('d',
+ "Directory containing runtime objects",
+ "directory")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ToolPrefix.pathPrefix = argument;
+ }
+ });
+
+ add(new Option('p',
+ "Binary tool prefix, prepended to nm and readelf to "
+ + "obtain target specific versions of these commands",
+ "prefix")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ ToolPrefix.toolPrefix = argument;
+ }
+ });
+
+ add(new Option("verbose", 'v',
+ "Verbose output; requires filename.bytes")
+ {
+ public void parsed(String argument) throws OptionException
+ {
+ verbose = true;
+ }
+ });
+
+ setHeader("usage: gc-analyze [-v] [-p tool-prefix] [-d <directory>] "
+ + "filename");
+ }
+
+ protected void validate() throws OptionException
+ {
+ if (filesFound != 1)
+ throw new OptionException("Must specify exactly one filename");
+ }
+
+ public String[] parse(String[] inArgs)
+ {
+ final ArrayList<String> fileResult = new ArrayList<String>();
+ parse(inArgs, new FileArgumentCallback()
+ {
+ public void notifyFile(String fileArgument)
+ {
+ filesFound++;
+ fileResult.add(fileArgument);
+ }
+ });
+ return fileResult.toArray(new String[1]);
+ }
+ }
+
+ public static void main(String[] args)
+ {
+ class Info
+ {
+ int size;
+ int count;
+ }
+ int total_space = 0;
+
+ Parser optionParser = new OptionParser();
+
+ String rest[] = optionParser.parse(args);
+
+ String filename = rest[0];
+
+ try
+ {
+ BufferedReader reader =
+ new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
+ SymbolLookup lookup = new SymbolLookup(reader, filename + ".bytes");
+ ObjectMap objectMap = new ObjectMap(reader);
+ BlockMap blockMap = new BlockMap(reader);
+ reader.close();
+
+ // add info to item(s)
+ // add item.klass
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ ObjectMap.ObjectItem item = me.getValue();
+
+ // try to get a klass (happens with intern'ed strings...)
+ if (item.klass==0)
+ {
+ BytePtr p = lookup.getBytePtr(item.ptr, item.size);
+ if (p!=null)
+ {
+ long vtable = p.getWord(0);
+ String sym =
+ lookup.getSymbolViaVtable(vtable - 2 * lookup.memoryMap.wordSize);
+ if (sym != null)
+ {
+ item.typeName = SymbolTable.demangleVTName(sym);
+ }
+ else if (vtable != 0)
+ {
+ // get klass from vtable
+ p = lookup.getBytePtr(vtable,
+ lookup.memoryMap.wordSize);
+ if (p != null)
+ {
+ long klass = p.getWord(0);
+ item.klass = klass;
+ }
+ }
+ }
+ }
+
+ // figure out strings
+ String class_name;
+ if (null == item.typeName)
+ {
+ class_name =
+ MemoryAnalyze.getSymbolPretty(lookup, item, false);
+ item.typeName = class_name;
+ }
+ else
+ {
+ class_name = item.typeName;
+ }
+ System.out.print("class_name=[" + class_name + "]");
+
+ if (class_name.compareTo("_ZTVN4java4lang6StringE")==0
+ || class_name.compareTo("java.lang.String")==0)
+ {
+ BytePtr p = lookup.getBytePtr(item.ptr, item.size);
+ long data = p.getWord(1);
+ int boffset = p.getInt(2 * p.intsPerWord());
+ int count = p.getInt(1 + 2 * p.intsPerWord());
+ int hash = p.getInt(2 + 2 * p.intsPerWord());
+ BytePtr chars = lookup.getBytePtr(data+boffset, count * 2);
+ StringBuffer sb = new StringBuffer(count);
+ for (int qq = 0; qq<count; qq++)
+ sb.append((char)chars.getShort(qq));
+ int newhash = sb.toString().hashCode();
+ if (newhash!=hash)
+ {
+ p.setInt(4, newhash);
+ }
+
+ item.string = sb.toString();
+ System.out.println(" value = \"" + item.string + "\"");
+ if (data != item.ptr)
+ {
+ ObjectMap.ObjectItem next = objectMap.get(data);
+ if (next != null)
+ next.stringData = true;
+ else
+ System.out.println("String [" + item.string + "] at "
+ + Long.toHexString(item.ptr)
+ + " can't find array at "
+ + Long.toHexString(data));
+ }
+ }
+ else if (null != item.string)
+ System.out.println(" value = \"" + item.string + "\"");
+ else
+ System.out.println();
+ }
+
+
+ HashMap<String, Info> map = new HashMap<String, Info>();
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ ObjectMap.ObjectItem item = me.getValue();
+ String name = getSymbolPretty(lookup, item, true);
+ Info info = map.get(name);
+ if (info == null)
+ {
+ info = new Info();
+ info.count = 0;
+ info.size = item.size;
+ map.put(name, info);
+ }
+ info.count++;
+ total_space += item.size;
+ }
+
+ ArrayList<String> list = new ArrayList<String>();
+ for (Iterator it = map.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry me = (Map.Entry)it.next();
+ String name = (String)me.getKey();
+ Info info = (Info)me.getValue();
+
+ StringBuffer sb = new StringBuffer();
+ sb.append(format(info.count * info.size * 100 / total_space,
+ 3));
+ sb.append("%");
+ sb.append(format(info.count * info.size, 10));
+ sb.append(" = ");
+ sb.append(format(info.count, 7));
+ sb.append(" * ");
+ sb.append(format(info.size, 9));
+ sb.append(" - ");
+ sb.append(name);
+ list.add(sb.toString());
+ }
+
+ sorted_report("Memory Usage Sorted by Total Size",
+ total_space, list, new SubstringComparator(5,14,true));
+ sorted_report("Memory Usage Sorted by Description",
+ total_space, list, new SubstringComparator(39,0,false));
+ sorted_report("Memory Usage Sorted by Count",
+ total_space, list, new SubstringComparator(17,25,true));
+ sorted_report("Memory Usage Sorted by Size",
+ total_space, list, new SubstringComparator(28,37,true));
+
+ blockMap.dump();
+
+ // dump raw memory
+ if (verbose)
+ {
+ // analyze references
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ long ptr = me.getKey();
+ ObjectMap.ObjectItem item = me.getValue();
+ BytePtr p = lookup.getBytePtr(ptr, item.size);
+ if (p == null)
+ System.out.println("can't find ptr 0x"
+ + Long.toHexString(ptr));
+ else if (item.kind != 0) // not GC_PTRFREE
+ for (int i = 1;
+ i < item.size / lookup.memoryMap.wordSize; i++)
+ {
+ long maybe_ptr = p.getWord(i);
+ ObjectMap.ObjectItem item2 = objectMap.get(maybe_ptr);
+ if (item2 != null)
+ {
+ item2.pointed_by.add(item);
+ item.points_to.add(item2);
+ }
+ }
+ }
+ System.out.println();
+ System.out.println("*** All Objects ***");
+ System.out.println();
+
+ for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
+ {
+ long ptr = me.getKey();
+ ObjectMap.ObjectItem item = me.getValue();
+ String name = getSymbolPretty(lookup, item, false);
+ System.out.print("0x" + Long.toHexString(ptr) + " - " + name
+ + " (" + item.size + ")");
+ if (item.string != null)
+ System.out.println(" \"" + item.string + "\"");
+ else
+ System.out.println();
+
+ BytePtr p = lookup.getBytePtr(ptr, item.size);
+
+ if (p == null)
+ System.out.println(
+ "can't find memory; recently allocated from free list?");
+ else
+ p.dump();
+
+ item.points_to.dump(" points to:", lookup);
+ item.pointed_by.dump(" pointed to by:", lookup);
+ System.out.println();
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static String kindToName(int kind)
+ {
+ String name;
+ switch (kind)
+ {
+ case 0:
+ name = "GC_PTRFREE";
+ break;
+ case 1:
+ name = "GC_NORMAL";
+ break;
+ case 2:
+ name = "GC_UNCOLLECTABLE";
+ break;
+ case 3:
+ name = "GC_AUUNCOLLCTABLE";
+ break;
+ case 4:
+ name = "(Java)";
+ break;
+ case 5:
+ name = "(Java Debug)";
+ break;
+ case 6:
+ name = "(Java Array)";
+ break;
+ default:
+ name = "(Kind " + kind + ")";
+ break;
+ }
+ return name;
+ }
+
+ public static String getSymbolPretty(SymbolLookup lookup,
+ ObjectMap.ObjectItem item,
+ boolean bsize)
+ throws IOException
+ {
+
+ String name = item.typeName;
+
+ if (name == null)
+ name = lookup.getSymbol(item.klass);
+
+ if (name == null)
+ {
+ String v = lookup.decodeUTF8(item.ptr, item.size);
+ if (null != v)
+ {
+ name = "UTF8Const";
+ item.string = v;
+ }
+ }
+
+ if (name == null)
+ {
+ name = kindToName(item.kind);
+ }
+ if (item.kind==6)
+ name += "[" + format(item.data, 0) + "]";
+ if (bsize)
+ name = name + " / " + format(item.size, 7);
+ return name;
+ }
+}