|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 package com.nokia.carbide.cpp.pi.address; |
|
19 |
|
20 import java.io.DataInputStream; |
|
21 import java.io.DataOutputStream; |
|
22 import java.io.EOFException; |
|
23 import java.io.File; |
|
24 import java.io.FileInputStream; |
|
25 import java.io.IOException; |
|
26 import java.util.Collection; |
|
27 import java.util.Enumeration; |
|
28 import java.util.Hashtable; |
|
29 import java.util.Iterator; |
|
30 import java.util.StringTokenizer; |
|
31 import java.util.Vector; |
|
32 |
|
33 import com.nokia.carbide.cpp.internal.pi.analyser.NpiInstanceRepository; |
|
34 import com.nokia.carbide.cpp.internal.pi.model.GenericTrace; |
|
35 import com.nokia.carbide.cpp.internal.pi.model.ParsedTraceData; |
|
36 import com.nokia.carbide.cpp.internal.pi.model.Parser; |
|
37 import com.nokia.carbide.cpp.internal.pi.model.TraceDataContainer; |
|
38 |
|
39 |
|
40 public class GppTraceParser extends Parser |
|
41 { |
|
42 // private String traceVersion; |
|
43 private boolean debug = false; |
|
44 private String profilerVersion; |
|
45 private String samplerVersion; |
|
46 private Hashtable<Integer,GppProcess> processes; |
|
47 private Hashtable<Integer,GppThread> threads; |
|
48 private GppSample[] traceData; |
|
49 private GppThread[] sortedThreads; |
|
50 private TraceDataContainer container; |
|
51 private Hashtable<Long,String> threadAddressToName; |
|
52 |
|
53 public GppTraceParser() throws IOException |
|
54 { |
|
55 this.processes = new Hashtable<Integer,GppProcess>(); |
|
56 this.threads = new Hashtable<Integer,GppThread>(); |
|
57 this.threadAddressToName = new Hashtable<Long,String>(); |
|
58 } |
|
59 |
|
60 public ParsedTraceData parse(File traceInput) throws IOException |
|
61 { |
|
62 if (!traceInput.exists()) |
|
63 throw new IOException(Messages.getString("GppTraceParser.0")); //$NON-NLS-1$ |
|
64 |
|
65 DataInputStream dis = new DataInputStream(new FileInputStream(traceInput)); |
|
66 |
|
67 if (validate(dis) == false) |
|
68 throw new IOException(Messages.getString("GppTraceParser.1")); //$NON-NLS-1$ |
|
69 |
|
70 long pc = 0; |
|
71 GppThread thread = null; |
|
72 int threadIndexer = 0; |
|
73 int count = 1; |
|
74 int samples = 0; |
|
75 long time = 0; |
|
76 |
|
77 Vector<GppSample> intermediateTraceData = new Vector<GppSample>(); |
|
78 |
|
79 // determine the base sampling period (address/thread sampling period) |
|
80 int addrThreadPeriod = 1; |
|
81 |
|
82 if (traceVersion.indexOf("V2.01") != -1) { //$NON-NLS-1$ |
|
83 addrThreadPeriod = (dis.readUnsignedByte() << 24) |
|
84 | (dis.readUnsignedByte() << 16) |
|
85 | (dis.readUnsignedByte() << 8) |
|
86 | dis.readUnsignedByte(); |
|
87 } |
|
88 |
|
89 // initialize the address/thread base sampling rate |
|
90 NpiInstanceRepository.getInstance().activeUidSetPersistState( |
|
91 "com.nokia.carbide.cpp.pi.address.samplingInterval", //$NON-NLS-1$ |
|
92 new Integer(addrThreadPeriod)); //$NON-NLS-1$ |
|
93 |
|
94 while (dis.available() > 0) |
|
95 { |
|
96 try |
|
97 { |
|
98 count = 1; |
|
99 int diff = (int)decodeInt(dis); |
|
100 |
|
101 if ((diff & 1) == 1) |
|
102 { |
|
103 diff &= ~1; |
|
104 thread = decodeThread(dis); |
|
105 } |
|
106 else if (diff == 0) |
|
107 { |
|
108 count = (int)decodeUInt(dis); |
|
109 } |
|
110 |
|
111 pc += diff; |
|
112 |
|
113 while (--count >= 0) |
|
114 { |
|
115 samples++; |
|
116 time += addrThreadPeriod; |
|
117 |
|
118 if (samples == 1 && thread == null) |
|
119 { |
|
120 // the first sample may be recorded before its thread's name |
|
121 |
|
122 // create a new sample object for this sample |
|
123 GppSample gppSample = new GppSample(); |
|
124 long pcMod = pc << 32; |
|
125 pcMod = pcMod >>> 32; |
|
126 gppSample.programCounter = pcMod; |
|
127 gppSample.sampleSynchTime = time; |
|
128 |
|
129 GppThread unknownThread = new GppThread(); |
|
130 unknownThread.threadId = -1; |
|
131 unknownThread.threadName = Messages.getString("GppTraceParser.unknown"); //$NON-NLS-1$ |
|
132 |
|
133 GppProcess unknownProcess = new GppProcess(); |
|
134 unknownProcess.id = -1; |
|
135 unknownProcess.name = Messages.getString("GppTraceParser.unknown"); //$NON-NLS-1$ |
|
136 this.processes.put(-1,unknownProcess); |
|
137 |
|
138 unknownThread.process = unknownProcess; |
|
139 unknownThread.index = threadIndexer++; |
|
140 |
|
141 gppSample.thread = unknownThread; |
|
142 |
|
143 this.threads.put(-1,unknownThread); |
|
144 |
|
145 gppSample.thread = unknownThread; |
|
146 intermediateTraceData.add(gppSample); |
|
147 } |
|
148 else if (thread.index >= -1) |
|
149 { |
|
150 if (thread.index == -1) thread.index = threadIndexer++; |
|
151 |
|
152 // create a new sample object for this sample |
|
153 |
|
154 GppSample gppSample = new GppSample(); |
|
155 long pcMod = pc << 32; |
|
156 pcMod = pcMod >>> 32; |
|
157 |
|
158 if (thread.threadName.equals("*Native*")) //$NON-NLS-1$ |
|
159 gppSample.programCounter = 0; |
|
160 else |
|
161 gppSample.programCounter = pcMod; |
|
162 |
|
163 //System.out.println("PC value:"+pc+" "+Long.toHexString(pc)); |
|
164 |
|
165 gppSample.sampleSynchTime = time; |
|
166 gppSample.thread = thread; |
|
167 thread.samples++; |
|
168 intermediateTraceData.add(gppSample); |
|
169 } |
|
170 } |
|
171 } |
|
172 catch (EOFException e) {} |
|
173 } |
|
174 if (debug) System.out.println(Messages.getString("GppTraceParser.2")); //$NON-NLS-1$ |
|
175 // all samples have been parsed |
|
176 this.traceData = new GppSample[intermediateTraceData.size()]; |
|
177 |
|
178 // store the trace data into an array |
|
179 intermediateTraceData.toArray(this.traceData); |
|
180 |
|
181 // sort the threads into an ordered array |
|
182 this.sortThreads(); |
|
183 |
|
184 container = new TraceDataContainer("GPP_address2threadname",new String[]{"address","threadname"}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
|
185 Enumeration<Long> ke = this.threadAddressToName.keys(); |
|
186 Iterator<String> vi = this.threadAddressToName.values().iterator(); |
|
187 |
|
188 while(ke.hasMoreElements()) |
|
189 { |
|
190 Long address = ke.nextElement(); |
|
191 String name = vi.next(); |
|
192 container.addDataToColumn("threadname",name); //$NON-NLS-1$ |
|
193 container.addDataToColumn("address",address); //$NON-NLS-1$ |
|
194 } |
|
195 this.threadAddressToName.clear(); |
|
196 this.threadAddressToName = null; |
|
197 |
|
198 ParsedTraceData pd = new ParsedTraceData(); |
|
199 pd.traceData = this.getTrace(); |
|
200 |
|
201 return pd; |
|
202 } |
|
203 |
|
204 private void sortThreads() |
|
205 { |
|
206 if (this.threads != null) |
|
207 { |
|
208 boolean sorted = false; |
|
209 |
|
210 GppThread[] tArray = new GppThread[this.threads.size()]; |
|
211 Collection<GppThread> threadCollection = this.threads.values(); |
|
212 threadCollection.toArray(tArray); |
|
213 |
|
214 // set initial sort order to the order in which |
|
215 // the threads appear in the array |
|
216 for (int i = 0; i < tArray.length; i++) |
|
217 { |
|
218 tArray[i].sortOrder = i; |
|
219 } |
|
220 |
|
221 // sort threads using bubble sort |
|
222 while (sorted == false) |
|
223 { |
|
224 sorted = true; |
|
225 for (int i = 0; i < tArray.length - 1; i++) |
|
226 { |
|
227 if (tArray[i].samples < tArray[i + 1].samples) |
|
228 { |
|
229 // switch the sort order |
|
230 GppThread store = tArray[i]; |
|
231 tArray[i] = tArray[i + 1]; |
|
232 tArray[i + 1] = store; |
|
233 sorted = false; |
|
234 } |
|
235 } |
|
236 } |
|
237 |
|
238 // finally, store the ordered array |
|
239 this.sortedThreads = tArray; |
|
240 for (int i=0;i<this.sortedThreads.length;i++) |
|
241 { |
|
242 this.sortedThreads[i].sortOrder = i; |
|
243 } |
|
244 |
|
245 } |
|
246 } |
|
247 |
|
248 private boolean validate(DataInputStream dis) throws IOException |
|
249 { |
|
250 String data = decodeName(dis); |
|
251 if (debug) System.out.println(Messages.getString("GppTraceParser.3")+data); //$NON-NLS-1$ |
|
252 if (data.equals("profile")) //pre 1.10 //$NON-NLS-1$ |
|
253 if (decodeUInt(dis) == 1) return true; |
|
254 |
|
255 if (data.startsWith("Bappea_GPP_V")) //version 1.20 //$NON-NLS-1$ |
|
256 { |
|
257 try |
|
258 { |
|
259 int separatorIndex = data.indexOf("#"); //$NON-NLS-1$ |
|
260 this.traceVersion = data.substring(data.indexOf("_")+1,separatorIndex); //$NON-NLS-1$ |
|
261 } |
|
262 catch (Exception e) |
|
263 { |
|
264 return false; |
|
265 } |
|
266 |
|
267 StringTokenizer st = new StringTokenizer(data,"#"); //$NON-NLS-1$ |
|
268 while(st.hasMoreElements()) |
|
269 { |
|
270 String id = st.nextToken(); |
|
271 if (id.equals("Prof")) //$NON-NLS-1$ |
|
272 { |
|
273 this.profilerVersion = st.nextToken(); |
|
274 } |
|
275 else if (id.equals("Samp")) //$NON-NLS-1$ |
|
276 { |
|
277 this.samplerVersion = st.nextToken(); |
|
278 } |
|
279 } |
|
280 |
|
281 System.out.println(Messages.getString("GppTraceParser.4")+traceVersion+Messages.getString("GppTraceParser.5")+profilerVersion+Messages.getString("GppTraceParser.6")+samplerVersion); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
|
282 |
|
283 if ( (traceVersion.indexOf("V1.10") != -1) //$NON-NLS-1$ |
|
284 || (traceVersion.indexOf("V1.64") != -1) //$NON-NLS-1$ |
|
285 || (traceVersion.indexOf("V2.01") != -1)) //$NON-NLS-1$ |
|
286 return true; |
|
287 else |
|
288 return false; |
|
289 } |
|
290 |
|
291 return false; |
|
292 } |
|
293 |
|
294 public static void encodeInt(int number, DataOutputStream dos) throws IOException |
|
295 { |
|
296 int digit; |
|
297 for (;;) { |
|
298 digit = number & 0x7f; |
|
299 if ((number >> 6) == (number >> 7)) |
|
300 break; |
|
301 number >>= 7; |
|
302 dos.write(digit); |
|
303 } |
|
304 dos.write(digit | 0x80); |
|
305 |
|
306 dos.flush(); |
|
307 } |
|
308 |
|
309 public static void encodeUInt(int number, DataOutputStream dos) throws IOException |
|
310 { |
|
311 int digit; |
|
312 for (;;) { |
|
313 digit = number & 0x7f; |
|
314 number >>= 7; |
|
315 if (number <= 0) |
|
316 break; |
|
317 dos.write(digit); |
|
318 } |
|
319 dos.write(digit | 0x80); |
|
320 } |
|
321 |
|
322 public static long decodeInt(DataInputStream dis) throws IOException |
|
323 { |
|
324 //System.out.println("DECODING INT"); |
|
325 |
|
326 int val = 0; |
|
327 int shift = 0; |
|
328 int data; |
|
329 do |
|
330 { |
|
331 data = dis.readUnsignedByte(); |
|
332 //System.out.print(":"+Integer.toHexString(data)); |
|
333 if (data < 0) |
|
334 throw new IOException(Messages.getString("GppTraceParser.7")); //$NON-NLS-1$ |
|
335 val |= (data & 0x7f) << shift; |
|
336 shift += 7; |
|
337 } while ((data & 0x80) == 0); |
|
338 |
|
339 if (shift < 32) |
|
340 { |
|
341 shift = 32 - shift; |
|
342 val = val << shift >> shift; |
|
343 } |
|
344 //System.out.println("read int"+(val & 0xffffffff)); |
|
345 |
|
346 return (val); |
|
347 } |
|
348 |
|
349 |
|
350 public static long decodeUInt(DataInputStream dis) throws IOException |
|
351 { |
|
352 //System.out.println("DECODING UINT"); |
|
353 long val = 0; |
|
354 int shift = 0; |
|
355 int data; |
|
356 do |
|
357 { |
|
358 data = dis.readUnsignedByte(); |
|
359 //System.out.println("read byte:"+Integer.toHexString(data)); |
|
360 if (data < 0) |
|
361 throw new IOException(Messages.getString("GppTraceParser.8")); //$NON-NLS-1$ |
|
362 val |= (data & 0x7f) << shift; |
|
363 shift += 7; |
|
364 } while ((data & 0x80) == 0); |
|
365 |
|
366 //System.out.println("read unsigned int"+val); |
|
367 return val; |
|
368 } |
|
369 |
|
370 |
|
371 private String decodeName(DataInputStream dis) throws IOException |
|
372 { |
|
373 //System.out.println("DECODING NAME"); |
|
374 |
|
375 int length = dis.readUnsignedByte(); |
|
376 //System.out.println("name length "+Integer.toHexString(length)); |
|
377 byte[] data = new byte[length]; |
|
378 dis.read(data); |
|
379 //System.out.println("Read name:"+new String(data)); |
|
380 return new String(data); |
|
381 } |
|
382 |
|
383 private GppProcess decodeProcess(DataInputStream dis) throws IOException |
|
384 { |
|
385 //System.out.println("DECODING PROCESS"); |
|
386 Integer pid = new Integer((int)decodeUInt(dis)); |
|
387 |
|
388 if (this.processes.containsKey(pid)) |
|
389 { |
|
390 return (GppProcess)this.processes.get(pid); |
|
391 } |
|
392 else |
|
393 { |
|
394 GppProcess np = new GppProcess(); |
|
395 np.id = pid; |
|
396 np.name = decodeName(dis); |
|
397 this.processes.put(pid,np); |
|
398 return np; |
|
399 } |
|
400 } |
|
401 |
|
402 private GppThread decodeThread(DataInputStream dis) throws IOException |
|
403 { |
|
404 //System.out.println("DECODING THREAD"); |
|
405 Integer tid = new Integer((int)decodeUInt(dis)); |
|
406 |
|
407 if (this.threads.containsKey(tid)) |
|
408 { |
|
409 return (GppThread)this.threads.get(tid); |
|
410 } |
|
411 |
|
412 GppProcess p = decodeProcess(dis); |
|
413 String name = decodeName(dis); |
|
414 |
|
415 try |
|
416 { |
|
417 if (name.endsWith("]")) //$NON-NLS-1$ |
|
418 { |
|
419 String l = name.substring(name.lastIndexOf("[")+1,name.lastIndexOf("]")); //$NON-NLS-1$ //$NON-NLS-2$ |
|
420 Long threadAddress = Long.decode("0x"+l); //$NON-NLS-1$ |
|
421 this.threadAddressToName.put(threadAddress,name); |
|
422 name = name.substring(0,name.lastIndexOf("[")); //$NON-NLS-1$ |
|
423 } |
|
424 } |
|
425 catch (Exception e) |
|
426 { |
|
427 e.printStackTrace(); |
|
428 } |
|
429 |
|
430 GppThread nt = new GppThread(); |
|
431 nt.threadId = tid; |
|
432 nt.threadName = name; |
|
433 nt.process = p; |
|
434 nt.index = -1; |
|
435 |
|
436 this.threads.put(tid,nt); |
|
437 |
|
438 return nt; |
|
439 } |
|
440 |
|
441 private GenericTrace getTrace() |
|
442 { |
|
443 GppTrace trace = new GppTrace(); |
|
444 for (int i = 0; i < traceData.length; i++) |
|
445 { |
|
446 trace.addSample(this.traceData[i]); |
|
447 } |
|
448 return trace; |
|
449 } |
|
450 } |
|
451 |