1
/*******************************************************************************
2
* Copyright (c) 2010 Red Hat, Inc.
3
* All rights reserved. This program and the accompanying materials
4
* are made available under the terms of the Eclipse Public License v1.0
5
* which accompanies this distribution, and is available at
6
* http://www.eclipse.org/legal/epl-v10.html
9
* Red Hat - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.linuxtools.internal.oprofile.core.opxml.modeldata;
13
import java.io.IOException;
14
import java.io.InputStream;
15
import java.util.ArrayList;
16
import java.util.Comparator;
17
import java.util.HashMap;
18
import java.util.TreeSet;
20
import javax.xml.parsers.DocumentBuilder;
21
import javax.xml.parsers.DocumentBuilderFactory;
22
import javax.xml.parsers.ParserConfigurationException;
24
import org.eclipse.linuxtools.internal.oprofile.core.opxml.AbstractDataAdapter;
25
import org.eclipse.linuxtools.internal.oprofile.core.opxml.info.InfoAdapter;
26
import org.w3c.dom.Document;
27
import org.w3c.dom.Element;
28
import org.w3c.dom.NodeList;
29
import org.xml.sax.SAXException;
32
* This class takes the XML that is output from 'opreport -X --details' for
33
* the current session, and uses that data to modify it into the format
34
* expected by the SAX parser.
36
public class ModelDataAdapter extends AbstractDataAdapter {
38
public final static String ID = "id"; //$NON-NLS-1$
39
public final static String IDREF = "idref"; //$NON-NLS-1$
40
public final static String NAME = "name"; //$NON-NLS-1$
41
public final static String COUNT = "count"; //$NON-NLS-1$
42
public final static String SAMPLE = "sample"; //$NON-NLS-1$
43
public final static String LINE = "line"; //$NON-NLS-1$
45
public final static String SYMBOL_DATA = "symboldata"; //$NON-NLS-1$
46
public final static String SYMBOL_DETAILS = "symboldetails"; //$NON-NLS-1$
47
public final static String SYMBOL = "symbol"; //$NON-NLS-1$
49
public final static String FILE = "file"; //$NON-NLS-1$
51
public final static String SETUP = "setup"; //$NON-NLS-1$
52
public final static String EVENT_SETUP = "eventsetup"; //$NON-NLS-1$
53
public final static String TIMER_SETUP = "timersetup"; //$NON-NLS-1$
54
public final static String SETUP_COUNT = "setupcount"; //$NON-NLS-1$
55
public final static String EVENT_NAME = "eventname"; //$NON-NLS-1$
56
public final static String RTC_INTERRUPTS = "rtcinterrupts"; //$NON-NLS-1$
58
public final static String PROFILE = "profile"; //$NON-NLS-1$
59
public final static String MODEL_DATA = "model-data"; //$NON-NLS-1$
61
public final static String MODULE = "module"; //$NON-NLS-1$
62
public final static String DEPENDENT = "dependent"; //$NON-NLS-1$
64
public final static String BINARY = "binary"; //$NON-NLS-1$
65
public final static String IMAGE = "image"; //$NON-NLS-1$
67
public final static String SYMBOLS = "symbols"; //$NON-NLS-1$
68
public final static String SYMBOL_TABLE = "symboltable"; //$NON-NLS-1$
69
public final static String DETAIL_TABLE = "detailtable"; //$NON-NLS-1$
71
public final static String DETAIL_DATA = "detaildata"; //$NON-NLS-1$
73
private boolean isParseable;
74
private Document newDoc; // the document we intend to build
75
private Element oldRoot; // the root of the document with data from opreport
76
private Element newRoot; // the root of the document we intent to build
78
public ModelDataAdapter(InputStream is) {
80
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
81
DocumentBuilder builder;
83
builder = factory.newDocumentBuilder();
85
Document oldDoc = builder.parse(is);
86
Element elem = (Element) oldDoc.getElementsByTagName(PROFILE).item(0);
89
newDoc = builder.newDocument();
90
newRoot = newDoc.createElement(MODEL_DATA);
91
newDoc.appendChild(newRoot);
92
} catch (IOException e) {
94
} catch (SAXException e) {
97
} catch (ParserConfigurationException e1) {
103
public void process (){
107
private void createXML() {
109
// get the binary name and the image count
110
Element oldImage = (Element) oldRoot.getElementsByTagName(BINARY).item(0);
111
Element newImage = newDoc.createElement(IMAGE);
113
String binName = oldImage.getAttribute(NAME);
114
newImage.setAttribute(NAME, binName);
116
Element countTag = (Element) oldImage.getElementsByTagName(COUNT).item(0);
117
String imageCount = countTag.getTextContent().trim();
118
newImage.setAttribute(COUNT, imageCount);
120
// There is no setup count in timer mode
121
if (!InfoAdapter.hasTimerSupport()){
122
// get the count that was used to profile
123
Element setupTag = (Element) oldRoot.getElementsByTagName(SETUP).item(0);
124
Element eventSetupTag = (Element) setupTag.getElementsByTagName(EVENT_SETUP).item(0);
125
String setupcount = eventSetupTag.getAttribute(SETUP_COUNT);
126
newImage.setAttribute(SETUP_COUNT, setupcount);
129
// these elements contain the data needed to populate the new symbol table
130
Element oldSymbolTableTag = (Element) oldRoot.getElementsByTagName(SYMBOL_TABLE).item(0);
131
NodeList oldSymbolDataList = oldSymbolTableTag.getElementsByTagName(SYMBOL_DATA);
133
Element oldDetailTableTag = (Element) oldRoot.getElementsByTagName(DETAIL_TABLE).item(0);
134
NodeList oldDetailTableList = oldDetailTableTag.getElementsByTagName(SYMBOL_DETAILS);
136
// parse the data into HashMaps for O(1) lookup time, as opposed to O(n).
137
HashMap<String, HashMap<String, String>> oldSymbolDataListMap = parseDataList (oldSymbolDataList);
138
HashMap<String, NodeList> oldDetailTableListMap = parseDetailTable (oldDetailTableList);
140
// An ArrayList to hold the binary and other modules
141
ArrayList<Element> oldImageList = new ArrayList<Element>();
142
// The first element is the original binary!
143
oldImageList.add(oldImage);
145
NodeList oldModuleList = oldImage.getElementsByTagName(MODULE);
146
// Set up the dependent tag for any modules run by this binary
147
Element dependentTag = newDoc.createElement(DEPENDENT);
148
if (oldModuleList.getLength() > 0){
149
dependentTag.setAttribute(COUNT, "0"); //$NON-NLS-1$
151
for (int t = 0; t < oldModuleList.getLength(); t++){
152
oldImageList.add((Element)oldModuleList.item(t));
156
// iterate through all (binary/modules)
157
for (Element oldImg : oldImageList) {
159
if (oldImg.getTagName().equals(BINARY)){
162
newImg = newDoc.createElement(IMAGE);
164
String imgName = oldImg.getAttribute(NAME);
165
newImg.setAttribute(NAME, imgName);
167
Element modCountTag = (Element) oldImg.getElementsByTagName(COUNT).item(0);
168
String imgCount = modCountTag.getTextContent().trim();
169
newImg.setAttribute(COUNT, imgCount);
172
Element newSymbolsTag = newDoc.createElement(SYMBOLS);
174
// these elements contain the data needed to populate the new symbol table
175
NodeList oldSymbolList = oldImg.getElementsByTagName(SYMBOL);
177
// iterate through all symbols
178
for (int i = 0; i < oldSymbolList.getLength(); i++) {
179
Element oldSymbol = (Element) oldSymbolList.item(i);
182
* The original binary is a parent for all symbols
183
* We only want library function calls under their respective
184
* modules, and not under the original binary as well.
186
if (!oldSymbol.getParentNode().isSameNode(oldImg)){
190
Element newSymbol = newDoc.createElement(SYMBOL);
191
String idref = oldSymbol.getAttribute(IDREF);
192
String symbolCount = ((Element) oldSymbol.getElementsByTagName(COUNT).item(0)).getTextContent().trim();
193
newSymbol.setAttribute(COUNT, symbolCount);
195
// get the symboltable entry corresponding to the id of this symbol
196
HashMap<String, String> symbolData = oldSymbolDataListMap.get(idref);
197
newSymbol.setAttribute(NAME, symbolData.get(NAME));
198
newSymbol.setAttribute(FILE, symbolData.get(FILE));
199
newSymbol.setAttribute(LINE, symbolData.get(LINE));
201
// get the symboldetails entry corresponding to the id of this symbol
202
NodeList detailDataList = oldDetailTableListMap.get(idref);
204
// go through the detail data of each symbol's details
205
HashMap<String, Element> tmp = new HashMap<String, Element>();
206
// temporary place to store the elements for sorting
207
TreeSet<Element> sorted = new TreeSet<Element>(SAMPLE_COUNT_ORDER);
208
for (int l = 0; l < detailDataList.getLength(); l++) {
210
Element detailData = (Element) detailDataList.item(l);
211
String sampleFile = detailData.getAttribute(FILE);
212
String sampleLine = detailData.getAttribute(LINE);
214
// The sample has a line number but no file
215
// This means that the file is the same as the symbol (parent)
216
if (sampleFile.equals("") && !sampleLine.equals("")){ //$NON-NLS-1$ $NON-NLS-2$
217
sampleFile = symbolData.get(FILE);
219
if (sampleFile.equals("")){ //$NON-NLS-1$
220
sampleFile = "??"; //$NON-NLS-1$
222
if (sampleLine.equals("")){ //$NON-NLS-1$
223
sampleLine = "0"; //$NON-NLS-1$
226
Element detailDataCount = (Element) detailData.getElementsByTagName(COUNT).item(0);
227
String count = detailDataCount.getTextContent().trim();
229
// if a sample at this line already exists then increase count for that line.
230
if (tmp.containsKey(sampleLine)) {
231
Element elem = (Element) tmp.get(sampleLine).getElementsByTagName(COUNT).item(0);
232
int val = Integer.parseInt(elem.getTextContent().trim()) + Integer.parseInt(count);
233
elem.setTextContent(String.valueOf(val));
235
Element sampleTag = newDoc.createElement(SAMPLE);
237
Element fileTag = newDoc.createElement(FILE);
238
fileTag.setTextContent(sampleFile);
240
Element lineTag = newDoc.createElement(LINE);
241
lineTag.setTextContent(sampleLine);
243
Element sampleCountTag = newDoc.createElement(COUNT);
244
sampleCountTag.setTextContent(count);
246
sampleTag.appendChild(fileTag);
247
sampleTag.appendChild(lineTag);
248
sampleTag.appendChild(sampleCountTag);
250
tmp.put(sampleLine, sampleTag);
254
// add the elements to the sorter
255
for (Element elem : tmp.values()) {
259
// append the elements in sorted order
260
for (Element e : sorted) {
261
newSymbol.appendChild(e);
264
newSymbolsTag.appendChild(newSymbol);
267
newImg.appendChild(newSymbolsTag);
268
// If this is a module, attach it to the dependent tag
269
if (oldImg.getTagName().equals(MODULE)){
270
dependentTag.appendChild(newImg);
271
int currVal = Integer.parseInt(dependentTag.getAttribute(COUNT));
272
int val = Integer.parseInt(newImg.getAttribute(COUNT));
273
dependentTag.setAttribute(COUNT, String.valueOf(currVal + val));
275
newRoot.appendChild(newImg);
279
if (oldModuleList.getLength() > 0){
280
newImage.appendChild(dependentTag);
287
* @param oldDetailTableList the list of 'symboldetails' tags within detailtable
288
* @return a HashMap where the key is a function id and the value is a NodeList
289
* containing a list of the 'detaildata' tags that contain sample information.
291
private HashMap<String, NodeList> parseDetailTable(NodeList oldDetailTableList) {
292
HashMap<String, NodeList> ret = new HashMap<String, NodeList> ();
293
for (int i = 0; i < oldDetailTableList.getLength(); i++){
294
Element symbolDetails = (Element) oldDetailTableList.item(i);
295
String id = symbolDetails.getAttribute(ID);
296
NodeList detailDataList = symbolDetails.getElementsByTagName(DETAIL_DATA);
297
ret.put(id, detailDataList);
304
* @param oldSymbolDataList the list of 'symboldata' tags within symboltable
305
* @return a Hashmap where the key is a function id and the value is a HashMap
306
* with various parameters of data
308
private HashMap<String, HashMap<String, String>> parseDataList(NodeList oldSymbolDataList) {
309
HashMap<String, HashMap<String,String>> ret = new HashMap<String, HashMap<String, String>> ();
310
for (int j = 0; j < oldSymbolDataList.getLength(); j++){
311
HashMap<String,String> tmp = new HashMap<String,String> ();
312
Element symbolData = (Element) oldSymbolDataList.item(j);
313
String id = symbolData.getAttribute(ID);
314
String name = symbolData.getAttribute(NAME);
315
String file = symbolData.getAttribute(FILE);
316
if (file.equals("")){ //$NON-NLS-1$
317
file = "??"; //$NON-NLS-1$
319
String line = symbolData.getAttribute(LINE);
320
if (line.equals("")){ //$NON-NLS-1$
321
line = "0"; //$NON-NLS-1$
332
public Document getDocument() {
337
* Helper class to sort the samples of a given symbol in descending order from largest
340
public static final Comparator<Element> SAMPLE_COUNT_ORDER = new Comparator<Element>()
342
public int compare(Element a, Element b) {
343
// sort from largest to smallest count in descending order
344
// items with the same count are sorted by line number from smallest
345
// to largest in descending order
346
Element a_countTag = (Element) a.getElementsByTagName(COUNT).item(0);
347
Element b_countTag = (Element) b.getElementsByTagName(COUNT).item(0);
348
Element a_LineTag = (Element) a.getElementsByTagName(LINE).item(0);
349
Element b_LineTag = (Element) b.getElementsByTagName(LINE).item(0);
351
Integer a_count = Integer.parseInt(a_countTag.getTextContent().trim());
352
Integer b_count = Integer.parseInt(b_countTag.getTextContent().trim());
353
Integer a_line = Integer.parseInt(a_LineTag.getTextContent().trim());
354
Integer b_line = Integer.parseInt(b_LineTag.getTextContent().trim());
356
if (a_count.compareTo(b_count) == 0){
357
return a_line.compareTo(b_line);
359
return -a_count.compareTo(b_count);
363
public boolean isParseable() {