1
/*******************************************************************************
2
* Copyright (c) 2008 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
* Elliott Baron <ebaron@redhat.com> - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.linuxtools.internal.valgrind.massif;
13
import java.io.BufferedReader;
15
import java.io.FileReader;
16
import java.io.IOException;
17
import java.util.ArrayList;
19
import org.eclipse.linuxtools.internal.valgrind.massif.MassifSnapshot.SnapshotType;
20
import org.eclipse.linuxtools.internal.valgrind.massif.MassifSnapshot.TimeUnit;
21
import org.eclipse.linuxtools.valgrind.core.ValgrindParserUtils;
22
import org.eclipse.osgi.util.NLS;
24
public class MassifParser {
25
private static final String COLON = ":"; //$NON-NLS-1$
26
private static final String SPACE = " "; //$NON-NLS-1$
27
private static final String EQUALS = "="; //$NON-NLS-1$
29
private static final String CMD = "cmd"; //$NON-NLS-1$
30
private static final String TIME_UNIT = "time_unit"; //$NON-NLS-1$
31
private static final String SNAPSHOT = "snapshot"; //$NON-NLS-1$
32
private static final String TIME = "time"; //$NON-NLS-1$
33
private static final String MEM_HEAP_B = "mem_heap_B"; //$NON-NLS-1$
34
private static final String MEM_HEAP_EXTRA_B = "mem_heap_extra_B"; //$NON-NLS-1$
35
private static final String MEM_STACKS_B = "mem_stacks_B"; //$NON-NLS-1$
36
private static final String HEAP_TREE = "heap_tree"; //$NON-NLS-1$
38
private static final String INSTRUCTIONS = "i"; //$NON-NLS-1$
39
private static final String MILLISECONDS = "ms"; //$NON-NLS-1$
40
private static final String BYTES = "B"; //$NON-NLS-1$
41
private static final String PEAK = "peak"; //$NON-NLS-1$
42
private static final String DETAILED = "detailed"; //$NON-NLS-1$
43
private static final String EMPTY = "empty"; //$NON-NLS-1$
45
protected Integer pid;
46
protected MassifSnapshot[] snapshots;
48
public MassifParser(File inputFile) throws IOException {
49
ArrayList<MassifSnapshot> list = new ArrayList<MassifSnapshot>();
50
BufferedReader br = null;
52
br = new BufferedReader(new FileReader(inputFile));
54
MassifSnapshot snapshot = null;
59
// retrive PID from filename
60
String filename = inputFile.getName();
61
pid = ValgrindParserUtils.parsePID(filename, MassifLaunchDelegate.OUT_PREFIX);
63
// parse contents of file
64
while ((line = br.readLine()) != null) {
65
if (line.startsWith(CMD + COLON)){
66
cmd = ValgrindParserUtils.parseStrValue(line, COLON + SPACE);
68
else if (line.startsWith(TIME_UNIT + COLON)) {
69
unit = parseTimeUnit(line);
71
else if (line.startsWith(SNAPSHOT)) {
72
if (snapshot != null) {
73
// this snapshot finished parsing
77
snapshot = new MassifSnapshot(n);
79
snapshot.setUnit(unit);
81
else if (line.startsWith(TIME + EQUALS)) {
82
snapshot.setTime(ValgrindParserUtils.parseLongValue(line, EQUALS));
84
else if (line.startsWith(MEM_HEAP_B + EQUALS)) {
85
snapshot.setHeapBytes(ValgrindParserUtils.parseLongValue(line, EQUALS));
87
else if (line.startsWith(MEM_HEAP_EXTRA_B + EQUALS)) {
88
snapshot.setHeapExtra(ValgrindParserUtils.parseLongValue(line, EQUALS));
90
else if (line.startsWith(MEM_STACKS_B + EQUALS)) {
91
snapshot.setStacks(ValgrindParserUtils.parseLongValue(line, EQUALS));
93
else if (line.startsWith(HEAP_TREE + EQUALS)) {
94
SnapshotType type = parseSnapshotType(line);
95
snapshot.setType(type);
99
MassifHeapTreeNode node = parseTree(snapshot, null, br);
100
node.setText(NLS.bind(Messages.getString("MassifParser.Snapshot_n"), n, node.getText())); // prepend snapshot number //$NON-NLS-1$
101
snapshot.setRoot(node);
105
if (snapshot != null) {
106
// last snapshot that finished parsing
109
snapshots = list.toArray(new MassifSnapshot[list.size()]);
117
private MassifHeapTreeNode parseTree(MassifSnapshot snapshot, MassifHeapTreeNode parent, BufferedReader br) throws IOException {
118
String line = br.readLine();
120
throw new IOException(Messages.getString("MassifParser.Unexpected_EOF")); //$NON-NLS-1$
122
line = line.trim(); // remove leading whitespace
123
String[] parts = line.split(" "); //$NON-NLS-1$
124
// bounds checking so we can fail with a more informative error
125
if (parts.length < 2) {
126
ValgrindParserUtils.fail(line);
129
Integer numChildren = parseNumChildren(parts[0]);
130
if (numChildren == null) {
131
ValgrindParserUtils.fail(line);
134
Long numBytes = parseNumBytes(parts[1]);
135
if (numBytes == null) {
136
ValgrindParserUtils.fail(line);
140
if (numBytes.intValue() == 0) {
144
percentage = numBytes.doubleValue() / snapshot.getTotal() * 100;
147
MassifHeapTreeNode node;
148
String address = null;
149
String function = null;
150
String filename = null;
152
if (parts[2].startsWith("0x")) { //$NON-NLS-1$
153
// we extend the above bounds checking
154
if (parts.length < 3) {
155
ValgrindParserUtils.fail(line);
157
// remove colon from address
158
address = parts[2].substring(0, parts[2].length() - 1);
160
function = parseFunction(parts[3], line);
162
// Parse source file if specified
163
Object[] subparts = ValgrindParserUtils.parseFilename(line);
164
filename = (String) subparts[0];
165
lineNo = (Integer) subparts[1];
167
node = new MassifHeapTreeNode(parent, percentage, numBytes, address, function, filename, lineNo);
170
// concatenate the rest
171
StringBuffer text = new StringBuffer();
172
for (int i = 2; i < parts.length; i++) {
173
text.append(parts[i]);
174
text.append(" "); //$NON-NLS-1$
177
node = new MassifHeapTreeNode(parent, percentage, numBytes, text.toString().trim());
181
for (int i = 0; i < numChildren.intValue(); i++) {
182
node.addChild(parseTree(snapshot, node, br));
187
private String parseFunction(String start, String line) throws IOException {
188
String function = null;
189
int ix = line.lastIndexOf("("); //$NON-NLS-1$
191
function = line.substring(line.indexOf(start), ix);
194
function = line.substring(line.indexOf(start));
196
if (function != null) {
197
function = function.trim();
200
ValgrindParserUtils.fail(line);
206
private Long parseNumBytes(String string) {
208
if (ValgrindParserUtils.isNumber(string)) {
209
result = Long.parseLong(string);
215
* format is "n[0-9]+:"
217
private Integer parseNumChildren(String string) {
218
Integer result = null;
219
if (string.length() >= 3) {
220
String number = string.substring(1, string.length() - 1);
221
if (ValgrindParserUtils.isNumber(number)) {
222
result = Integer.parseInt(number);
228
public Integer getPid() {
232
public MassifSnapshot[] getSnapshots() {
236
protected SnapshotType parseSnapshotType(String line) throws IOException {
237
SnapshotType result = null;
238
String[] parts = line.split(EQUALS);
239
if (parts.length > 1) {
240
String type = parts[1];
241
if (type.equals(EMPTY)) {
242
result = SnapshotType.EMPTY;
244
else if (type.equals(DETAILED)) {
245
result = SnapshotType.DETAILED;
247
else if (type.equals(PEAK)) {
248
result = SnapshotType.PEAK;
251
if (result == null) {
252
ValgrindParserUtils.fail(line);
257
protected TimeUnit parseTimeUnit(String line) throws IOException {
258
TimeUnit result = null;
259
String[] parts = line.split(COLON + SPACE);
260
if (parts.length > 1) {
261
String type = parts[1];
262
if (type.equals(INSTRUCTIONS)) {
263
result = TimeUnit.INSTRUCTIONS;
265
else if (type.equals(MILLISECONDS)) {
266
result = TimeUnit.MILLISECONDS;
268
else if (type.equals(BYTES)) {
269
result = TimeUnit.BYTES;
272
if (result == null) {
273
ValgrindParserUtils.fail(line);