diff options
author | hjk <hjk@qt.io> | 2019-12-18 13:27:20 +0100 |
---|---|---|
committer | hjk <hjk@qt.io> | 2020-01-07 12:14:27 +0000 |
commit | dff4469bafd514c408d390a030b25459e3215ec0 (patch) | |
tree | 01953905598c7b3371634d3bb78d7da16db782e0 | |
parent | c2c48598d49be80f2744f3ab393ad0dbf3d0ae82 (diff) | |
download | qt-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.py | 64 | ||||
-rw-r--r-- | share/qtcreator/debugger/gdbbridge.py | 11 |
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)) |