VBoxDbgStats.cpp revision ec9a11eb28318df36cc0c39d53454ac2729e932e
/* $Id$ */
/** @file
* VBox Debugger GUI - Statistics.
*/
/*
* Copyright (C) 2006-2007 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DBGG
#include "VBoxDbgStats.h"
#ifdef VBOXDBG_USE_QT4
# include <QLocale>
# include <QPushButton>
# include <QSpinBox>
# include <QLabel>
# include <QClipboard>
# include <QApplication>
# include <QHBoxLayout>
# include <QVBoxLayout>
#else
# include <qlocale.h>
# include <qpushbutton.h>
# include <qspinbox.h>
# include <qlabel.h>
# include <qclipboard.h>
# include <qapplication.h>
#endif
#include <stdio.h> //remove me
/**
* Gets the last component of a statistics name string.
*
* @returns the last component in the name string.
*/
const char *getNodeName(const char *pszName)
{
}
/*
*
* V B o x D b g S t a t s I t e m
* V B o x D b g S t a t s I t e m
* V B o x D b g S t a t s I t e m
*
*/
VBoxDbgStatsItem::VBoxDbgStatsItem(const char *pszName, VBoxDbgStatsItem *pParent, bool fBranch /*= true*/)
#ifdef VBOXDBG_USE_QT4
#else
#endif
{
}
VBoxDbgStatsItem::VBoxDbgStatsItem(const char *pszName, QListView *pParent, bool fBranch/* = true*/)
#ifdef VBOXDBG_USE_QT4
#else
#endif
{
}
{
}
{
/* Iterate and print our children. */
#ifdef VBOXDBG_USE_QT4
int cChildren = childCount();
for (int i = 0; i < cChildren; i++)
{
}
#else
{
}
#endif
}
{
/* Iterate and stringify our children. */
#ifdef VBOXDBG_USE_QT4
int cChildren = childCount();
for (int i = 0; i < cChildren; i++)
{
}
#else
{
}
#endif
}
void VBoxDbgStatsItem::copyTreeToClipboard(void) const
{
if (pClipboard)
}
/*
*
* V B o x D b g S t a t s L e a f I t e m
* V B o x D b g S t a t s L e a f I t e m
* V B o x D b g S t a t s L e a f I t e m
*
*/
{
}
{
}
/**
* Formats a number into a 64-byte buffer.
*/
{
static const char s_szDigits[] = "0123456789";
psz += 63;
*psz-- = '\0';
unsigned cDigits = 0;
for (;;)
{
u64 /= 10;
if (!u64)
break;
psz--;
if (!(++cDigits % 3))
*psz-- = ',';
}
return psz;
}
/**
* Formats a number into a 64-byte buffer.
* (18.446.744.073.709.551.615)
*/
{
static const char s_szDigits[] = "0123456789";
psz += 63;
*psz-- = '\0';
unsigned cDigits = 0;
for (;;)
{
u64 /= 10;
if (!u64)
break;
psz--;
if (!(++cDigits % 3))
*psz-- = ',';
}
if (fNegative)
*--psz = '-';
return psz;
}
/**
* Formats a unsigned hexadecimal number into a into a 64-byte buffer.
*/
{
static const char s_szDigits[] = "0123456789abcdef";
psz += 63;
*psz-- = '\0';
unsigned cDigits = 0;
for (;;)
{
u64 /= 16;
++cDigits;
break;
psz--;
if (!(cDigits % 8))
*psz-- = '\'';
}
return psz;
}
/**
* Formats a sort key number.
*/
{
static const char s_szDigits[] = "0123456789abcdef";
/* signed */
*psz++ = '+';
/* 16 hex digits */
unsigned i = 16;
while (i-- > 0)
{
if (u64)
{
u64 /= 16;
}
else
psz[i] = '0';
}
}
#if 0/* unused */
/**
* Formats a sort key number.
*/
{
static const char s_szDigits[] = "0123456789abcdef";
/* signed */
if (i64 >= 0)
{
*psz++ = '+';
}
else
{
*psz++ = '-';
}
/* 16 hex digits */
unsigned i = 16;
while (i-- > 0)
{
if (u64)
{
u64 /= 16;
}
else
psz[i] = '0';
}
}
#endif
void VBoxDbgStatsLeafItem::update(STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, STAMVISIBILITY enmVisibility, const char *pszDesc)
{
/*
* Detect changes.
* This path will be taken on the first update and if a item
*/
{
/*
* Unit.
*/
/**
* Update the description.
* Insert two spaces as gap after the last left-aligned field.
* @todo dmik: How to make this better?
*/
/*
* Clear the content.
*/
}
/*
* Update the data.
*/
char sz[64];
switch (enmType)
{
case STAMTYPE_COUNTER:
{
break;
}
case STAMTYPE_PROFILE:
case STAMTYPE_PROFILE_ADV:
{
{
}
else
{
}
break;
}
case STAMTYPE_RATIO_U32:
case STAMTYPE_RATIO_U32_RESET:
{
char sz2[64];
char sz3[128];
strcat(strcat(strcpy(sz3, formatNumber(sz, m_Data.RatioU32.u32A)), " : "), formatNumber(sz2, m_Data.RatioU32.u32B));
///@todo ratio: setText(7, formatNumberSigned(sz, m_Data.u64 - u64Prev));
break;
}
case STAMTYPE_CALLBACK:
{
break;
}
case STAMTYPE_U8:
case STAMTYPE_U8_RESET:
{
break;
}
case STAMTYPE_X8:
case STAMTYPE_X8_RESET:
{
break;
}
case STAMTYPE_U16:
case STAMTYPE_U16_RESET:
{
break;
}
case STAMTYPE_X16:
case STAMTYPE_X16_RESET:
{
break;
}
case STAMTYPE_U32:
case STAMTYPE_U32_RESET:
{
break;
}
case STAMTYPE_X32:
case STAMTYPE_X32_RESET:
{
break;
}
case STAMTYPE_U64:
case STAMTYPE_U64_RESET:
{
break;
}
case STAMTYPE_X64:
case STAMTYPE_X64_RESET:
{
break;
}
default:
break;
}
}
{
/* name and description */
/* the number columns */
char sz[128];
switch (m_enmType)
{
case STAMTYPE_COUNTER:
switch (iColumn)
{
default: sz[0] = '\0'; break;
}
break;
case STAMTYPE_PROFILE:
case STAMTYPE_PROFILE_ADV:
{
switch (iColumn)
{
default: sz[0] = '\0'; break;
}
}
else
sz[0] = '\0';
break;
case STAMTYPE_RATIO_U32:
case STAMTYPE_RATIO_U32_RESET:
else
break;
case STAMTYPE_U8:
case STAMTYPE_U8_RESET:
switch (iColumn)
{
default: sz[0] = '\0'; break;
}
break;
case STAMTYPE_U16:
case STAMTYPE_U16_RESET:
switch (iColumn)
{
default: sz[0] = '\0'; break;
}
break;
case STAMTYPE_U32:
case STAMTYPE_U32_RESET:
switch (iColumn)
{
default: sz[0] = '\0'; break;
}
break;
case STAMTYPE_U64:
case STAMTYPE_U64_RESET:
switch (iColumn)
{
default: sz[0] = '\0'; break;
}
break;
case STAMTYPE_CALLBACK:
default:
}
}
{
/*
* Generic printing.
*/
#ifdef VBOXDBG_USE_QT4
if (!isHidden())
{
const char *apszColumns[9];
for (int i = 0; RT_ELEMENTS(aColumns); i++)
{
}
if (fReleaseLog)
RTLogRelPrintf("%-50s %-10s %18s %18s %18s %18s %16s %s\n",
else
RTLogPrintf("%-50s %-10s %18s %18s %18s %18s %16s %s\n",
}
#else
if (isVisible())
{
if (fReleaseLog)
RTLogRelPrintf("%-50s %-10s %18s %18s %18s %18s %16s %s\n",
else
RTLogPrintf("%-50s %-10s %18s %18s %18s %18s %16s %s\n",
}
#endif
/*
* Let the super class to do the rest.
*/
}
{
/*
* Generic printing.
*/
#ifdef VBOXDBG_USE_QT4
if (!isHidden())
{
const char *apszColumns[9];
for (int i = 0; RT_ELEMENTS(aColumns); i++)
{
}
String += ItemString;
}
#else
if (isVisible())
{
String += ItemString;
}
#endif
/*
* Let the super class to do the rest.
*/
}
/*
*
* V B o x D b g S t a t s V i e w
* V B o x D b g S t a t s V i e w
* V B o x D b g S t a t s V i e w
*
*
*/
{
/*
* Create the columns.
*/
#ifdef VBOXDBG_USE_QT4
setColumnCount(9);
setHeaderLabels(Headers << "Name" << "Unit" << "Value/Times" << "Min" << "Average" << "Max" << "Total" << "dInt" << "Description");
setItemsExpandable(true);
setSortingEnabled(true);
#else
NOREF(i);
Assert(i == 8);
setShowSortIndicator(true);
#endif
/*
* Create the root node.
*/
setRootIsDecorated(true);
#ifdef VBOXDBG_USE_QT4
m_pRoot->setExpanded(true);
#else
#endif
/*
* We've got three menus to populate and link up.
*/
#ifdef VBOXDBG_USE_QT4
/** @todo */
#else /* QT3 */
m_pLeafMenu = new QPopupMenu(this);
m_pBranchMenu = new QPopupMenu(this);
m_pViewMenu = new QPopupMenu(this);
#endif /* QT3 */
}
{
/* Who frees the items? What happens to the reference in QListView? Does the parent free things in some way? */
#if 0
while (pCur)
{
delete pFree;
}
delete m_pRoot;
#endif
}
/**
* Hides all parent branches which doesn't have any visible leafs.
*/
{
#ifdef VBOXDBG_USE_QT4
/// @todo
#else
{
if (pChild)
return;
pParent->setVisible(false);
}
#endif
}
/**
* Shows all parent branches
*/
{
pParent->setVisible(true);
}
{
if (VBOX_SUCCESS(rc))
{
/* hide what's left */
{
pCur->setVisible(false);
}
}
}
{
}
{
#ifdef VBOXDBG_USE_QT4
pItem->setExpanded(f);
for (int i = 0; i < cChildren; i++)
#else
setOpenTree(pItem, f);
#endif
}
#ifndef VBOXDBG_USE_QT4
void VBoxDbgStatsView::expandAll()
{
setOpenTree(m_pRoot, true);
}
void VBoxDbgStatsView::collapsAll()
{
setOpenTree(m_pRoot, false);
}
#endif /* QT3 */
/*static*/ DECLCALLBACK(int) VBoxDbgStatsView::updateCallback(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit,
{
/*
* Skip the ones which shouldn't be visible in the GUI.
*/
if (enmVisibility == STAMVISIBILITY_NOT_GUI)
return 0;
/*
* Advance to the matching item.
*/
while (pCur)
{
/*
* ASSUMES ascending order of STAM items.
*/
if (!iDiff)
break;
if (iDiff > 0)
{
/*
* Removed / filtered out.
*/
{
pCur->setVisible(false);
}
}
else if (iDiff < 0)
{
/*
* New item, insert before pCur.
*/
else
break;
}
}
/*
* End of items, insert it at the tail.
*/
if (!pCur)
{
else
}
/*
* Update it and move on.
*/
return 0;
}
{
const char * const pszFullName = pszName;
/*
* Start at root.
*/
while (*pszName == '/')
pszName++;
/*
* Walk down the path creating what's missing.
*/
for (;;)
{
/*
* Extract the path component.
*/
if (!pszEnd)
return pParent;
/* advance */
/*
* Try find the name among the children of that parent guy.
*/
#ifdef VBOXDBG_USE_QT4
for (int i = 0; i < cChildren; i++)
{
break;
}
#else
#endif
if (pChild)
else
{
#ifdef VBOXDBG_USE_QT4
#else
#endif
}
pParent->setVisible(true);
}
}
{
if (pItem)
{
if (m_pContextMenuItem->isLeaf())
{
#ifdef VBOXDBG_USE_QT4
#else
#endif
}
else
{
#ifdef VBOXDBG_USE_QT4
#else
#endif
}
}
else
{
#ifdef VBOXDBG_USE_QT4
#else
#endif
}
}
{
AssertReturn(pItem, (void)0);
{
case eReset:
/* fall thru */
case eRefresh:
break;
case eCopy:
break;
case eLog:
break;
case eLogRel:
break;
default: /* keep gcc quite */
break;
}
}
{
AssertReturn(m_pContextMenuItem, (void)0);
/** @todo make enum for iId */
{
case eExpand:
setOpenTree(m_pContextMenuItem, true);
break;
case eCollaps:
setOpenTree(m_pContextMenuItem, false);
break;
case eReset:
{
}
/* fall thru */
case eRefresh:
{
{
while ( m_pCur
{
}
if (!m_pCur)
return;
}
else
{
}
break;
}
case eCopy:
break;
case eLog:
break;
case eLogRel:
break;
}
}
{
{
case eExpand:
setOpenTree(m_pRoot, true);
break;
case eCollaps:
setOpenTree(m_pRoot, false);
break;
case eReset:
/* fall thru */
case eRefresh:
break;
case eCopy:
break;
case eLog:
break;
case eLogRel:
break;
}
}
/*
*
* V B o x D b g S t a t s
* V B o x D b g S t a t s
* V B o x D b g S t a t s
*
*
*/
VBoxDbgStats::VBoxDbgStats(PVM pVM, const char *pszPat/* = NULL*/, unsigned uRefreshRate/* = 0*/, QWidget *pParent/* = NULL*/)
#ifdef VBOXDBG_USE_QT4
#else
#endif
{
#ifdef VBOXDBG_USE_QT4
setWindowTitle("VBoxDbg - Statistics");
#else
setCaption("VBoxDbg - Statistics");
#endif
/*
* On top, a horizontal box with the pattern field, buttons and refresh interval.
*/
#ifdef VBOXDBG_USE_QT4
m_pPatCB->setDuplicatesEnabled(false);
m_pPatCB->setEditable(true);
pSB->setMinimum(0);
/* The reset of the spinbox setup is identical - bet they forgot to change something ;-) */
#else
m_pPatCB->setDuplicatesEnabled(false);
#endif
pSB->setWrapping(false);
/*
* Create the tree view and setup the layout.
*/
#ifdef VBOXDBG_USE_QT4
#else
#endif
/*
* Perform the first refresh to get a good window size.
* We do this with sorting disabled because it's horribly slow otherwise.
*/
#ifdef VBOXDBG_USE_QT4
m_pView->setUpdatesEnabled(false);
m_pView->setSortingEnabled(false);
refresh();
// QTreeView::expandAll
for (int i = 0; i <= 8; i++)
{
}
m_pView->setUpdatesEnabled(true);
#else
refresh();
#endif
/*
* Create a refresh timer and start it.
*/
}
{
//????
}
{
refresh();
}
void VBoxDbgStats::applyAll()
{
apply("");
}
void VBoxDbgStats::refresh()
{
}
{
if ((unsigned)iRefresh != m_uRefreshRate)
{
#ifdef VBOXDBG_USE_QT4
if (!m_uRefreshRate || iRefresh)
#else
if (!m_uRefreshRate)
else if (iRefresh)
#endif
else
}
}