This is an archive of the discontinued LLVM Phabricator instance.

[Dexter] Improve Dexter's performance by evaluating expressions only when needed
ClosedPublic

Authored by StephenTozer on Jul 29 2021, 6:42 AM.

Details

Summary

Currently, Dexter's model for fetching watch values is to build a list of expressions to watch before running the debugger, then evaluating all of them at each breakpoint, then finally looking up the values of these expressions at each line they were expected on. When using dexter on a large project while watching many different expressions, this is very slow, as Dexter will make a massive number of calls made to the debugger's API, the vast majority of which are not being used for anything. This patch fixes this issue by having Dexter only evaluate expressions at a breakpoint when it will be used by a Dexter command.

Diff Detail

Event Timeline

StephenTozer requested review of this revision.Jul 29 2021, 6:42 AM
StephenTozer created this revision.

A couple of nits, really nice patch though! Its really going to improve things.

cross-project-tests/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py
14–1

I'm keen on ternary ifs myself, but coupled with the construction of a StepExpectInfo in a from_iterable I feel this block could be a little hard to read. But I concede its just personal preference.

cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py
18

Possibly awkward to read combination of and, not, or. Is there a nicer way to expess this? Just a nit really.

LGTM in principle, although I agree with Chris, the get_watches block is a bit too pythonic, and contains a generator within a generator. It'd be best to split that into statements, IMO.

It's not ideal that the debugger wrappers have to be adjusted to benefit from these improvements; I guess that's a future refactoring project though.

cross-project-tests/debuginfo-tests/dexter/dex/command/commands/DexExpectWatchBase.py
3

I have mixed feelings about this; IMO we want to steer away from relying on the source files being accessible by Dexter while running. But on the other hand, the previous implementation on this function relied on it for correctness, all this assert is doing is drawing attention to the fact that if the file isn't there, you won't get the results you wanted.

Overall I would call this an improvement, as it accelerates our likelyhood of fixing this.

cross-project-tests/debuginfo-tests/dexter/dex/debugger/DebuggerBase.py
16–17

Adding a type annotation, docu-comment or otherwise to indicate the type of watch_info would be good. It'll be hard for returning readers otherwise.

Add comments and type annotations, split complex statements out across multiple lines.

Reupload previous diff with -U999999 flag.

jmorse accepted this revision.Sep 13 2021, 4:34 AM

LGTM with one inline question -- if that's an issue, fine to land with the obvious fix.

cross-project-tests/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py
27

Is this going to lead to multiple StepExpectInfo objects referring to the same range object? And if so, doesn't that mean consuming the range in one frame will consume it in all the frames?

(If so, easily fixed by converting to a list).

This revision is now accepted and ready to land.Sep 13 2021, 4:34 AM
StephenTozer added inline comments.Sep 13 2021, 10:14 AM
cross-project-tests/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py
27

I don't think so - the frame index is in the StepExpectInfo tuple, so unless the same value is being watched twice in the same stack frame there shouldn't be duplicates (and if there are then we should merge them).

jmorse added inline comments.Sep 14 2021, 2:46 AM
cross-project-tests/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py
27

Possibly I've misread, but if there are multiple watches (line 66) in a frame, then multiple StepExpectInfo's will be constructed, each referring to the range object constructed on line 63, no?

StephenTozer added inline comments.Sep 14 2021, 3:14 AM
cross-project-tests/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py
27

Ah, I understand now - this isn't an issue, because python range objects are not consumed on use; they're an immutable object, and they must be in order to be used as part of a set element. For the same reason, we can't use a list here (because a list is a mutable object). This means that it should be perfectly safe to pass around the same object into every set.

This revision was landed with ongoing or failed builds.Sep 14 2021, 6:10 AM
This revision was automatically updated to reflect the committed changes.