1
/*******************************************************************************
2
* Copyright (c) 2009 STMicroelectronics.
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
* Xavier Raynaud <xavier.raynaud@st.com> - initial API and implementation
10
*******************************************************************************/
11
package org.eclipse.linuxtools.internal.gprof.parser;
13
import java.io.DataInput;
14
import java.io.IOException;
15
import java.io.PrintStream;
17
import org.eclipse.cdt.core.IBinaryParser.ISymbol;
18
import org.eclipse.linuxtools.internal.gprof.symbolManager.Bucket;
19
import org.eclipse.linuxtools.internal.gprof.view.histogram.HistRoot;
23
* Reads the histogram in gmon files
24
* @author Xavier Raynaud <xavier.raynaud@st.com>
26
public class HistogramDecoder {
28
private static final int GMON_HDRSIZE_BSD44 = (3 * 4);
30
private static final int GMON_HDRSIZE_BSD44_32 = (4 + 4 + 4 + 4 + 4 + GMON_HDRSIZE_BSD44);
31
private static final int GMON_HDRSIZE_BSD44_64 = (8 + 8 + 4 + 4 + 4 + GMON_HDRSIZE_BSD44);
32
private static final int GMON_HDRSIZE_OLDBSD_32 = (4 + 4 + 4) ;
33
private static final int GMON_HDRSIZE_OLDBSD_64 = (8 + 8 + 4);
37
protected final GmonDecoder decoder;
40
/** Base pc address of sampled buffer */
42
/** Max pc address of sampled buffer */
43
protected long highpc;
44
/** Profiling clock rate */
45
protected int prof_rate;
46
/** physical dimension - usually "seconds" */
47
protected String dimen;
48
/** usually 's' for seconds, 'm' for milliseconds... */
49
protected char dimen_abbrev;
50
/** used when aggregate several gmon files */
51
protected boolean initialized = false;
54
/** Histogram samples (shorts in the file!). */
55
protected int[] hist_sample;
56
/** Total time for all routines. */
57
protected double total_time;
59
protected long bucketSize;
64
* @param decoder the Gmon decoder
66
public HistogramDecoder(GmonDecoder decoder) {
67
this.decoder = decoder;
70
protected long readAddress(DataInput stream) throws IOException {
71
long ret = stream.readInt() & 0xFFFFFFFFL;
75
public boolean hasValues() {
76
return (this.hist_sample != null && this.hist_sample.length > 0);
80
* Decode the given stream
81
* @param stream a DataInputStream, pointing on a histogram header in a gmon file.
82
* @throws IOException if an IO error occurs
84
public void decodeHeader(DataInput stream) throws IOException {
85
long lowpc = readAddress(stream);
86
long highpc = readAddress(stream);
87
int hist_num_bins = stream.readInt();
88
int prof_rate = stream.readInt();
89
byte[] bytes = new byte[15];
90
stream.readFully(bytes);
91
byte b = stream.readByte();
93
if (!isCompatible(lowpc, highpc, prof_rate, hist_num_bins))
95
// TODO exception to normalize
96
throw new RuntimeException("Histogram header's incompatibility among gmon files");
100
this.prof_rate = prof_rate;
101
hist_sample = new int[hist_num_bins]; // Impl note: JVM sets all integers to 0
102
dimen = new String(bytes);
103
dimen_abbrev = (char) b;
104
long temp = highpc - lowpc;
105
bucketSize = Math.round(temp/(double)hist_num_bins);
109
* Decode the given stream
110
* @param stream a DataInputStream, pointing on a histogram header in a gmon file.
111
* @throws IOException if an IO error occurs
113
public void decodeOldHeader(DataInput stream) throws IOException {
114
long low_pc = readAddress(stream);
115
long high_pc = readAddress(stream);
116
int ncnt = stream.readInt();
117
int version = stream.readInt();
120
if (version == GmonDecoder.GMONVERSION)
122
profrate = stream.readInt();
123
stream.skipBytes(GMON_HDRSIZE_BSD44);
124
if (decoder._32_bit_platform) {
125
header_size = GMON_HDRSIZE_BSD44_32;
127
header_size = GMON_HDRSIZE_BSD44_64;
130
/* Old style BSD format. */
131
if (decoder._32_bit_platform) {
132
header_size = GMON_HDRSIZE_OLDBSD_32;
134
header_size = GMON_HDRSIZE_OLDBSD_64;
138
int samp_bytes = ncnt - header_size;
139
int hist_num_bins = samp_bytes / 2;
141
if (!isCompatible(low_pc, high_pc, profrate, hist_num_bins))
143
// TODO exception to normalize
144
throw new RuntimeException("Histogram header's incompatibility among gmon files");
149
this.highpc = high_pc;
150
this.prof_rate = profrate;
151
hist_sample = new int[hist_num_bins]; // Impl note: JVM sets all integers to 0
154
long temp = highpc - lowpc;
155
bucketSize = Math.round(temp/(double)hist_num_bins);
160
* Checks whether the gmon file currently parsed is compatible with the previous one (if any).
164
* @param sample_count
165
* @return whether the gmon file currently parsed is compatible with the previous one (if any).
167
public boolean isCompatible(long lowpc, long highpc, int profrate, int sample_count) {
168
if (!initialized) return true;
170
(this.lowpc == lowpc) &&
171
(this.highpc == highpc) &&
172
(this.prof_rate == profrate) &&
173
(this.hist_sample.length == sample_count)
180
* Reads hitogram record
181
* @param stream a DataInputStream, pointing just after histogram header in a gmon file.
182
* @throws IOException if an IO error occurs
184
public void decodeHistRecord(DataInput stream) throws IOException {
185
for (int i = 0; i<hist_sample.length; i++) {
186
short _rv = stream.readShort();
188
int hist_size = (_rv & 0xFFFF);
189
hist_sample[i] += hist_size;
196
* Print the histogram header, for debug usage.
197
* @param ps a printstream (typically System.out)
199
public void printHistHeader(PrintStream ps)
201
ps.println(" \nHistogram Header : \n");
202
ps.print(" Base pc address of sample buffer = 0x");
203
ps.println(Long.toHexString(lowpc));
204
ps.print(" Max pc address of sampled buffer = 0x");
205
ps.println(Long.toHexString(highpc));
206
ps.print(" Number of histogram samples = ");
207
ps.println(hist_sample.length);
208
ps.print(" Profiling clock rate = ");
209
ps.println(prof_rate);
210
// ps.print(" Physical dimension usually \"seconds\" = ");
211
// ps.println(dimen);
212
ps.print(" Physical dimension abreviation : 's' for \"seconds\" 'm' for \"milliseconds\" = ");
213
ps.println(dimen_abbrev);
217
* Print the histogram, for debug usage.
218
* @param ps a printstream (typically System.out)
220
public void printHistRecords(PrintStream ps) {
222
ps.println(" == HISTOGRAM RECORDS == ");
223
ps.println(" ========================= ");
227
/*ps.println(" \nHistogram Samples : ");
228
ISymbol[] symbols = this.decoder.getProgram().getSymbols();
229
for (ISymbol iSymbol : symbols) {
230
ps.println(iSymbol.getName() + "\t" + iSymbol.getAddress());
232
for (int i = 0; i<hist_sample.length; i++) {
233
ps.println("histSample[" + i + "]\t" + hist_sample[i]);
238
* Assign the hits to the given symbols
241
public void AssignSamplesSymbol()
243
if (hist_sample == null || hist_sample.length == 0) return;
244
ISymbol[] symblist = this.decoder.getProgram().getSymbols();
245
/* read samples and assign to namelist symbols */
247
for (int i = 0; i < hist_sample.length; i++)
249
int ccnt = hist_sample[i];
252
long pcl = lowpc + (bucketSize*i);
253
long pch = pcl+bucketSize;
256
long svalue1 = symblist[j-1].getAddress().getValue().longValue();
257
for (j = j-1; j < symblist.length - 1; j++)
260
svalue1 = symblist[j+1].getAddress().getValue().longValue();
261
/* if high end of tick is below entry address,
262
* go for next tick. */
265
/* if low end of tick into next routine,
266
* go for next routine. */
269
long start_addr = pcl>svalue0?pcl:svalue0;
270
long end_addr = pch<svalue1?pch:svalue1;
271
long overlap = end_addr - start_addr;
274
ISymbol symbol = symblist[j];
275
int time = (int) ((overlap * ccnt) / bucketSize);
276
Bucket bck = new Bucket(start_addr, end_addr, time);
277
addBucket(bck,symbol);
285
private void addBucket(Bucket b, ISymbol s) {
286
HistRoot root = this.decoder.getRootNode();
287
root.addBucket(b, s, decoder.getProgram());
291
* @return the prof_rate
293
public int getProf_rate() {
299
* @return 's' for seconds, 'm' for ms, 'u' for �s....
301
public char getTimeDimension() {
306
* get the bucket size
308
public long getBucketSize(){