HeapPanelpublic final class HeapPanel extends BaseHeapPanel Base class for our information panels. |
Fields Summary |
---|
private static final String | PREFS_STATS_COL_TYPE | private static final String | PREFS_STATS_COL_COUNT | private static final String | PREFS_STATS_COL_SIZE | private static final String | PREFS_STATS_COL_SMALLEST | private static final String | PREFS_STATS_COL_LARGEST | private static final String | PREFS_STATS_COL_MEDIAN | private static final String | PREFS_STATS_COL_AVERAGE | private static final int | NOT_SELECTED | private static final int | NOT_ENABLED | private static final int | ENABLED | private static final int | NUM_PALETTE_ENTRIEScolor palette and map legend. NATIVE is the last enum is a 0 based enum list, so we need
Native+1 at least. We also need 2 more entries for free area and expansion area. | private static final String[] | mMapLegend | private static final org.eclipse.swt.graphics.PaletteData | mMapPalette | private static final boolean | DISPLAY_HEAP_BITMAP | private static final boolean | DISPLAY_HILBERT_BITMAP | private static final int | PLACEHOLDER_HILBERT_SIZE | private static final int | PLACEHOLDER_LINEAR_V_SIZE | private static final int | PLACEHOLDER_LINEAR_H_SIZE | private static final int[] | ZOOMS | private static final NumberFormat | sByteFormatter | private static final NumberFormat | sLargeByteFormatter | private static final NumberFormat | sCountFormatter | private org.eclipse.swt.widgets.Display | mDisplay | private org.eclipse.swt.widgets.Composite | mTop | private org.eclipse.swt.widgets.Label | mUpdateStatus | private org.eclipse.swt.widgets.Table | mHeapSummary | private org.eclipse.swt.widgets.Combo | mDisplayMode | private org.eclipse.swt.widgets.Composite | mDisplayBase | private org.eclipse.swt.custom.StackLayout | mDisplayStack | private org.eclipse.swt.widgets.Composite | mStatisticsBase | private org.eclipse.swt.widgets.Table | mStatisticsTable | private org.jfree.chart.JFreeChart | mChart | private org.jfree.experimental.chart.swt.ChartComposite | mChartComposite | private org.eclipse.swt.widgets.Button | mGcButton | private org.jfree.data.category.DefaultCategoryDataset | mAllocCountDataSet | private org.eclipse.swt.widgets.Composite | mLinearBase | private org.eclipse.swt.widgets.Label | mLinearHeapImage | private org.eclipse.swt.widgets.Composite | mHilbertBase | private org.eclipse.swt.widgets.Label | mHilbertHeapImage | private org.eclipse.swt.widgets.Group | mLegend | private org.eclipse.swt.widgets.Combo | mZoom | private org.eclipse.swt.graphics.Image | mHilbertImageImage used for the hilbert display. Since we recreate a new image every time, we
keep this one around to dispose it. | private org.eclipse.swt.graphics.Image | mLinearImage | private org.eclipse.swt.widgets.Composite[] | mLayout | private static final int | HILBERT_DIR_N | private static final int | HILBERT_DIR_S | private static final int | HILBERT_DIR_E | private static final int | HILBERT_DIR_W |
Methods Summary |
---|
private static java.lang.String | addCommasToNumber(long num)
return sCountFormatter.format(num);
| private static java.lang.String | approximateByteCount(long bytes)
double fracBytes = bytes;
String units = "";
if (fracBytes >= 1024) {
fracBytes /= 1024;
units = "K";
}
if (fracBytes >= 1024) {
fracBytes /= 1024;
units = "M";
}
if (fracBytes >= 1024) {
fracBytes /= 1024;
units = "G";
}
return sByteFormatter.format(fracBytes) + units;
| public void | clientChanged(com.android.ddmlib.Client client, int changeMask)Sent when an existing client information changed.
This is sent from a non UI thread.
if (client == getCurrentClient()) {
if ((changeMask & Client.CHANGE_HEAP_MODE) == Client.CHANGE_HEAP_MODE ||
(changeMask & Client.CHANGE_HEAP_DATA) == Client.CHANGE_HEAP_DATA) {
try {
mTop.getDisplay().asyncExec(new Runnable() {
public void run() {
clientSelected();
}
});
} catch (SWTException e) {
// display is disposed (app is quitting most likely), we do nothing.
}
}
}
| public void | clientSelected()Sent when a new client is selected. The new client can be accessed
with {@link #getCurrentClient()}.
if (mTop.isDisposed())
return;
Client client = getCurrentClient();
Log.d("ddms", "HeapPanel: changed " + client);
if (client != null) {
ClientData cd = client.getClientData();
if (client.isHeapUpdateEnabled()) {
mGcButton.setEnabled(true);
mDisplayMode.setEnabled(true);
setUpdateStatus(ENABLED);
} else {
setUpdateStatus(NOT_ENABLED);
mGcButton.setEnabled(false);
mDisplayMode.setEnabled(false);
}
fillSummaryTable(cd);
int mode = mDisplayMode.getSelectionIndex();
if (mode == 0) {
fillDetailedTable(client, false /* forceRedraw */);
} else {
if (DISPLAY_HEAP_BITMAP) {
renderHeapData(cd, mode - 1, false /* forceRedraw */);
}
}
} else {
mGcButton.setEnabled(false);
mDisplayMode.setEnabled(false);
fillSummaryTable(null);
fillDetailedTable(null, true);
setUpdateStatus(NOT_SELECTED);
}
// sizes of things change frequently, so redo layout
//mScrolledComposite.setMinSize(mDisplayStack.topControl.computeSize(SWT.DEFAULT,
// SWT.DEFAULT));
mDisplayBase.layout();
//mScrolledComposite.redraw();
| private void | createChart()Creates the chart below the statistics table
mAllocCountDataSet = new DefaultCategoryDataset();
mChart = ChartFactory.createBarChart(null, "Size", "Count", mAllocCountDataSet,
PlotOrientation.VERTICAL, false, true, false);
// get the font to make a proper title. We need to convert the swt font,
// into an awt font.
Font f = mStatisticsBase.getFont();
FontData[] fData = f.getFontData();
// event though on Mac OS there could be more than one fontData, we'll only use
// the first one.
FontData firstFontData = fData[0];
java.awt.Font awtFont = SWTUtils.toAwtFont(mStatisticsBase.getDisplay(),
firstFontData, true /* ensureSameSize */);
mChart.setTitle(new TextTitle("Allocation count per size", awtFont));
Plot plot = mChart.getPlot();
if (plot instanceof CategoryPlot) {
// get the plot
CategoryPlot categoryPlot = (CategoryPlot)plot;
// set the domain axis to draw labels that are displayed even with many values.
CategoryAxis domainAxis = categoryPlot.getDomainAxis();
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_90);
CategoryItemRenderer renderer = categoryPlot.getRenderer();
renderer.setBaseToolTipGenerator(new CategoryToolTipGenerator() {
public String generateToolTip(CategoryDataset dataset, int row, int column) {
// get the key for the size of the allocation
ByteLong columnKey = (ByteLong)dataset.getColumnKey(column);
String rowKey = (String)dataset.getRowKey(row);
Number value = dataset.getValue(rowKey, columnKey);
return String.format("%1$d %2$s of %3$d bytes", value.intValue(), rowKey,
columnKey.getValue());
}
});
}
mChartComposite = new ChartComposite(mStatisticsBase, SWT.BORDER, mChart,
ChartComposite.DEFAULT_WIDTH,
ChartComposite.DEFAULT_HEIGHT,
ChartComposite.DEFAULT_MINIMUM_DRAW_WIDTH,
ChartComposite.DEFAULT_MINIMUM_DRAW_HEIGHT,
3000, // max draw width. We don't want it to zoom, so we put a big number
3000, // max draw height. We don't want it to zoom, so we put a big number
true, // off-screen buffer
true, // properties
true, // save
true, // print
false, // zoom
true); // tooltips
mChartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
| private org.eclipse.swt.graphics.Image | createColorRect(org.eclipse.swt.widgets.Display display, org.eclipse.swt.graphics.RGB color)
int width = 32;
int height = 16;
Image img = new Image(display, width, height);
GC gc = new GC(img);
gc.setBackground(new Color(display, color));
gc.fillRectangle(0, 0, width, height);
gc.dispose();
return img;
| protected org.eclipse.swt.widgets.Control | createControl(org.eclipse.swt.widgets.Composite parent)Create our control(s).
mDisplay = parent.getDisplay();
GridLayout gl;
mTop = new Composite(parent, SWT.NONE);
mTop.setLayout(new GridLayout(1, false));
mTop.setLayoutData(new GridData(GridData.FILL_BOTH));
mUpdateStatus = new Label(mTop, SWT.NONE);
setUpdateStatus(NOT_SELECTED);
Composite summarySection = new Composite(mTop, SWT.NONE);
summarySection.setLayout(gl = new GridLayout(2, false));
gl.marginHeight = gl.marginWidth = 0;
mHeapSummary = createSummaryTable(summarySection);
mGcButton = new Button(summarySection, SWT.PUSH);
mGcButton.setText("Cause GC");
mGcButton.setEnabled(false);
mGcButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Client client = getCurrentClient();
if (client != null) {
client.executeGarbageCollector();
}
}
});
Composite comboSection = new Composite(mTop, SWT.NONE);
gl = new GridLayout(2, false);
gl.marginHeight = gl.marginWidth = 0;
comboSection.setLayout(gl);
Label displayLabel = new Label(comboSection, SWT.NONE);
displayLabel.setText("Display: ");
mDisplayMode = new Combo(comboSection, SWT.READ_ONLY);
mDisplayMode.setEnabled(false);
mDisplayMode.add("Stats");
if (DISPLAY_HEAP_BITMAP) {
mDisplayMode.add("Linear");
if (DISPLAY_HILBERT_BITMAP) {
mDisplayMode.add("Hilbert");
}
}
// the base of the displays.
mDisplayBase = new Composite(mTop, SWT.NONE);
mDisplayBase.setLayoutData(new GridData(GridData.FILL_BOTH));
mDisplayStack = new StackLayout();
mDisplayBase.setLayout(mDisplayStack);
// create the statistics display
mStatisticsBase = new Composite(mDisplayBase, SWT.NONE);
//mStatisticsBase.setLayoutData(new GridData(GridData.FILL_BOTH));
mStatisticsBase.setLayout(gl = new GridLayout(1, false));
gl.marginHeight = gl.marginWidth = 0;
mDisplayStack.topControl = mStatisticsBase;
mStatisticsTable = createDetailedTable(mStatisticsBase);
mStatisticsTable.setLayoutData(new GridData(GridData.FILL_BOTH));
createChart();
//create the linear composite
mLinearBase = new Composite(mDisplayBase, SWT.NONE);
//mLinearBase.setLayoutData(new GridData());
gl = new GridLayout(1, false);
gl.marginHeight = gl.marginWidth = 0;
mLinearBase.setLayout(gl);
{
mLinearHeapImage = new Label(mLinearBase, SWT.NONE);
mLinearHeapImage.setLayoutData(new GridData());
mLinearHeapImage.setImage(ImageHelper.createPlaceHolderArt(mDisplay,
PLACEHOLDER_LINEAR_H_SIZE, PLACEHOLDER_LINEAR_V_SIZE,
mDisplay.getSystemColor(SWT.COLOR_BLUE)));
// create a composite to contain the bottom part (legend)
Composite bottomSection = new Composite(mLinearBase, SWT.NONE);
gl = new GridLayout(1, false);
gl.marginHeight = gl.marginWidth = 0;
bottomSection.setLayout(gl);
createLegend(bottomSection);
}
/*
mScrolledComposite = new ScrolledComposite(mTop, SWT.H_SCROLL | SWT.V_SCROLL);
mScrolledComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
mScrolledComposite.setExpandHorizontal(true);
mScrolledComposite.setExpandVertical(true);
mScrolledComposite.setContent(mDisplayBase);
*/
// create the hilbert display.
mHilbertBase = new Composite(mDisplayBase, SWT.NONE);
//mHilbertBase.setLayoutData(new GridData());
gl = new GridLayout(2, false);
gl.marginHeight = gl.marginWidth = 0;
mHilbertBase.setLayout(gl);
if (DISPLAY_HILBERT_BITMAP) {
mHilbertHeapImage = new Label(mHilbertBase, SWT.NONE);
mHilbertHeapImage.setLayoutData(new GridData());
mHilbertHeapImage.setImage(ImageHelper.createPlaceHolderArt(mDisplay,
PLACEHOLDER_HILBERT_SIZE, PLACEHOLDER_HILBERT_SIZE,
mDisplay.getSystemColor(SWT.COLOR_BLUE)));
// create a composite to contain the right part (legend + zoom)
Composite rightSection = new Composite(mHilbertBase, SWT.NONE);
gl = new GridLayout(1, false);
gl.marginHeight = gl.marginWidth = 0;
rightSection.setLayout(gl);
Composite zoomComposite = new Composite(rightSection, SWT.NONE);
gl = new GridLayout(2, false);
zoomComposite.setLayout(gl);
Label l = new Label(zoomComposite, SWT.NONE);
l.setText("Zoom:");
mZoom = new Combo(zoomComposite, SWT.READ_ONLY);
for (int z : ZOOMS) {
mZoom.add(String.format("%1$d%%", z)); // $NON-NLS-1$
}
mZoom.select(0);
mZoom.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
setLegendText(mZoom.getSelectionIndex());
Client client = getCurrentClient();
if (client != null) {
renderHeapData(client.getClientData(), 1, true);
mTop.pack();
}
}
});
createLegend(rightSection);
}
mHilbertBase.pack();
mLayout = new Composite[] { mStatisticsBase, mLinearBase, mHilbertBase };
mDisplayMode.select(0);
mDisplayMode.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
int index = mDisplayMode.getSelectionIndex();
Client client = getCurrentClient();
if (client != null) {
if (index == 0) {
fillDetailedTable(client, true /* forceRedraw */);
} else {
renderHeapData(client.getClientData(), index-1, true /* forceRedraw */);
}
}
mDisplayStack.topControl = mLayout[index];
//mScrolledComposite.setMinSize(mDisplayStack.topControl.computeSize(SWT.DEFAULT,
// SWT.DEFAULT));
mDisplayBase.layout();
//mScrolledComposite.redraw();
}
});
//mScrolledComposite.setMinSize(mDisplayStack.topControl.computeSize(SWT.DEFAULT,
// SWT.DEFAULT));
mDisplayBase.layout();
//mScrolledComposite.redraw();
return mTop;
| private org.eclipse.swt.widgets.Table | createDetailedTable(org.eclipse.swt.widgets.Composite base)
IPreferenceStore store = DdmUiPreferences.getStore();
Table tab = new Table(base, SWT.SINGLE | SWT.FULL_SELECTION);
tab.setHeaderVisible(true);
tab.setLinesVisible(true);
TableHelper.createTableColumn(tab, "Type", SWT.LEFT,
"4-byte array (object[], int[], float[])", //$NON-NLS-1$
PREFS_STATS_COL_TYPE, store);
TableHelper.createTableColumn(tab, "Count", SWT.RIGHT,
"00,000", //$NON-NLS-1$
PREFS_STATS_COL_COUNT, store);
TableHelper.createTableColumn(tab, "Total Size", SWT.RIGHT,
"000.000 WW", //$NON-NLS-1$
PREFS_STATS_COL_SIZE, store);
TableHelper.createTableColumn(tab, "Smallest", SWT.RIGHT,
"000.000 WW", //$NON-NLS-1$
PREFS_STATS_COL_SMALLEST, store);
TableHelper.createTableColumn(tab, "Largest", SWT.RIGHT,
"000.000 WW", //$NON-NLS-1$
PREFS_STATS_COL_LARGEST, store);
TableHelper.createTableColumn(tab, "Median", SWT.RIGHT,
"000.000 WW", //$NON-NLS-1$
PREFS_STATS_COL_MEDIAN, store);
TableHelper.createTableColumn(tab, "Average", SWT.RIGHT,
"000.000 WW", //$NON-NLS-1$
PREFS_STATS_COL_AVERAGE, store);
tab.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
Client client = getCurrentClient();
if (client != null) {
int index = mStatisticsTable.getSelectionIndex();
TableItem item = mStatisticsTable.getItem(index);
if (item != null) {
Map<Integer, ArrayList<HeapSegmentElement>> heapMap =
client.getClientData().getVmHeapData().getProcessedHeapMap();
ArrayList<HeapSegmentElement> list = heapMap.get(item.getData());
if (list != null) {
showChart(list);
}
}
}
}
});
return tab;
| private org.eclipse.swt.graphics.ImageData | createHilbertHeapImage(byte[] pixData)
int w, h;
// Pick an image size that the largest of heaps will fit into.
w = (int)Math.sqrt((double)((16 * 1024 * 1024)/8));
// Space-filling curves require a power-of-2 width.
w = nextPow2(w);
h = w;
// Create the heap image.
ImageData id = new ImageData(w, h, 8, mMapPalette);
// Copy the data into the image
//int maxX = zOrderData(id, pixData);
Point maxP = hilbertOrderData(id, pixData);
// update the max size to make it a round number once the zoom is applied
int factor = 100 / ZOOMS[mZoom.getSelectionIndex()];
if (factor != 1) {
int tmp = maxP.x % factor;
if (tmp != 0) {
maxP.x += factor - tmp;
}
tmp = maxP.y % factor;
if (tmp != 0) {
maxP.y += factor - tmp;
}
}
if (maxP.y < id.height) {
// Crop the image down to the interesting part.
id = new ImageData(id.width, maxP.y, id.depth, id.palette,
id.scanlinePad, id.data);
}
if (maxP.x < id.width) {
// crop the image again. A bit trickier this time.
ImageData croppedId = new ImageData(maxP.x, id.height, id.depth, id.palette);
int[] buffer = new int[maxP.x];
for (int l = 0 ; l < id.height; l++) {
id.getPixels(0, l, maxP.x, buffer, 0);
croppedId.setPixels(0, l, maxP.x, buffer, 0);
}
id = croppedId;
}
// apply the zoom
if (factor != 1) {
id = id.scaledTo(id.width / factor, id.height / factor);
}
return id;
| private void | createLegend(org.eclipse.swt.widgets.Composite parent)
mLegend = new Group(parent, SWT.NONE);
mLegend.setText(getLegendText(0));
mLegend.setLayout(new GridLayout(2, false));
RGB[] colors = mMapPalette.colors;
for (int i = 0; i < NUM_PALETTE_ENTRIES; i++) {
Image tmpImage = createColorRect(parent.getDisplay(), colors[i]);
Label l = new Label(mLegend, SWT.NONE);
l.setImage(tmpImage);
l = new Label(mLegend, SWT.NONE);
l.setText(mMapLegend[i]);
}
| private static org.eclipse.swt.graphics.PaletteData | createPalette()
RGB colors[] = new RGB[NUM_PALETTE_ENTRIES];
colors[0]
= new RGB(192, 192, 192); // non-heap pixels are gray
mMapLegend[0]
= "(heap expansion area)";
colors[1]
= new RGB(0, 0, 0); // free chunks are black
mMapLegend[1]
= "free";
colors[HeapSegmentElement.KIND_OBJECT + 2]
= new RGB(0, 0, 255); // objects are blue
mMapLegend[HeapSegmentElement.KIND_OBJECT + 2]
= "data object";
colors[HeapSegmentElement.KIND_CLASS_OBJECT + 2]
= new RGB(0, 255, 0); // class objects are green
mMapLegend[HeapSegmentElement.KIND_CLASS_OBJECT + 2]
= "class object";
colors[HeapSegmentElement.KIND_ARRAY_1 + 2]
= new RGB(255, 0, 0); // byte/bool arrays are red
mMapLegend[HeapSegmentElement.KIND_ARRAY_1 + 2]
= "1-byte array (byte[], boolean[])";
colors[HeapSegmentElement.KIND_ARRAY_2 + 2]
= new RGB(255, 128, 0); // short/char arrays are orange
mMapLegend[HeapSegmentElement.KIND_ARRAY_2 + 2]
= "2-byte array (short[], char[])";
colors[HeapSegmentElement.KIND_ARRAY_4 + 2]
= new RGB(255, 255, 0); // obj/int/float arrays are yellow
mMapLegend[HeapSegmentElement.KIND_ARRAY_4 + 2]
= "4-byte array (object[], int[], float[])";
colors[HeapSegmentElement.KIND_ARRAY_8 + 2]
= new RGB(255, 128, 128); // long/double arrays are pink
mMapLegend[HeapSegmentElement.KIND_ARRAY_8 + 2]
= "8-byte array (long[], double[])";
colors[HeapSegmentElement.KIND_UNKNOWN + 2]
= new RGB(255, 0, 255); // unknown objects are cyan
mMapLegend[HeapSegmentElement.KIND_UNKNOWN + 2]
= "unknown object";
colors[HeapSegmentElement.KIND_NATIVE + 2]
= new RGB(64, 64, 64); // native objects are dark gray
mMapLegend[HeapSegmentElement.KIND_NATIVE + 2]
= "non-Java object";
return new PaletteData(colors);
| private org.eclipse.swt.widgets.Table | createSummaryTable(org.eclipse.swt.widgets.Composite base)
Table tab = new Table(base, SWT.SINGLE | SWT.FULL_SELECTION);
tab.setHeaderVisible(true);
tab.setLinesVisible(true);
TableColumn col;
col = new TableColumn(tab, SWT.RIGHT);
col.setText("ID");
col.pack();
col = new TableColumn(tab, SWT.RIGHT);
col.setText("000.000WW"); // $NON-NLS-1$
col.pack();
col.setText("Heap Size");
col = new TableColumn(tab, SWT.RIGHT);
col.setText("000.000WW"); // $NON-NLS-1$
col.pack();
col.setText("Allocated");
col = new TableColumn(tab, SWT.RIGHT);
col.setText("000.000WW"); // $NON-NLS-1$
col.pack();
col.setText("Free");
col = new TableColumn(tab, SWT.RIGHT);
col.setText("000.00%"); // $NON-NLS-1$
col.pack();
col.setText("% Used");
col = new TableColumn(tab, SWT.RIGHT);
col.setText("000,000,000"); // $NON-NLS-1$
col.pack();
col.setText("# Objects");
return tab;
| public void | deviceSelected()Sent when a new device is selected. The new device can be accessed
with {@link #getCurrentDevice()}
// pass
| private void | fillDetailedTable(com.android.ddmlib.Client client, boolean forceRedraw)
// first check if the client is invalid or heap updates are not enabled.
if (client == null || client.isHeapUpdateEnabled() == false) {
mStatisticsTable.removeAll();
showChart(null);
return;
}
ClientData cd = client.getClientData();
Map<Integer, ArrayList<HeapSegmentElement>> heapMap;
// Atomically get and clear the heap data.
synchronized (cd) {
if (serializeHeapData(cd.getVmHeapData()) == false && forceRedraw == false) {
// no change, we return.
return;
}
heapMap = cd.getVmHeapData().getProcessedHeapMap();
}
// we have new data, lets display it.
// First, get the current selection, and its key.
int index = mStatisticsTable.getSelectionIndex();
Integer selectedKey = null;
if (index != -1) {
selectedKey = (Integer)mStatisticsTable.getItem(index).getData();
}
// disable redraws and remove all from the table.
mStatisticsTable.setRedraw(false);
mStatisticsTable.removeAll();
if (heapMap != null) {
int selectedIndex = -1;
ArrayList<HeapSegmentElement> selectedList = null;
// get the keys
Set<Integer> keys = heapMap.keySet();
int iter = 0; // use a manual iter int because Set<?> doesn't have an index
// based accessor.
for (Integer key : keys) {
ArrayList<HeapSegmentElement> list = heapMap.get(key);
// check if this is the key that is supposed to be selected
if (key.equals(selectedKey)) {
selectedIndex = iter;
selectedList = list;
}
iter++;
TableItem item = new TableItem(mStatisticsTable, SWT.NONE);
item.setData(key);
// get the type
item.setText(0, mMapLegend[key]);
// set the count, smallest, largest
int count = list.size();
item.setText(1, addCommasToNumber(count));
if (count > 0) {
item.setText(3, prettyByteCount(list.get(0).getLength()));
item.setText(4, prettyByteCount(list.get(count-1).getLength()));
int median = count / 2;
HeapSegmentElement element = list.get(median);
long size = element.getLength();
item.setText(5, prettyByteCount(size));
long totalSize = 0;
for (int i = 0 ; i < count; i++) {
element = list.get(i);
size = element.getLength();
totalSize += size;
}
// set the average and total
item.setText(2, prettyByteCount(totalSize));
item.setText(6, prettyByteCount(totalSize / count));
}
}
mStatisticsTable.setRedraw(true);
if (selectedIndex != -1) {
mStatisticsTable.setSelection(selectedIndex);
showChart(selectedList);
} else {
showChart(null);
}
} else {
mStatisticsTable.setRedraw(true);
}
| private void | fillSummaryTable(com.android.ddmlib.ClientData cd)
if (mHeapSummary.isDisposed()) {
return;
}
mHeapSummary.setRedraw(false);
mHeapSummary.removeAll();
if (cd != null) {
synchronized (cd) {
Iterator<Integer> iter = cd.getVmHeapIds();
while (iter.hasNext()) {
Integer id = iter.next();
Map<String, Long> heapInfo = cd.getVmHeapInfo(id);
if (heapInfo == null) {
continue;
}
long sizeInBytes = heapInfo.get(ClientData.HEAP_SIZE_BYTES);
long bytesAllocated = heapInfo.get(ClientData.HEAP_BYTES_ALLOCATED);
long objectsAllocated = heapInfo.get(ClientData.HEAP_OBJECTS_ALLOCATED);
TableItem item = new TableItem(mHeapSummary, SWT.NONE);
item.setText(0, id.toString());
item.setText(1, prettyByteCount(sizeInBytes));
item.setText(2, prettyByteCount(bytesAllocated));
item.setText(3, prettyByteCount(sizeInBytes - bytesAllocated));
item.setText(4, fractionalPercent(bytesAllocated, sizeInBytes));
item.setText(5, addCommasToNumber(objectsAllocated));
}
}
}
mHeapSummary.pack();
mHeapSummary.setRedraw(true);
| private static java.lang.String | fractionalPercent(long num, long denom)
double val = (double)num / (double)denom;
val *= 100;
NumberFormat nf = NumberFormat.getInstance();
nf.setMinimumFractionDigits(2);
nf.setMaximumFractionDigits(2);
return nf.format(val) + "%";
| private java.lang.String | getLegendText(int level)
int bytes = 8 * (100 / ZOOMS[level]);
return String.format("Key (1 pixel = %1$d bytes)", bytes);
| private org.eclipse.swt.graphics.Point | hilbertOrderData(org.eclipse.swt.graphics.ImageData id, byte[] pixData)
int order = 0;
for (int n = 1; n < id.width; n *= 2) {
order++;
}
/* Skanky; use an otherwise-unused ImageData field
* to keep track of maxX.
*/
Point p = new Point(0,0);
int oldIdX = id.x;
int oldIdY = id.y;
id.x = id.y = 0;
try {
hilbertWalk(id, new ByteArrayInputStream(pixData),
order, 0, 0, HILBERT_DIR_E);
p.x = id.x;
p.y = id.y;
} catch (IOException ex) {
System.err.println("Exception during hilbertWalk()");
p.x = id.height;
p.y = id.width;
}
id.x = oldIdX;
id.y = oldIdY;
return p;
| private void | hilbertWalk(org.eclipse.swt.graphics.ImageData id, java.io.InputStream pixData, int order, int x, int y, int dir)
if (x >= id.width || y >= id.height) {
return;
} else if (order == 0) {
try {
int p = pixData.read();
if (p >= 0) {
// flip along x=y axis; assume width == height
id.setPixel(y, x, p);
/* Skanky; use an otherwise-unused ImageData field
* to keep track of the max x,y used. Note that x and y are inverted.
*/
if (y > id.x) {
id.x = y;
}
if (x > id.y) {
id.y = x;
}
}
//xxx just give up; don't bother walking the rest of the image
} catch (IllegalArgumentException ex) {
System.out.println("bad pixels: order " + order +
", dir " + dir +
", w " + id.width +
", h " + id.height +
", x " + x +
", y " + y);
throw ex;
}
} else {
order--;
int delta = 1 << order;
int nextX = x + delta;
int nextY = y + delta;
switch (dir) {
case HILBERT_DIR_E:
hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_N);
hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_E);
hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_E);
hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_S);
break;
case HILBERT_DIR_N:
hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_E);
hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_N);
hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_N);
hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_W);
break;
case HILBERT_DIR_S:
hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_W);
hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_S);
hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_S);
hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_E);
break;
case HILBERT_DIR_W:
hilbertWalk(id, pixData, order, nextX, nextY, HILBERT_DIR_S);
hilbertWalk(id, pixData, order, nextX, y, HILBERT_DIR_W);
hilbertWalk(id, pixData, order, x, y, HILBERT_DIR_W);
hilbertWalk(id, pixData, order, x, nextY, HILBERT_DIR_N);
break;
default:
throw new RuntimeException("Unexpected Hilbert direction " +
dir);
}
}
| private int | nextPow2(int value)Return the closest power of two greater than or equal to value.
for (int i = 31; i >= 0; --i) {
if ((value & (1<<i)) != 0) {
if (i < 31) {
return 1<<(i + 1);
} else {
return 1<<31;
}
}
}
return 0;
| private static java.lang.String | prettyByteCount(long bytes)
double fracBytes = bytes;
String units = " B";
if (fracBytes < 1024) {
return sByteFormatter.format(fracBytes) + units;
} else {
fracBytes /= 1024;
units = " KB";
}
if (fracBytes >= 1024) {
fracBytes /= 1024;
units = " MB";
}
if (fracBytes >= 1024) {
fracBytes /= 1024;
units = " GB";
}
return sLargeByteFormatter.format(fracBytes) + units;
| private void | renderHeapData(com.android.ddmlib.ClientData cd, int mode, boolean forceRedraw)Convert the raw heap data to an image. We know we're running in
the UI thread, so we can issue graphics commands directly.
http://help.eclipse.org/help31/nftopic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/graphics/GC.html
Image image;
byte[] pixData;
// Atomically get and clear the heap data.
synchronized (cd) {
if (serializeHeapData(cd.getVmHeapData()) == false && forceRedraw == false) {
// no change, we return.
return;
}
pixData = getSerializedData();
}
if (pixData != null) {
ImageData id;
if (mode == 1) {
id = createHilbertHeapImage(pixData);
} else {
id = createLinearHeapImage(pixData, 200, mMapPalette);
}
image = new Image(mDisplay, id);
} else {
// Render a placeholder image.
int width, height;
if (mode == 1) {
width = height = PLACEHOLDER_HILBERT_SIZE;
} else {
width = PLACEHOLDER_LINEAR_H_SIZE;
height = PLACEHOLDER_LINEAR_V_SIZE;
}
image = new Image(mDisplay, width, height);
GC gc = new GC(image);
gc.setForeground(mDisplay.getSystemColor(SWT.COLOR_RED));
gc.drawLine(0, 0, width-1, height-1);
gc.dispose();
gc = null;
}
// set the new image
if (mode == 1) {
if (mHilbertImage != null) {
mHilbertImage.dispose();
}
mHilbertImage = image;
mHilbertHeapImage.setImage(mHilbertImage);
mHilbertHeapImage.pack(true);
mHilbertBase.layout();
mHilbertBase.pack(true);
} else {
if (mLinearImage != null) {
mLinearImage.dispose();
}
mLinearImage = image;
mLinearHeapImage.setImage(mLinearImage);
mLinearHeapImage.pack(true);
mLinearBase.layout();
mLinearBase.pack(true);
}
| public void | setFocus()Sets the focus to the proper control inside the panel.
mHeapSummary.setFocus();
| private void | setLegendText(int level)
mLegend.setText(getLegendText(level));
| protected void | setTableFocusListener()
addTableToFocusListener(mHeapSummary);
| private void | setUpdateStatus(int status)
switch (status) {
case NOT_SELECTED:
mUpdateStatus.setText("Select a client to see heap updates");
break;
case NOT_ENABLED:
mUpdateStatus.setText("Heap updates are " +
"NOT ENABLED for this client");
break;
case ENABLED:
mUpdateStatus.setText("Heap updates will happen after " +
"every GC for this client");
break;
default:
throw new RuntimeException();
}
mUpdateStatus.pack();
| private void | showChart(java.util.ArrayList list)Fills the chart with the content of the list of {@link HeapSegmentElement}.
mAllocCountDataSet.clear();
if (list != null) {
String rowKey = "Alloc Count";
long currentSize = -1;
int currentCount = 0;
for (HeapSegmentElement element : list) {
if (element.getLength() != currentSize) {
if (currentSize != -1) {
ByteLong columnKey = new ByteLong(currentSize);
mAllocCountDataSet.addValue(currentCount, rowKey, columnKey);
}
currentSize = element.getLength();
currentCount = 1;
} else {
currentCount++;
}
}
// add the last item
if (currentSize != -1) {
ByteLong columnKey = new ByteLong(currentSize);
mAllocCountDataSet.addValue(currentCount, rowKey, columnKey);
}
}
| private int | zOrderData(org.eclipse.swt.graphics.ImageData id, byte[] pixData)
int maxX = 0;
for (int i = 0; i < pixData.length; i++) {
/* Tread the pixData index as a z-order curve index and
* decompose into Cartesian coordinates.
*/
int x = (i & 1) |
((i >>> 2) & 1) << 1 |
((i >>> 4) & 1) << 2 |
((i >>> 6) & 1) << 3 |
((i >>> 8) & 1) << 4 |
((i >>> 10) & 1) << 5 |
((i >>> 12) & 1) << 6 |
((i >>> 14) & 1) << 7 |
((i >>> 16) & 1) << 8 |
((i >>> 18) & 1) << 9 |
((i >>> 20) & 1) << 10 |
((i >>> 22) & 1) << 11 |
((i >>> 24) & 1) << 12 |
((i >>> 26) & 1) << 13 |
((i >>> 28) & 1) << 14 |
((i >>> 30) & 1) << 15;
int y = ((i >>> 1) & 1) << 0 |
((i >>> 3) & 1) << 1 |
((i >>> 5) & 1) << 2 |
((i >>> 7) & 1) << 3 |
((i >>> 9) & 1) << 4 |
((i >>> 11) & 1) << 5 |
((i >>> 13) & 1) << 6 |
((i >>> 15) & 1) << 7 |
((i >>> 17) & 1) << 8 |
((i >>> 19) & 1) << 9 |
((i >>> 21) & 1) << 10 |
((i >>> 23) & 1) << 11 |
((i >>> 25) & 1) << 12 |
((i >>> 27) & 1) << 13 |
((i >>> 29) & 1) << 14 |
((i >>> 31) & 1) << 15;
try {
id.setPixel(x, y, pixData[i]);
if (x > maxX) {
maxX = x;
}
} catch (IllegalArgumentException ex) {
System.out.println("bad pixels: i " + i +
", w " + id.width +
", h " + id.height +
", x " + x +
", y " + y);
throw ex;
}
}
return maxX;
|
|