OSDN Git Service

gcc/java:
[pf3gnuchains/gcc-fork.git] / libjava / gnu / gcj / tools / gc_analyze / MemoryAnalyze.java
1 /* MemoryAnalyze.java -- Analyzes a libgcj heap dump.
2    Copyright (C) 2007  Free Software Foundation
3
4    This file is part of libgcj.
5
6 This software is copyrighted work licensed under the terms of the
7 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
8 details.  */
9
10 package gnu.gcj.tools.gc_analyze;
11
12 import gnu.classpath.tools.getopt.FileArgumentCallback;
13 import gnu.classpath.tools.getopt.Option;
14 import gnu.classpath.tools.getopt.OptionException;
15 import gnu.classpath.tools.getopt.Parser;
16
17 import java.io.BufferedReader;
18 import java.io.FileInputStream;
19 import java.io.IOException;
20 import java.io.InputStreamReader;
21 import java.text.NumberFormat;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.Map;
28
29 class MemoryAnalyze
30 {
31   public MemoryAnalyze()
32   {
33   }
34
35   private static NumberFormat numberFormat;
36   private static boolean verbose;
37   static String format(long number, int digits)
38   {
39     if (numberFormat == null)
40       {
41         numberFormat = NumberFormat.getNumberInstance();
42         numberFormat.setGroupingUsed(true);
43       }
44     String temp = numberFormat.format(number);
45     int spaces = digits - temp.length();
46     if (spaces < 0)
47       spaces = 0;
48     return "                                ".substring(0,spaces) + temp;
49   }
50
51   static void sorted_report(String description,
52                             int total_space,
53                             ArrayList<String> list,
54                             Comparator<String> comparator)
55   {
56     System.out.println("*** " + description + " ***");
57     System.out.println();
58     System.out.println("  Total Size       Count       Size    Description");
59     System.out.println("--------------     -----    --------   -----------------------------------");
60     Collections.sort(list, comparator);
61     for (Iterator it = list.iterator(); it.hasNext(); )
62       {
63         String v = (String)it.next();
64         System.out.println(stripend(v));
65       }
66     System.out.println("--------------     -----    --------   -----------------------------------");
67     System.out.println(format(total_space, 14));
68     System.out.println();
69     System.out.println();
70   }
71
72   private static String stripend(String s)
73   {
74     int n = s.lastIndexOf(" /");
75     if (n > 0)
76       return s.substring(0,n);
77     return s;
78   }
79
80   static  class SubstringComparator implements Comparator<String>
81   {
82     private int begin, end;
83     private boolean reverse;
84
85     SubstringComparator(int begin, int end, boolean reverse)
86     {
87       this.begin = begin;
88       this.end = end;
89       this.reverse = reverse;
90     }
91
92     public int compare(String s1, String s2)
93     {
94       if (end == 0)
95         s1 = s1.substring(begin);
96       else
97         s1 = s1.substring(begin, end);
98
99       if (end == 0)
100         s2 = s2.substring(begin);
101       else
102         s2 = s2.substring(begin, end);
103       int i = s1.compareTo(s2);
104       if (reverse)
105         return -i;
106       return i;
107     }
108   }
109
110   static class OptionParser extends Parser
111   {
112     int filesFound;
113           
114     OptionParser()
115     {
116       super("gc-analyze",
117             "gc-analyze (" + System.getProperty("java.vm.version") + ")");
118
119       add(new Option('d',
120                      "Directory containing runtime objects",
121                      "directory")
122         {
123           public void parsed(String argument) throws OptionException
124           {
125             ToolPrefix.pathPrefix = argument;                   
126           }
127         });
128
129       add(new Option('p',
130                      "Binary tool prefix, prepended to nm and readelf to "
131                      + "obtain target specific versions of these commands",
132                      "prefix")
133         {
134           public void parsed(String argument) throws OptionException
135           {
136             ToolPrefix.toolPrefix = argument;                   
137           }
138         });
139
140       add(new Option("verbose", 'v',
141                      "Verbose output; requires filename.bytes")
142         {
143           public void parsed(String argument) throws OptionException
144           {
145             verbose = true;                     
146           }
147         });
148
149       setHeader("usage: gc-analyze [-v] [-p tool-prefix] [-d <directory>] "
150                 + "filename");
151     }
152           
153     protected void validate() throws OptionException
154     {
155       if (filesFound != 1)
156         throw new OptionException("Must specify exactly one filename");
157     }
158           
159     public String[] parse(String[] inArgs)
160     {
161       final ArrayList<String> fileResult = new ArrayList<String>();
162       parse(inArgs, new FileArgumentCallback()
163         {
164           public void notifyFile(String fileArgument)
165           {
166             filesFound++;
167             fileResult.add(fileArgument);
168           }
169         });
170       return fileResult.toArray(new String[1]);
171     }
172   }
173   
174   public static void main(String[] args)
175   {
176     class Info
177     {
178       int size;
179       int count;
180     }
181     int total_space = 0;
182
183     Parser optionParser = new OptionParser();
184     
185     String rest[] = optionParser.parse(args);
186     
187     String filename = rest[0];
188     
189     try
190       {
191         BufferedReader reader =
192           new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
193         SymbolLookup lookup = new SymbolLookup(reader, filename + ".bytes");
194         ObjectMap objectMap = new ObjectMap(reader);
195         BlockMap blockMap = new BlockMap(reader);
196         reader.close();
197
198         // add info to item(s)
199         // add item.klass
200         for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
201         {
202             ObjectMap.ObjectItem item = me.getValue();
203
204             // try to get a klass (happens with intern'ed strings...)
205             if (item.klass==0)
206               {
207                 BytePtr p = lookup.getBytePtr(item.ptr, item.size);
208                 if (p!=null)
209                   {
210                     long vtable = p.getWord(0);
211                     String sym =
212                         lookup.getSymbolViaVtable(vtable - 2 * lookup.memoryMap.wordSize);
213                     if (sym != null)
214                       {
215                         item.typeName = SymbolTable.demangleVTName(sym);
216                       }
217                     else if (vtable != 0)
218                       {
219                         // get klass from vtable
220                         p = lookup.getBytePtr(vtable,
221                                               lookup.memoryMap.wordSize);
222                         if (p != null)
223                           {
224                             long klass = p.getWord(0);
225                             item.klass = klass;
226                           }
227                       }
228                   }
229               }
230
231             // figure out strings
232             String class_name;
233             if (null == item.typeName)
234               {
235                 class_name =
236                   MemoryAnalyze.getSymbolPretty(lookup, item, false);
237                 item.typeName = class_name;
238               }
239             else
240               {
241                 class_name = item.typeName;
242               }
243             System.out.print("class_name=[" + class_name + "]");
244
245             if (class_name.compareTo("_ZTVN4java4lang6StringE")==0
246                 || class_name.compareTo("java.lang.String")==0)
247               {
248                 BytePtr p = lookup.getBytePtr(item.ptr, item.size);
249                 long data = p.getWord(1); 
250                 int boffset = p.getInt(2 * p.intsPerWord());
251                 int count = p.getInt(1 + 2 * p.intsPerWord());
252                 int hash = p.getInt(2 + 2 * p.intsPerWord());
253                 BytePtr chars = lookup.getBytePtr(data+boffset, count * 2);
254                 StringBuffer sb = new StringBuffer(count);
255                 for (int qq = 0; qq<count; qq++)
256                   sb.append((char)chars.getShort(qq));
257                 int newhash = sb.toString().hashCode();
258                 if (newhash!=hash)
259                   {
260                     p.setInt(4, newhash);
261                   }
262
263                 item.string = sb.toString();
264                 System.out.println(" value = \"" + item.string + "\"");
265                 if (data != item.ptr)
266                   {
267                     ObjectMap.ObjectItem next = objectMap.get(data);
268                     if (next != null)
269                       next.stringData = true;
270                     else
271                       System.out.println("String [" + item.string + "] at "
272                                          + Long.toHexString(item.ptr)
273                                          + " can't find array at " 
274                                          + Long.toHexString(data));
275                   }
276               }
277             else if (null != item.string)
278               System.out.println(" value = \"" + item.string + "\"");
279             else
280               System.out.println();
281           }
282
283
284         HashMap<String, Info> map = new HashMap<String, Info>();
285         for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
286           {
287             ObjectMap.ObjectItem item = me.getValue();
288             String name = getSymbolPretty(lookup, item, true);
289             Info info = map.get(name);
290             if (info == null)
291               {
292                 info = new Info();
293                 info.count = 0;
294                 info.size = item.size;
295                 map.put(name, info);
296               }
297             info.count++;
298             total_space += item.size;
299           }
300
301         ArrayList<String> list = new ArrayList<String>();
302         for (Iterator it = map.entrySet().iterator(); it.hasNext(); )
303           {
304             Map.Entry me = (Map.Entry)it.next();
305             String name = (String)me.getKey();
306             Info info = (Info)me.getValue();
307
308             StringBuffer sb = new StringBuffer();
309             sb.append(format(info.count * info.size * 100 / total_space,
310                              3));
311             sb.append("%");
312             sb.append(format(info.count * info.size, 10));
313             sb.append(" = ");
314             sb.append(format(info.count, 7));
315             sb.append(" * ");
316             sb.append(format(info.size, 9));
317             sb.append(" - ");
318             sb.append(name);
319             list.add(sb.toString());
320           }
321
322         sorted_report("Memory Usage Sorted by Total Size",
323                       total_space, list, new SubstringComparator(5,14,true));
324         sorted_report("Memory Usage Sorted by Description",
325                       total_space, list, new SubstringComparator(39,0,false));
326         sorted_report("Memory Usage Sorted by Count",
327                       total_space, list, new SubstringComparator(17,25,true));
328         sorted_report("Memory Usage Sorted by Size",
329                       total_space, list, new SubstringComparator(28,37,true));
330
331         blockMap.dump();
332
333         // dump raw memory
334         if (verbose)
335           {
336             // analyze references
337             for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
338               {
339                 long ptr = me.getKey();
340                 ObjectMap.ObjectItem item = me.getValue();
341                 BytePtr p = lookup.getBytePtr(ptr, item.size);
342                 if (p == null)
343                   System.out.println("can't find ptr 0x"
344                                      + Long.toHexString(ptr));
345                 else if (item.kind != 0) // not GC_PTRFREE
346                   for (int i = 1;
347                        i < item.size / lookup.memoryMap.wordSize; i++)
348                     {
349                       long maybe_ptr = p.getWord(i);
350                       ObjectMap.ObjectItem item2 = objectMap.get(maybe_ptr);
351                       if (item2 != null)
352                         {
353                           item2.pointed_by.add(item);
354                           item.points_to.add(item2);
355                         }
356                     }
357               }
358             System.out.println();
359             System.out.println("*** All Objects ***");
360             System.out.println();
361
362             for (Map.Entry<Long, ObjectMap.ObjectItem> me : objectMap)
363             {
364               long ptr = me.getKey();
365               ObjectMap.ObjectItem item = me.getValue();
366               String name = getSymbolPretty(lookup, item, false);
367               System.out.print("0x" + Long.toHexString(ptr) + " - " + name
368                                + " (" + item.size + ")");
369               if (item.string != null)
370                 System.out.println(" \"" + item.string + "\"");
371               else
372                 System.out.println();
373
374               BytePtr p = lookup.getBytePtr(ptr, item.size);
375
376               if (p == null)
377                 System.out.println(
378                   "can't find memory; recently allocated from free list?");
379               else
380                 p.dump();
381
382               item.points_to.dump("  points to:", lookup);
383               item.pointed_by.dump("  pointed to by:", lookup);
384               System.out.println();
385             }
386           }
387       }
388     catch (IOException e)
389       {
390         e.printStackTrace();
391       }
392   }
393
394   public static String kindToName(int kind)
395   {
396     String name;
397     switch (kind)
398       {
399       case 0:
400         name = "GC_PTRFREE";
401         break;
402       case 1:
403         name = "GC_NORMAL";
404         break;
405       case 2:
406         name = "GC_UNCOLLECTABLE";
407         break;
408       case 3:
409         name = "GC_AUUNCOLLCTABLE";
410         break;
411       case 4:
412         name = "(Java)";
413         break;
414       case 5:
415         name = "(Java Debug)";
416         break;
417       case 6:
418         name = "(Java Array)";
419         break;
420       default:
421         name = "(Kind " + kind + ")";
422         break;
423       }
424     return name;
425   }
426
427   public static String getSymbolPretty(SymbolLookup lookup,
428                                        ObjectMap.ObjectItem item,
429                                        boolean bsize)
430     throws IOException
431   {
432     
433     String name = item.typeName;
434     
435     if (name == null)
436       name = lookup.getSymbol(item.klass);
437     
438     if (name == null)
439       {
440         String v = lookup.decodeUTF8(item.ptr, item.size);
441         if (null != v)
442           {
443             name = "UTF8Const";
444             item.string = v;
445           }
446       }
447     
448     if (name == null)
449       {
450         name = kindToName(item.kind);
451       }
452     if (item.kind==6)
453       name += "[" + format(item.data, 0) + "]";
454     if (bsize)
455       name = name + " / " + format(item.size, 7);
456     return name;
457   }
458 }