1
# -*- coding: utf-8 -*-
3
# Copyright (c) 2003 - 2007 Detlev Offenbach <detlev@die-offenbachs.de>
7
Module implementing a dialog to display profile data.
14
from PyQt4.QtCore import *
15
from PyQt4.QtGui import *
17
from KdeQt import KQMessageBox
19
from Ui_PyProfileDialog import Ui_PyProfileDialog
22
from eric4config import getConfig
24
class ProfileTreeWidgetItem(QTreeWidgetItem):
26
Class implementing a custom QTreeWidgetItem to allow sorting on numeric values.
28
def __getNC(self, itm):
30
Private method to get the value to compare on for the first column.
32
@param itm item to operate on (ProfileTreeWidgetItem)
35
return int(s.split('/')[0])
37
def __lt__(self, other):
39
Public method to check, if the item is less than the other one.
41
@param other reference to item to compare against (ProfileTreeWidgetItem)
42
@return true, if this item is less than other (boolean)
44
column = self.treeWidget().sortColumn()
46
return self.__getNC(self) < self.__getNC(other)
48
return int(str(self.text(column))) < int(str(other.text(column)))
49
return self.text(column) < other.text(column)
51
class PyProfileDialog(QDialog, Ui_PyProfileDialog):
53
Class implementing a dialog to display the results of a syntax check run.
55
def __init__(self, parent = None):
59
@param parent parent widget (QWidget)
61
QDialog.__init__(self, parent)
64
self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
65
self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
67
self.cancelled = False
69
self.ericpath = getConfig('ericDir')
70
self.pyLibPath = Utilities.getPythonLibPath()
72
self.resultList.header().setSortIndicator(0, Qt.DescendingOrder)
74
self.__menu = QMenu(self)
75
self.filterItm = self.__menu.addAction(self.trUtf8('Exclude Python Library'),
77
self.__menu.addSeparator()
78
self.__menu.addAction(self.trUtf8('Erase Profiling Info'),
80
self.__menu.addAction(self.trUtf8('Erase Timing Info'), self.__eraseTiming)
81
self.__menu.addSeparator()
82
self.__menu.addAction(self.trUtf8('Erase All Infos'), self.__eraseAll)
83
self.resultList.setContextMenuPolicy(Qt.CustomContextMenu)
84
self.connect(self.resultList,
85
SIGNAL('customContextMenuRequested(const QPoint &)'),
86
self.__showContextMenu)
87
self.summaryList.setContextMenuPolicy(Qt.CustomContextMenu)
88
self.connect(self.summaryList,
89
SIGNAL('customContextMenuRequested(const QPoint &)'),
90
self.__showContextMenu)
92
def __createResultItem(self, calls, totalTime, totalTimePerCall, cumulativeTime,
93
cumulativeTimePerCall, file, line, functionName):
95
Private method to create an entry in the result list.
97
@param calls number of calls (integer)
98
@param totalTime total time (double)
99
@param totalTimePerCall total time per call (double)
100
@param cumulativeTime cumulative time (double)
101
@param cumulativeTimePerCall cumulative time per call (double)
102
@param file filename of file (string or QString)
103
@param line linenumber (integer)
104
@param functionName function name (string or QString)
106
itm = ProfileTreeWidgetItem(self.resultList, QStringList() \
107
<< calls << "% 8.3f" % totalTime << totalTimePerCall \
108
<< "% 8.3f" % cumulativeTime << cumulativeTimePerCall \
109
<< file << str(line) << functionName)
110
for col in [0, 1, 2, 3, 4, 6]:
111
itm.setTextAlignment(col, Qt.AlignRight)
113
def __createSummaryItem(self, label, contents):
115
Private method to create an entry in the summary list.
117
@param label text of the first column (string or QString)
118
@param contents text of the second column (string or QString)
120
itm = QTreeWidgetItem(self.summaryList, QStringList() << label << contents)
121
itm.setTextAlignment(1, Qt.AlignRight)
123
def __resortResultList(self):
125
Private method to resort the tree.
127
self.resultList.sortItems(self.resultList.sortColumn(),
128
self.resultList.header().sortIndicatorOrder())
130
def __populateLists(self, exclude = False):
132
Private method used to populate the listviews.
134
@param exclude flag indicating whether files residing in the
135
Python library should be excluded
137
self.resultList.clear()
138
self.summaryList.clear()
140
self.checkProgress.setMaximum(len(self.stats))
141
QApplication.processEvents()
149
# disable updates of the list for speed
150
self.resultList.setUpdatesEnabled(False)
151
self.resultList.setSortingEnabled(False)
153
# now go through all the files
154
for func, (cc, nc, tt, ct, callers) in self.stats.items():
158
if not (self.ericpath and func[0].startswith(self.ericpath)) and \
159
not (exclude and func[0].startswith(self.pyLibPath)):
160
if self.file is None or func[0].startswith(self.file) or \
161
func[0].startswith(self.pyLibPath):
162
# calculate the totals
168
c = "%d/%d" % (nc, cc)
174
tpc = "% 8.3f" % (tt/nc,)
178
cpc = "% 8.3f" % (ct/cc,)
179
self.__createResultItem(c, tt, tpc, ct, cpc, func[0],
180
str(func[1]), func[2])
183
self.checkProgress.setValue(progress)
184
QApplication.processEvents()
186
# reenable updates of the list
187
self.resultList.setSortingEnabled(True)
188
self.resultList.setUpdatesEnabled(True)
189
self.__resortResultList()
191
# now do the summary stuff
192
self.__createSummaryItem(self.trUtf8("function calls"), str(total_calls))
193
if total_calls != prim_calls:
194
self.__createSummaryItem(self.trUtf8("primitive calls"), str(prim_calls))
195
self.__createSummaryItem(self.trUtf8("CPU seconds"), "%.3f" % total_tt)
197
def start(self, pfn, fn=None):
199
Public slot to start the calculation of the profile data.
201
@param pfn basename of the profiling file (string)
202
@param fn file to display the profiling data for (string)
204
self.basename = os.path.splitext(pfn)[0]
206
fname = "%s.profile" % self.basename
207
if not os.path.exists(fname):
208
KQMessageBox.warning(None,
209
self.trUtf8("Profile Results"),
210
self.trUtf8("""<p>There is no profiling data"""
211
""" available for <b>%1</b>.</p>""")
216
f = open(fname, 'rb')
217
self.stats = marshal.load(f)
220
KQMessageBox.critical(None,
221
self.trUtf8("Loading Profiling Data"),
222
self.trUtf8("""<p>The profiling data could not be"""
223
""" read from file <b>%1</b>.</p>""")
229
self.__populateLists()
234
Private slot called when the action finished or the user pressed the button.
236
self.cancelled = True
237
self.buttonBox.button(QDialogButtonBox.Close).setEnabled(True)
238
self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(False)
239
self.buttonBox.button(QDialogButtonBox.Close).setDefault(True)
240
QApplication.processEvents()
241
self.resultList.header().resizeSections(QHeaderView.ResizeToContents)
242
self.resultList.header().setStretchLastSection(True)
243
self.summaryList.header().resizeSections(QHeaderView.ResizeToContents)
244
self.summaryList.header().setStretchLastSection(True)
246
def __unfinish(self):
248
Private slot called to revert the effects of the __finish slot.
250
self.cancelled = False
251
self.buttonBox.button(QDialogButtonBox.Close).setEnabled(False)
252
self.buttonBox.button(QDialogButtonBox.Cancel).setEnabled(True)
253
self.buttonBox.button(QDialogButtonBox.Cancel).setDefault(True)
255
def on_buttonBox_clicked(self, button):
257
Private slot called by a button of the button box clicked.
259
@param button button that was clicked (QAbstractButton)
261
if button == self.buttonBox.button(QDialogButtonBox.Close):
263
elif button == self.buttonBox.button(QDialogButtonBox.Cancel):
266
def __showContextMenu(self, coord):
268
Private slot to show the context menu of the listview.
270
@param coord the position of the mouse pointer (QPoint)
272
self.__menu.popup(self.mapToGlobal(coord))
274
def __eraseProfile(self):
276
Private slot to handle the Erase Profile context menu action.
278
fname = "%s.profile" % self.basename
279
if os.path.exists(fname):
282
def __eraseTiming(self):
284
Private slot to handle the Erase Timing context menu action.
286
fname = "%s.timings" % self.basename
287
if os.path.exists(fname):
290
def __eraseAll(self):
292
Private slot to handle the Erase All context menu action.
294
self.__eraseProfile()
299
Private slot to handle the Exclude/Include Python Library context menu action.
304
self.filterItm.setText(self.trUtf8('Include Python Library'))
305
self.__populateLists(True)
308
self.filterItm.setText(self.trUtf8('Exclude Python Library'))
309
self.__populateLists(False)