summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhjk <hjk@qt.io>2019-12-18 13:27:20 +0100
committerhjk <hjk@qt.io>2020-01-07 12:14:27 +0000
commitdff4469bafd514c408d390a030b25459e3215ec0 (patch)
tree01953905598c7b3371634d3bb78d7da16db782e0
parentc2c48598d49be80f2744f3ab393ad0dbf3d0ae82 (diff)
downloadqt-creator-dff4469bafd514c408d390a030b25459e3215ec0.tar.gz
Debugger: Use a more convenient way to create timing samples
Change-Id: I4ca983957c81a1f5f963a85b16a2d1b255b2cd2d Reviewed-by: Orgad Shaneh <orgads@gmail.com>
-rw-r--r--share/qtcreator/debugger/dumper.py64
-rw-r--r--share/qtcreator/debugger/gdbbridge.py11
2 files changed, 34 insertions, 41 deletions
diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py
index 04969d8e32..3ebdedbd2e 100644
--- a/share/qtcreator/debugger/dumper.py
+++ b/share/qtcreator/debugger/dumper.py
@@ -173,6 +173,20 @@ def error(message):
def showException(msg, exType, exValue, exTraceback):
DumperBase.showException(msg, exType, exValue, exTraceback)
+
+class Timer:
+ def __init__(self, d, desc):
+ self.d = d
+ self.desc = desc + '-' + d.currentIName
+
+ def __enter__(self):
+ self.starttime = time.time()
+
+ def __exit__(self, exType, exValue, exTraceBack):
+ elapsed = int(1000 * (time.time() - self.starttime))
+ self.d.timings.append([self.desc, elapsed])
+
+
class Children:
def __init__(self, d, numChild = 1, childType = None, childNumChild = None,
maxNumChild = None, addrBase = None, addrStep = None):
@@ -261,6 +275,9 @@ class DumperBase:
except:
pass
+ def timer(self, desc):
+ return Timer(self, desc)
+
def __init__(self):
self.isCdb = False
self.isGdb = False
@@ -372,12 +389,10 @@ class DumperBase:
self.counts = {}
self.structPatternCache = {}
- self.pretimings = {}
self.timings = []
def resetStats(self):
# Timing collection
- self.pretimings = {}
self.timings = []
pass
@@ -392,15 +407,6 @@ class DumperBase:
else:
self.counts[key] = 1
- def preping(self, key):
- return
- self.pretimings[key] = time.time()
-
- def ping(self, key):
- return
- elapsed = int(1000 * (time.time() - self.pretimings[key]))
- self.timings.append([key, elapsed])
-
def childRange(self):
if self.currentMaxNumChild is None:
return xrange(0, self.currentNumChild)
@@ -1369,9 +1375,8 @@ class DumperBase:
return False
def putFormattedPointer(self, value):
- self.preping('formattedPointer')
+ #with self.timer('formattedPointer'):
self.putFormattedPointerX(value)
- self.ping('formattedPointer')
def putDerefedPointer(self, value):
derefValue = value.dereference()
@@ -1735,15 +1740,13 @@ class DumperBase:
metaObjectPtr = 0
if not metaObjectPtr:
# measured: 3 ms (example had one level of inheritance)
- self.preping('metaObjectType-' + self.currentIName)
+ #with self.timer('metaObjectType-' + self.currentIName):
metaObjectPtr = extractStaticMetaObjectPtrFromType(typeobj)
- self.ping('metaObjectType-' + self.currentIName)
if not metaObjectPtr:
# measured: 200 ms (example had one level of inheritance)
- self.preping('metaObjectCall-' + self.currentIName)
+ #with self.timer('metaObjectCall-' + self.currentIName):
metaObjectPtr = extractMetaObjectPtrFromAddress()
- self.ping('metaObjectCall-' + self.currentIName)
#if metaObjectPtr:
# self.bump('foundMetaObject')
@@ -2392,7 +2395,7 @@ class DumperBase:
def handleLocals(self, variables):
#warn('VARIABLES: %s' % variables)
- self.preping('locals')
+ #with self.timer('locals'):
shadowed = {}
for value in variables:
if value.name == 'argv':
@@ -2412,20 +2415,17 @@ class DumperBase:
# A 'normal' local variable or parameter.
iname = value.iname if hasattr(value, 'iname') else 'local.' + name
with TopLevelItem(self, iname):
- self.preping('all-' + iname)
+ #with self.timer('all-' + iname):
self.putField('iname', iname)
self.putField('name', name)
self.putItem(value)
- self.ping('all-' + iname)
- self.ping('locals')
def handleWatches(self, args):
- self.preping('watches')
+ #with self.timer('watches'):
for watcher in args.get('watchers', []):
iname = watcher['iname']
exp = self.hexdecode(watcher['exp'])
self.handleWatch(exp, exp, iname)
- self.ping('watches')
def handleWatch(self, origexp, exp, iname):
exp = str(exp).strip()
@@ -2734,9 +2734,8 @@ class DumperBase:
self.putSubItem(i, val)
def putItem(self, value):
- self.preping('putItem')
+ #with self.timer('putItem'):
self.putItemX(value)
- self.ping('putItem')
def putItemX(self, value):
#warn('PUT ITEM: %s' % value.stringify())
@@ -2868,9 +2867,8 @@ class DumperBase:
self.putEmptyValue()
#warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address()))
if self.showQObjectNames:
- self.preping(self.currentIName)
+ #with self.timer(self.currentIName):
self.putQObjectNameValue(value)
- self.ping(self.currentIName)
if self.isExpanded():
self.putField('sortable', 1)
with Children(self, 1, childType=None):
@@ -3351,7 +3349,7 @@ class DumperBase:
error('CANNOT CONVERT TO BYTES: %s' % self)
def extractInteger(self, bitsize, unsigned):
- self.dumper.preping('extractInt')
+ #with self.dumper.timer('extractInt'):
self.check()
if bitsize > 32:
size = 8
@@ -3369,23 +3367,21 @@ class DumperBase:
res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
#warn('Extract: Code: %s Bytes: %s Bitsize: %s Size: %s'
# % (self.dumper.packCode + code, self.dumper.hexencode(rawBytes), bitsize, size))
- self.dumper.ping('extractInt')
return res
def extractSomething(self, code, bitsize):
- self.dumper.preping('extractSomething')
+ #with self.dumper.timer('extractSomething'):
self.check()
size = (bitsize + 7) >> 3
rawBytes = self.data(size)
res = struct.unpack_from(self.dumper.packCode + code, rawBytes, 0)[0]
- self.dumper.ping('extractSomething')
return res
def to(self, pattern):
return self.split(pattern)[0]
def split(self, pattern):
- self.dumper.preping('split')
+ #with self.dumper.timer('split'):
#warn('EXTRACT STRUCT FROM: %s' % self.type)
(pp, size, fields) = self.dumper.describeStruct(pattern)
#warn('SIZE: %s ' % size)
@@ -3405,7 +3401,6 @@ class DumperBase:
return thing
if len(fields) != len(result):
error('STRUCT ERROR: %s %s' (fields, result))
- self.dumper.ping('split')
return tuple(map(structFixer, fields, result))
def checkPointer(self, p, align = 1):
@@ -3548,9 +3543,8 @@ class DumperBase:
# FIXME: That buys some performance at the cost of a fail
# of Gdb13393 dumper test.
#return self
- self.dumper.preping('dynamicType %s 0x%s' % (self.name, address))
+ #with self.dumper.timer('dynamicType %s 0x%s' % (self.name, address)):
dynTypeName = self.dynamicTypeName(address)
- self.dumper.ping('dynamicType %s 0x%s' % (self.name, address))
if dynTypeName is not None:
return self.dumper.createType(dynTypeName)
return self
diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py
index dcd7f694da..6a912ea388 100644
--- a/share/qtcreator/debugger/gdbbridge.py
+++ b/share/qtcreator/debugger/gdbbridge.py
@@ -243,6 +243,10 @@ class Dumper(DumperBase):
nativeTargetValue = None
targetType = self.fromNativeType(nativeType.target().unqualified())
val = self.createPointerValue(toInteger(nativeValue), targetType)
+ # The nativeValue is needed in case of multiple inheritance, see
+ # QTCREATORBUG-17823. Using it triggers nativeValueDereferencePointer()
+ # later which
+ # is surprisingly expensive.
val.nativeValue = nativeValue
#warn('CREATED PTR 1: %s' % val)
if not nativeValue.address is None:
@@ -447,7 +451,6 @@ class Dumper(DumperBase):
return typeId
def nativeStructAlignment(self, nativeType):
- self.preping('align ' + str(nativeType))
#warn('NATIVE ALIGN FOR %s' % nativeType.name)
def handleItem(nativeFieldType, align):
a = self.fromNativeType(nativeFieldType).alignment()
@@ -455,7 +458,6 @@ class Dumper(DumperBase):
align = 1
for f in nativeType.fields():
align = handleItem(f.type, align)
- self.ping('align ' + str(nativeType))
return align
@@ -668,9 +670,7 @@ class Dumper(DumperBase):
self.resetStats()
self.prepare(args)
- self.preping('endian')
self.isBigEndian = gdb.execute('show endian', to_string = True).find('big endian') > 0
- self.ping('endian')
self.packCode = '>' if self.isBigEndian else '<'
(ok, res) = self.tryFetchInterpreterVariables(args)
@@ -827,9 +827,7 @@ class Dumper(DumperBase):
#warn('READ: %s FROM 0x%x' % (size, address))
if address == 0 or size == 0:
return bytes()
- self.preping('readMem')
res = self.selectedInferior().read_memory(address, size)
- self.ping('readMem')
return res
def findStaticMetaObject(self, type):
@@ -1137,6 +1135,7 @@ class Dumper(DumperBase):
self.reportResult('selected="0x%x",expr="(%s*)0x%x"' % (p, n, p), args)
def nativeValueDereferencePointer(self, value):
+ # This is actually pretty expensive, up to 100ms.
deref = value.nativeValue.dereference()
return self.fromNativeValue(deref.cast(deref.dynamic_type))