1 | /* |
2 | * Copyright 2008 Eric Caspole |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this |
5 | * file except in compliance with the License. You may obtain a copy of the License at |
6 | * |
7 | * http://www.apache.org/licenses/LICENSE-2.0 |
8 | * |
9 | * Unless required by applicable law or agreed to in writing, software distributed under |
10 | * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
11 | * KIND, either express or implied. See the License for the specific language governing |
12 | * permissions and limitations under the License. |
13 | */ |
14 | package net.sf.madmap; |
15 | |
16 | import java.io.*; |
17 | import java.util.*; |
18 | import java.util.concurrent.*; |
19 | import java.util.concurrent.atomic.AtomicInteger; |
20 | import java.math.*; |
21 | import java.lang.management.*; |
22 | import javax.management.*; |
23 | import javax.swing.JOptionPane; |
24 | |
25 | /** |
26 | * |
27 | * HprofReader manages reading the hprof file using a thread pool of Workers. |
28 | * |
29 | * @author ecaspole |
30 | */ |
31 | public class HprofReader implements IHprofReader, HprofReaderMBean { |
32 | |
33 | ILogger _logger; |
34 | |
35 | static String objStart = new String( "O" ); |
36 | static String arrStart = new String( "A" ); |
37 | static String clsStart = new String( "CL" ); |
38 | |
39 | // MBean fields and methods |
40 | AtomicInteger _objects = new AtomicInteger(0); |
41 | AtomicInteger _arrays = new AtomicInteger(0); |
42 | AtomicInteger _classes = new AtomicInteger(0); |
43 | public int getCurrentObjects() { return _objects.get(); } |
44 | public int getCurrentArrays() { return _arrays.get(); } |
45 | public int getCurrentClasses() { return _classes.get(); } |
46 | public String getReaderName() { return "HprofReader:workers=" + MadmapMain.concurrency(); } |
47 | |
48 | public HprofReader() { } |
49 | |
50 | public void setLogger( ILogger logger ) { _logger = logger; } |
51 | |
52 | public static FileInputStream openHprofFile(String fileName) |
53 | { |
54 | FileInputStream fis; |
55 | |
56 | try { |
57 | fis = new FileInputStream( fileName ); |
58 | return fis; |
59 | } catch ( Exception ie ) { |
60 | System. out. println ( "Error opening file : Caught " + ie ); |
61 | ie.printStackTrace(); |
62 | } |
63 | return null; |
64 | } |
65 | |
66 | public void parse( Madmap owner, String fileName) { |
67 | long fileSize = 0; |
68 | |
69 | try { |
70 | File fi = new File( fileName ); |
71 | fileSize = fi.length(); |
72 | if ( MadmapMain.verbose() ) { |
73 | _logger.myLog( owner.getWindow(), "Total file length of " + fileName + " is " + fileSize ); |
74 | } |
75 | } catch ( Exception ie ) { |
76 | System. out. println ( "Error opening file : Caught " + ie ); |
77 | ie.printStackTrace(); |
78 | } |
79 | |
80 | long stripeWidth = fileSize / MadmapMain.concurrency(); |
81 | if ( MadmapMain.verbose() ) { |
82 | _logger.myLog( owner.getWindow(), "Stripe width is " + stripeWidth ); |
83 | _logger.myLog( owner.getWindow(), "Going to run with " + MadmapMain.concurrency() + ( MadmapMain.concurrency() == 1 ? " thread" : " threads" )); |
84 | } |
85 | |
86 | try { |
87 | ExecutorService tpe = Executors.newFixedThreadPool( MadmapMain.concurrency() ); |
88 | for ( int i = 0; i < MadmapMain.concurrency(); i ++ ) { |
89 | tpe.execute( new Worker( owner, i, openHprofFile(fileName), i * stripeWidth, stripeWidth ) ); |
90 | } |
91 | // Shutdown input on the thread queue and wait for the jobs to complete |
92 | tpe.shutdown(); |
93 | tpe.awaitTermination(9999, TimeUnit.SECONDS); |
94 | } catch ( InterruptedException ie ) { |
95 | System. out. println ( "*** InterruptedException happened 2" ); |
96 | } |
97 | } |
98 | |
99 | /** |
100 | * Workers read the hprof file in 1 or more chunks based on the available |
101 | * concurrency. |
102 | * |
103 | * @author ecaspole |
104 | */ |
105 | private class Worker implements Runnable { |
106 | |
107 | Madmap _owner = null; |
108 | |
109 | ConcurrentHashMap<HprofHeapAllocation,HprofHeapAllocation> _heap_objects_table = null; |
110 | ConcurrentHashMap _stack_trace_table = null; |
111 | ConcurrentHashMap _threads_list = null; |
112 | Vector _roots_list = null; |
113 | ConcurrentHashMap _class_list = null; |
114 | |
115 | boolean _verbose = false; |
116 | |
117 | public void dumpObjectsTable() { _heap_objects_table = null; } |
118 | |
119 | public ConcurrentHashMap getStackTraces() { return _stack_trace_table; } |
120 | public ConcurrentHashMap getThreads() { return _threads_list; } |
121 | public Vector getRoots() { return _roots_list; } |
122 | public ConcurrentHashMap getClasses() { return _class_list; } |
123 | |
124 | FileInputStream _fis; |
125 | LineNumberReader _bfr; |
126 | int _readerId; |
127 | long _startOffset; |
128 | long _estimatedCompletionLine; |
129 | |
130 | String _pushed_string = null; |
131 | int _linesSeen = 0; |
132 | long _startTime = 0; |
133 | |
134 | org.apache.regexp.RE thread_start_re = new org.apache.regexp.RE( "THREAD START .*" ); |
135 | org.apache.regexp.RE thread_end_re = new org.apache.regexp.RE( "THREAD END .*" ); |
136 | org.apache.regexp.RE stack_trace_re = new org.apache.regexp.RE( "^TRACE ([0-9]*):" ); |
137 | org.apache.regexp.RE obj_start_re = new org.apache.regexp.RE( "^OBJ .*" ); |
138 | org.apache.regexp.RE array_start_re = new org.apache.regexp.RE( "^ARR .*" ); |
139 | |
140 | org.apache.regexp.RE thread_start_obj = new org.apache.regexp.RE( "obj=([0-9A-Za-z]*),.*" ); |
141 | org.apache.regexp.RE thread_start_id = new org.apache.regexp.RE( "id = ([0-9 ]*),.*" ); |
142 | org.apache.regexp.RE thread_start_name = new org.apache.regexp.RE( "name=(.*),.*" ); |
143 | org.apache.regexp.RE thread_start_group = new org.apache.regexp.RE( "group=(\".*\")" ); |
144 | |
145 | org.apache.regexp.RE _stack_trace_title_re = new org.apache.regexp.RE( "^TRACE ([0-9]*):" ); |
146 | org.apache.regexp.RE _stack_trace_item_re = new org.apache.regexp.RE( "\t(.*)" ); |
147 | |
148 | org.apache.regexp.RE _heap_dump_begin_re = new org.apache.regexp.RE( "^HEAP DUMP BEGIN " ); |
149 | org.apache.regexp.RE _heap_dump_objects_re = new org.apache.regexp.RE( "([0-9]*) objects, " ); |
150 | org.apache.regexp.RE _heap_dump_bytes_re = new org.apache.regexp.RE( ", ([0-9]*) bytes" ); |
151 | org.apache.regexp.RE _heap_dump_end_re = new org.apache.regexp.RE( "^HEAP DUMP END" ); |
152 | |
153 | org.apache.regexp.RE _root_begin_re = new org.apache.regexp.RE( "^ROOT ([0-9A-Za-z]*) " ); |
154 | org.apache.regexp.RE _root_kind_re = new org.apache.regexp.RE( "kind=([0-9A-Za-z -<>]*), " ); |
155 | org.apache.regexp.RE _root_kind_unknown_re = new org.apache.regexp.RE( "kind=<unknown>" ); |
156 | org.apache.regexp.RE _root_kind_busymon_re = new org.apache.regexp.RE( "kind=<busy monitor>" ); |
157 | org.apache.regexp.RE _root_classname_re = new org.apache.regexp.RE( " name=([0-9A-Za-z.$]*)" ); |
158 | org.apache.regexp.RE _root_id_re = new org.apache.regexp.RE( "id=(.*), " ); |
159 | org.apache.regexp.RE _root_trace_re = new org.apache.regexp.RE( "trace= ([0-9]*)" ); |
160 | |
161 | org.apache.regexp.RE _obj_all_re = new org.apache.regexp.RE( "^OBJ ([0-9A-Za-z]*) [:punct:]sz=([0-9]*), trace=([0-9]*), class=([0-9A-Za-z_.$]*)@([0-9a-f]*)" ); |
162 | org.apache.regexp.RE _obj_member_both_re = new org.apache.regexp.RE( "^\t([0-9A-Za-z_$]*)[ \t]+([0-9A-Za-z_]*)" ); |
163 | |
164 | // This one for class types |
165 | org.apache.regexp.RE _arr_type_both_re = new org.apache.regexp.RE( "elem type=(.*)@([0-9A-Za-z]*)" ); |
166 | |
167 | // This one for basic type arrays |
168 | org.apache.regexp.RE _arr_type_re2 = new org.apache.regexp.RE( "elem type=(.*)[:punct:]" ); |
169 | |
170 | org.apache.regexp.RE _arr_elem_both_re = new org.apache.regexp.RE( "^\t([:punct:][0-9]+[:punct:])[\t ]+([0-9A-Za-z]+)" ); |
171 | |
172 | //org.apache.regexp.RE _arr_data_re = new org.apache.regexp.RE( "sz=([0-9]*), trace=([0-9]*), nelems=([0-9A-Za-z]*), " ); |
173 | org.apache.regexp.RE _arr_all_re = new org.apache.regexp.RE( "^ARR ([0-9A-Za-z]*) [:punct:]sz=([0-9]*), trace=([0-9]*), nelems=([0-9A-Za-z]*), " ); |
174 | |
175 | org.apache.regexp.RE _cls_super_re = new org.apache.regexp.RE( "^\tsuper[ \t]+([0-9A-Za-z]*)" ); |
176 | org.apache.regexp.RE _cls_loader_re = new org.apache.regexp.RE( "^\tloader[ \t]+([0-9A-Za-z]*)" ); |
177 | org.apache.regexp.RE _cls_static_name_re = new org.apache.regexp.RE( "^\tstatic ([0-9_A-Za-z.$]*)" ); |
178 | org.apache.regexp.RE _cls_static_addr_re = new org.apache.regexp.RE( "^\tstatic [0-9_A-Za-z.$]+[\t]+([0-9a-f]*)" ); |
179 | //org.apache.regexp.RE _cls_data_re = new org.apache.regexp.RE( "name=(.*), trace=([0-9]*)" ); |
180 | org.apache.regexp.RE _cls_all_re = new org.apache.regexp.RE( "^CLS ([0-9A-Za-z]*) [:punct:]name=(.*), trace=([0-9]*)" ); |
181 | |
182 | |
183 | public void run() { |
184 | |
185 | int ln = 0; |
186 | |
187 | _startTime = System.currentTimeMillis(); |
188 | System. out. println ( "Moving to start position " + _startOffset ); |
189 | |
190 | try { |
191 | InputStreamReader isr; |
192 | _fis.skip( _startOffset ); |
193 | |
194 | isr = new InputStreamReader( _fis ); |
195 | _bfr = new LineNumberReader( isr ); |
196 | |
197 | } catch ( IOException ioe ) { |
198 | System. out. println ( "Exception while seeking to file start position..." ); |
199 | ioe.printStackTrace(); |
200 | } |
201 | |
202 | System. out. println ( "Loading file from start position " + _startOffset ); |
203 | |
204 | readAndProcessLines(-1); |
205 | long endMillis = System.currentTimeMillis(); |
206 | |
207 | System. out. println ( "Done Loading stripe from start position: " + _startOffset ); |
208 | System. out. println ( "Elapsed time: " + elapsedTime()); |
209 | } |
210 | |
211 | /** |
212 | * @param owner the Madmap document this Worker is working for |
213 | * @param id the id of this Worker |
214 | * @param rdr the FileInputStream to read from |
215 | * @param startPos the position to start from as computed by the HprofReader |
216 | * @param stripeWidth the number of bytes to be read, it is only used for |
217 | * progress messages. |
218 | */ |
219 | public Worker(Madmap owner, int id, FileInputStream rdr, long startPos, long stripeWidth) { |
220 | _startOffset = startPos; |
221 | _fis = rdr; |
222 | _owner = owner; |
223 | _readerId = id; |
224 | |
225 | // about 35 chars/line on average... |
226 | _estimatedCompletionLine = stripeWidth / 35; |
227 | if (( ! MadmapMain.noGUI()) && ( _readerId == 0 )) { |
228 | _owner.getWindow().getProgressBar().setMaximum((int)_estimatedCompletionLine); |
229 | _owner.getWindow().getLabelForProgressBar().setText("Loading File"); |
230 | } |
231 | System. out. println ( "HprofReader reader id = " + _readerId + " _estimatedCompletionLine " + _estimatedCompletionLine ); |
232 | |
233 | _heap_objects_table = owner.getObjects(); |
234 | _stack_trace_table = owner.getStackTraces(); |
235 | _threads_list = owner.getThreads(); |
236 | _roots_list = owner.getRoots(); |
237 | _class_list = owner.getClasses(); |
238 | } |
239 | |
240 | long[] longArrayListtoLongArray( ArrayList in ) { |
241 | long[] out = new long[ in.size() ]; |
242 | for ( int i = 0; i < out.length; i++ ) { |
243 | out[ i ] = ((Long) in.get( i )).longValue(); |
244 | } |
245 | return out; |
246 | } |
247 | |
248 | |
249 | public String matchAndGet( org.apache.regexp.RE active, String s) { |
250 | if ( active.match(s) == true ) { |
251 | return active.getParen( 1 ); |
252 | } else { |
253 | return null; |
254 | } |
255 | } |
256 | |
257 | public long convertAddrStringToLong( String s) { |
258 | return (new BigInteger( s, 16 )).longValue(); |
259 | } |
260 | |
261 | public void handleClass( String s ) { |
262 | String objstr = null; |
263 | String trcstr = null; |
264 | String clsstr = null; |
265 | String elem_name = null; |
266 | String elem_addr = null; |
267 | String sooper = null; |
268 | String loader = null; |
269 | String next = null; |
270 | ArrayList st_names = new ArrayList(); |
271 | ArrayList st_refs = new ArrayList(); |
272 | |
273 | if ( _cls_all_re.match( s ) ) { |
274 | objstr = _cls_all_re.getParen( 1 ); |
275 | clsstr = _cls_all_re.getParen( 2 ); |
276 | trcstr = _cls_all_re.getParen( 3 ); |
277 | } |
278 | clsstr = clsstr.intern(); |
279 | |
280 | int trcId = Integer.parseInt( trcstr, 10 ); |
281 | |
282 | try { |
283 | next = readNextLine(); |
284 | while (next != null) { |
285 | if ( _cls_super_re.match( next )) { |
286 | sooper = _cls_super_re.getParen( 1 ); |
287 | } else if ( _cls_loader_re.match( next )) { |
288 | loader = _cls_loader_re.getParen( 1 ); |
289 | } else if ( _cls_static_name_re.match( next )) { |
290 | elem_name = _cls_static_name_re.getParen( 1 ); |
291 | elem_name = elem_name.intern(); |
292 | st_names.add( elem_name ); |
293 | if ( _cls_static_addr_re.match( next ) ) { |
294 | elem_addr = _cls_static_addr_re.getParen( 1 ); |
295 | //st_refs.add( Long.parseLong( elem_addr, 16 ) ); |
296 | st_refs.add( convertAddrStringToLong( elem_addr ) ); |
297 | } |
298 | } else { |
299 | if (_verbose) { |
300 | System. out. println( "#### Class unmatched: " + objstr + " " + clsstr); |
301 | System. out. println( "#### Class unmatched: " + next); |
302 | } |
303 | break; |
304 | } |
305 | next = readNextLine(); |
306 | } |
307 | } catch ( Exception e ) { |
308 | System. out. println ( "handleClass : Caught " + e + " on line : " + s ); |
309 | System. out. println( "#### Class problem: s = " + s); |
310 | System. out. println( "#### Class problem: sooper = " + sooper); |
311 | System. out. println( "#### Class problem: loader = " + loader); |
312 | System. out. println( "#### Class problem: elem_name = " + elem_name); |
313 | e. printStackTrace(); |
314 | System.exit( -1 ); |
315 | } |
316 | |
317 | if ( next != null) { |
318 | pushBack( next ); |
319 | } |
320 | |
321 | //long addr = Long.parseLong( objstr, 16 ); |
322 | long addr = convertAddrStringToLong( objstr ); |
323 | |
324 | long sooper_addr = 0; |
325 | long loader_addr = 0; |
326 | if ( sooper != null ) { |
327 | //sooper_addr = Long.parseLong( sooper, 16 ); |
328 | sooper_addr = convertAddrStringToLong( sooper ); |
329 | } |
330 | if ( loader != null ) { |
331 | //loader_addr = Long.parseLong( loader, 16 ); |
332 | loader_addr = convertAddrStringToLong( loader ); |
333 | } |
334 | |
335 | // see if this class is already added... |
336 | HprofClassElement cls = (HprofClassElement) _class_list.get( new HprofHeapElement(addr) ); |
337 | if ( cls != null ) { |
338 | //assert clsstr.equals( cls.className() ) : "Classes are messed up" ; |
339 | if ( ! clsstr.equals( cls.className() ) ) { |
340 | System.out.println( "### Classes are messed up: " + clsstr + " != " + cls.className() ); |
341 | } |
342 | |
343 | cls.completeClass( clsstr, trcId, sooper_addr, loader_addr, st_names, st_refs ); |
344 | } else { |
345 | if ( _verbose ) { |
346 | System. out. println( "#### Adding Class class with no instances: " + clsstr); |
347 | } |
348 | cls = new HprofClassElement( addr, clsstr, trcId, sooper_addr, loader_addr, st_names, st_refs ); |
349 | _class_list.put(cls, cls); |
350 | _classes.incrementAndGet(); |
351 | } |
352 | } |
353 | |
354 | |
355 | public int handleArray( String s ) { |
356 | String objstr = null; |
357 | String trcstr = null; |
358 | String szstr = null; |
359 | String nelemstr = null; |
360 | String idstr = null; |
361 | String elem_idx; |
362 | String elem_addr; |
363 | String next = null; |
364 | ArrayList elems = new ArrayList(); |
365 | long cls_addr = 0; |
366 | |
367 | if ( _arr_all_re.match( s ) ) { |
368 | objstr = _arr_all_re.getParen( 1 ); |
369 | szstr = _arr_all_re.getParen( 2 ); |
370 | trcstr = _arr_all_re.getParen( 3 ); |
371 | nelemstr = _arr_all_re.getParen( 4 ); |
372 | } |
373 | |
374 | int trcId = Integer.parseInt( trcstr, 10 ); |
375 | |
376 | String clsstr = null; |
377 | HprofClassElement k = null; |
378 | |
379 | if ( _arr_type_both_re.match( s ) ) { |
380 | // it is a class array with a class addr |
381 | clsstr = _arr_type_both_re.getParen( 1 ); |
382 | idstr = _arr_type_both_re.getParen( 2 ); |
383 | //cls_addr = Long.parseLong( idstr, 16 ); |
384 | cls_addr = convertAddrStringToLong( idstr ); |
385 | |
386 | // intern here for pointer equality test and it helps with footprint reduction |
387 | clsstr = clsstr.intern(); |
388 | |
389 | // It could be a basic type array denoted like "elem type=[B@570006b0" |
390 | if ( MadmapMain.jdk14_compatible() ) { |
391 | if (( clsstr.charAt( 0 ) == '[' ) && ( clsstr.charAt( 1 ) != 'L' ) && ( clsstr.charAt( 1 ) != '[' )) { |
392 | k = Madmap.getFakeArrayClass( clsstr ); |
393 | //} else if ((( clsstr.charAt( 0 ) == '[' ) && ( clsstr.charAt( 1 ) == 'L' )) || ( clsstr.charAt( 0 ) == 'L' )) { |
394 | } else { |
395 | // It is an array-of-objects type or multi-dimensional array, |
396 | // add the class if not already added. |
397 | // This is similar to HprofObject.findOrCreateClass() but arrays |
398 | // don't have nonstatic fields to record |
399 | k = (HprofClassElement)(_owner.getClasses()).get( new HprofHeapElement(cls_addr) ); |
400 | if ( k == null ) { |
401 | k = new HprofClassElement( cls_addr, clsstr ); |
402 | _owner.getClasses().put( k, k ); |
403 | //System.out.println( "### Added object type array: " + clsstr + "@" + idstr ); |
404 | } |
405 | |
406 | // Add a class for the array-of-objects type |
407 | // Use 1 - cls_addr as the class addr for this fake class, I think it is unlikely |
408 | // to collide with another class |
409 | long arrayKlassAddr = 1 - cls_addr; |
410 | |
411 | // See if it is already added |
412 | HprofClassElement ak = (HprofClassElement)(_owner.getClasses()).get( new HprofHeapElement(arrayKlassAddr) ); |
413 | if ( ak == null ) { |
414 | // Add the klass right now |
415 | String arrayKlassName = new String( "[Array type]" + clsstr ); |
416 | arrayKlassName = arrayKlassName.intern(); |
417 | ak = new HprofClassElement( arrayKlassAddr, arrayKlassName ); |
418 | _owner.getClasses().put( ak, ak ); |
419 | //System.out.println( "### Added object array klass: " + arrayKlassName + "@" + Long.toHexString( arrayKlassAddr )); |
420 | } |
421 | |
422 | // Record the array objects with its true array-of-objects type |
423 | k = ak; |
424 | } |
425 | } |
426 | } else { |
427 | // it is a basic type array with no class addr |
428 | clsstr = matchAndGet( _arr_type_re2, s ); |
429 | // intern here for pointer equality test and it helps with footprint reduction |
430 | clsstr = clsstr.intern(); |
431 | k = Madmap.getFakeArrayClass( clsstr ); |
432 | } |
433 | |
434 | next = readNextLine(); |
435 | |
436 | while ((next != null) && ( next.startsWith( "\t" ))) { |
437 | // skip the leading tab |
438 | String fields = next.substring( 1 ); |
439 | |
440 | int len = 0; |
441 | while ( fields.charAt( len ) != '\t' ) { |
442 | len++; |
443 | } |
444 | |
445 | // skip tabs in between name and addr |
446 | while ( fields.charAt( len ) == '\t' ) { |
447 | len++; |
448 | } |
449 | String faddr = fields.substring( len ); |
450 | elems.add( convertAddrStringToLong( faddr ) ); |
451 | |
452 | next = readNextLine(); |
453 | } |
454 | |
455 | if ( next != null) { |
456 | pushBack( next ); |
457 | } |
458 | |
459 | long addr = convertAddrStringToLong( objstr ); |
460 | long nelems = Long.parseLong( nelemstr, 10 ); // base 10 |
461 | long size = Long.parseLong( szstr, 10 ); // base 10 |
462 | |
463 | HprofHeapCollectable testObj = (HprofHeapCollectable) _heap_objects_table.get( new HprofHeapElement(addr) ); |
464 | if ( testObj != null ) { |
465 | return -1; |
466 | } |
467 | |
468 | HprofArrayObject arr = new HprofArrayObject( addr, clsstr, trcId, size, nelems, k, elems ); |
469 | _heap_objects_table.put( arr, arr ); |
470 | _arrays.incrementAndGet(); |
471 | return 0; |
472 | } |
473 | |
474 | HprofClassElement findOrCreateClass( String klass, long klass_addr, long size, ArrayList field_names ) { |
475 | |
476 | assert size != 0 : "size should not be 0" ; |
477 | |
478 | HprofClassElement k = (HprofClassElement) getClasses().get( new HprofHeapElement(klass_addr) ); |
479 | if ( k == null ) { |
480 | // Add the klass right now |
481 | k = new HprofClassElement( klass_addr, klass, size ); |
482 | getClasses().put( k, k ); |
483 | } else { |
484 | assert k.addr() == klass_addr : "klass addr is wrong" ; |
485 | |
486 | // instance size will be 0 if the class was created during |
487 | // loading an array of objects of this type |
488 | if ( k.instanceSize() == 0 ) { |
489 | k.updateInstanceSize(size); |
490 | } |
491 | } |
492 | |
493 | return k; |
494 | } |
495 | |
496 | public int handleObject( String s ) { |
497 | //String objstr = matchAndGet( _obj_begin_re, s ); |
498 | String objstr = null; |
499 | String trcstr = null; |
500 | String clsstr = null; |
501 | String clsaddrstr = null; |
502 | String szstr = null; |
503 | String elem = null; |
504 | String id = null; |
505 | String next = null; |
506 | ArrayList elem_ids = new ArrayList(); |
507 | ArrayList elem_names = new ArrayList(); |
508 | |
509 | if ( _obj_all_re.match( s ) ) { |
510 | objstr = _obj_all_re.getParen( 1 ); |
511 | szstr = _obj_all_re.getParen( 2 ); |
512 | trcstr = _obj_all_re.getParen( 3 ); |
513 | clsstr = _obj_all_re.getParen( 4 ); |
514 | clsaddrstr = _obj_all_re.getParen( 5 ); |
515 | } |
516 | |
517 | clsstr = clsstr.intern(); |
518 | next = readNextLine(); |
519 | int trcId = Integer.parseInt( trcstr, 10 ); |
520 | |
521 | while ((next != null) && ( next.startsWith( "\t" ))) { |
522 | // skip the leading tab |
523 | String fields = next.substring( 1 ); |
524 | |
525 | int len = 0; |
526 | while ( fields.charAt( len ) != '\t' ) { |
527 | len++; |
528 | } |
529 | |
530 | String fname = fields.substring( 0, len ); |
531 | fname = fname.intern(); |
532 | elem_names.add( fname ); |
533 | // skip tabs in between name and addr |
534 | while ( fields.charAt( len ) == '\t' ) { |
535 | len++; |
536 | } |
537 | String faddr = fields.substring( len ); |
538 | elem_ids.add( convertAddrStringToLong( faddr ) ); |
539 | |
540 | next = readNextLine(); |
541 | } |
542 | |
543 | if ( next != null) { |
544 | pushBack( next ); |
545 | } |
546 | |
547 | if ( clsaddrstr == null ) { |
548 | System. out. println( "#### Object clsaddrstr is null: " + objstr); |
549 | } |
550 | |
551 | long addr = convertAddrStringToLong( objstr ); |
552 | |
553 | HprofHeapCollectable testObj = (HprofHeapCollectable) _heap_objects_table.get( new HprofHeapElement(addr) ); |
554 | if ( testObj != null ) { |
555 | // debug 080527 |
556 | //System. out. println( "#### #################################################: "); |
557 | //System. out. println( "#### handleObject Found object already in table: " + Long.toHexString(addr)); |
558 | //System. out. println( "#### handleObject started with: " + s); |
559 | //testObj.print(); |
560 | return -1; |
561 | } |
562 | |
563 | long cls_addr = convertAddrStringToLong( clsaddrstr ); |
564 | long size = Long.parseLong( szstr, 10 ); |
565 | |
566 | if ( ! MadmapMain.getSaveMemberNames() ) { |
567 | elem_names = null; |
568 | } |
569 | |
570 | // Dont store an empty array |
571 | if ( elem_ids.size() == 0 ) { |
572 | elem_ids = null; |
573 | elem_names = null; |
574 | } |
575 | |
576 | |
577 | HprofClassElement k = findOrCreateClass( clsstr, cls_addr, size, elem_names ); |
578 | |
579 | HprofObject ho = new HprofObject( addr, clsstr, k, size, trcId, elem_names, elem_ids ); |
580 | |
581 | if (( elem_names != null ) && ( elem_names.size() != 0 )) { |
582 | ho.set_member_name_indexes( k.setNonstaticFieldNames( elem_names ) ); |
583 | } |
584 | |
585 | //_heap_objects_table.put( (int) addr, ho ); |
586 | _heap_objects_table.put( ho, ho ); |
587 | _objects.incrementAndGet(); |
588 | return 0; |
589 | } |
590 | |
591 | |
592 | public void handleRoot( String s ) { |
593 | int i = 0; |
594 | String objstr = matchAndGet( _root_begin_re, s ); |
595 | String kindstr = matchAndGet( _root_kind_re, s ); |
596 | String idstr = null; |
597 | String trcstr = null; |
598 | String classnamestr = null; |
599 | |
600 | if ( kindstr == null ) { |
601 | if ( _root_kind_unknown_re.match(s) ) { |
602 | kindstr = "<unknown>"; |
603 | } else if ( _root_kind_busymon_re.match(s) ) { |
604 | kindstr = "<busy monitor>"; |
605 | } |
606 | } |
607 | |
608 | kindstr = kindstr.intern(); |
609 | |
610 | if ( kindstr.equals("<JNI global ref>") ) { |
611 | idstr = matchAndGet( _root_id_re, s ); |
612 | trcstr = matchAndGet( _root_trace_re, s ); |
613 | } else if ( kindstr.equals("<unknown>") ) { |
614 | } else if ( kindstr.equals("<Java stack>") ) { |
615 | } else if ( kindstr.equals("<thread block>") ) { |
616 | } else if ( kindstr.equals("<JNI local ref>") ) { |
617 | } else if ( kindstr.equals("<thread>") ) { |
618 | } else if ( kindstr.equals("<busy monitor>") ) { |
619 | } else if ( kindstr.equals("<native stack>") ) { |
620 | // nothing to do |
621 | } else if ( kindstr.equals("<system class>") ) { |
622 | classnamestr = matchAndGet( _root_classname_re, s ); |
623 | //System. out. println( "### classnamestr root : " + classnamestr ); |
624 | classnamestr = classnamestr.intern(); |
625 | } else { |
626 | System. out. println( "### unknown root : " + s ); |
627 | } |
628 | |
629 | //System. out. println( "Adding root: " + objstr + " " + kindstr); |
630 | |
631 | HprofRoot rt = new HprofRoot( convertAddrStringToLong( objstr ), kindstr ); |
632 | _roots_list.add( rt ); |
633 | } |
634 | |
635 | |
636 | public void handleHeapDumpStart( String s ) { |
637 | int i = 0; |
638 | String objstr = matchAndGet( _heap_dump_objects_re, s ); |
639 | String bytestr = matchAndGet( _heap_dump_bytes_re, s ); |
640 | |
641 | System. out. println( "Heap dump objects : " + objstr ); |
642 | System. out. println( "Heap dump bytes : " + bytestr ); |
643 | } |
644 | |
645 | |
646 | public void handleThreadStart( String s ) { |
647 | String objstr = matchAndGet( thread_start_obj, s ); |
648 | String idstr = matchAndGet( thread_start_id, s ); |
649 | String namestr = matchAndGet( thread_start_name, s ); |
650 | String grpstr = matchAndGet( thread_start_group, s ); |
651 | |
652 | if ( objstr != null && idstr != null && namestr != null && grpstr != null ) { |
653 | long addr = convertAddrStringToLong( objstr ); |
654 | int id = Integer.parseInt( idstr, 10 ); |
655 | |
656 | HprofThreadData td = new HprofThreadData( namestr, id, addr, grpstr ); |
657 | _threads_list.put( (int) addr, td ); |
658 | } else { |
659 | System. out. println( "### Malformed thread ??: " + s ); |
660 | } |
661 | } |
662 | |
663 | |
664 | public void handleThreadEnd( String s ) { |
665 | } |
666 | |
667 | |
668 | public int handleHeapDumpEnd( String s ) { |
669 | // Stop processing here in case the input file has multiple dumps |
670 | if ( MadmapMain.verbose() ) { |
671 | System. out. println( "Found the end: " + s ); |
672 | } |
673 | return -1; |
674 | } |
675 | |
676 | |
677 | public void handleTrace( String s ) { |
678 | String traceid = matchAndGet( _stack_trace_title_re, s );; |
679 | String next = null; |
680 | String elem = null; |
681 | Vector backtrace = new Vector(); |
682 | HprofStackTraceData sd = null; |
683 | |
684 | if ( traceid == null ) { |
685 | System. out. println( "### Malformed trace title ??: " + s ); |
686 | return; |
687 | } |
688 | |
689 | next = readNextLine(); |
690 | while ((next != null) && ( _stack_trace_item_re.match( next ))) { |
691 | elem = _stack_trace_item_re.getParen( 1); |
692 | elem = elem.intern(); |
693 | backtrace.add( elem ); |
694 | next = readNextLine(); |
695 | } |
696 | |
697 | if ( next != null) { |
698 | pushBack( next ); |
699 | } |
700 | |
701 | // Consider option to suppress save traces to save footprint |
702 | int id = Integer.parseInt( traceid, 10 ); |
703 | sd = new HprofStackTraceData( id, backtrace ); |
704 | getStackTraces().put( id, sd ); |
705 | } |
706 | |
707 | |
708 | public void pushBack( String s ) { |
709 | _pushed_string = s; |
710 | } |
711 | |
712 | |
713 | public String readNextLine() { |
714 | try { |
715 | if ( _pushed_string != null ) { |
716 | String s = _pushed_string; |
717 | _pushed_string = null; |
718 | return s; |
719 | } else { |
720 | _linesSeen++; |
721 | if ( MadmapMain.verbose() && ((_linesSeen % 200000) == 0)) { |
722 | float rate = (float) _linesSeen / (float) elapsedTime(); |
723 | System. out. println( elapsedTime() + ": Processed " + _linesSeen + " lines from " + _startOffset + ", " + rate + "/sec" ); |
724 | } |
725 | if (( ! MadmapMain.noGUI()) && ( _readerId == 0 )) { |
726 | _owner.getWindow().getProgressBar().setValue((int)_linesSeen); |
727 | _owner.getWindow().updateMemoryProgressBar(); |
728 | } |
729 | |
730 | String ln = _bfr. readLine(); |
731 | //System. out. println( ln ); |
732 | //return _bfr. readLine(); |
733 | return ln; |
734 | } |
735 | } catch ( Exception ie ) { |
736 | System. out. println ( "readNextLine : Caught " + ie ); |
737 | return null; |
738 | } |
739 | } |
740 | |
741 | |
742 | public void readAndProcessLines(int max) { |
743 | long linesRead = 0; |
744 | String theInput = null; |
745 | int result = 0; |
746 | try { |
747 | theInput = _bfr. readLine(); |
748 | while((theInput != null) && (result == 0)) { |
749 | result = processLine( theInput ); |
750 | theInput = readNextLine(); |
751 | } |
752 | } catch (OutOfMemoryError e) { |
753 | JOptionPane.showMessageDialog(_owner.getWindow(), |
754 | "Sorry, cannot continue. Relaunch Madmap with larger heap size.", |
755 | "OutOfMemoryError", JOptionPane.ERROR_MESSAGE); |
756 | System.out.println("OutOfMemoryError in reader thread. "); |
757 | e.printStackTrace(); |
758 | System.exit(-1); |
759 | } catch ( Throwable ie ) { |
760 | System. out. println ( "processLine : Caught " + ie + " near line " + _linesSeen + " : " + theInput ); |
761 | ie.printStackTrace(); |
762 | System.exit(-1); |
763 | } |
764 | } |
765 | |
766 | public int processLine(String theInput) { |
767 | |
768 | // This needs fixing for all method returns |
769 | |
770 | //if( _obj_begin_re. match( theInput ) == true ) { |
771 | //if( theInput.startsWith( "OBJ" ) ) { |
772 | if( theInput.startsWith( objStart ) ) { |
773 | //System. out. println( "###### matched object: " + theInput ); |
774 | return handleObject( theInput ); |
775 | //} else if( _arr_begin_re. match( theInput ) == true ) { |
776 | //} else if( theInput.startsWith( "ARR" ) ) { |
777 | } else if( theInput.startsWith( arrStart ) ) { |
778 | //System. out. println( "###### matched object: " + theInput ); |
779 | return handleArray( theInput ); |
780 | //} else if( _cls_begin_re. match( theInput ) == true ) { |
781 | //} else if( theInput.startsWith( "CLS" ) ) { |
782 | } else if( theInput.startsWith( clsStart ) ) { |
783 | //System. out. println( "###### matched class: " + theInput ); |
784 | handleClass( theInput ); |
785 | //} else if( _root_begin_re. match( theInput ) == true ) { |
786 | } else if( theInput.startsWith( "ROOT " ) ) { |
787 | //System. out. println( "###### matched root: " + theInput ); |
788 | handleRoot( theInput ); |
789 | } else if( stack_trace_re. match( theInput ) == true ) { |
790 | //} else if( theInput.startsWith( "TRACE " ) ) { |
791 | //System. out. println( "###### matched trace: " + theInput ); |
792 | handleTrace( theInput ); |
793 | } else if( thread_start_re. match( theInput ) == true ) { |
794 | //System. out. println( "###### matched thd start: " + theInput ); |
795 | handleThreadStart( theInput ); |
796 | } else if( thread_end_re. match( theInput ) == true ) { |
797 | handleThreadEnd( theInput ); |
798 | } else if( _heap_dump_begin_re. match( theInput ) == true ) { |
799 | handleHeapDumpStart( theInput ); |
800 | } else if( _heap_dump_end_re. match( theInput ) == true ) { |
801 | handleHeapDumpEnd( theInput ); |
802 | } else { |
803 | //if ( Madmap.verbose() ) { |
804 | // System. out. println( "###### unmatched: line " + linesSeen + " : " + theInput ); |
805 | //} |
806 | } |
807 | return 0; |
808 | } |
809 | |
810 | |
811 | public float elapsedTime() { |
812 | return (float)(System.currentTimeMillis() - _startTime)/(float)1000.0; |
813 | } |
814 | } |
815 | |
816 | } |
817 | |