[lldb-dev] lldb.frame.EvaluateExpression slows down when called a lot

Greg Clayton gclayton at apple.com
Thu Apr 17 11:27:52 PDT 2014


SBValue
SBTarget::FindFirstGlobalVariable (const char* name);

This doesn't support the "GetValueForVariablePath()", so you will need to do:

ruby_current_vm = lldb.target.FindFirstGlobalVariable('ruby_current_vm');

heaps_used = ruby_current_vm.GetValueForExpressionPath('->objspace->heap_pages.used').GetValueAsUnsigned(0)

You can also use a very handy wrapper utility class called lldb.value:

ruby_current_vm = lldb.value(lldb.target.FindFirstGlobalVariable('ruby_current_vm'))

Now "ruby_current_vm" behaves like a C structure would, except you can't use "->" to refer to a child of a pointer you need to use ".". So you should be able to do:

heaps_used = ruby_current_vm.objspace.heap_pages.used

for i in xrange(heaps_used):
    page = ruby_current_vm.objspace.heap_pages.sorted[i]

You had a derefernce on "page" before, but, you can use page is a lldb.value, so you can just do "page.foo.bar" if you need anything inside of it.

Greg

On Apr 17, 2014, at 11:09 AM, Scott Knight <knightsc at gmail.com> wrote:

> Thanks for the information Greg. I have a quick followup. I'm using the version of lldb that comes with XCode 5.1.1
> 
> Launching it like this
> 
> Scotts-MacBook-Pro:~ scottknight$ /Applications/Xcode.app/Contents/Developer/usr/bin/lldb -p 13892
> Attaching to process with:
>     process attach -p 13892
> Process 13892 stopped
> Executable module set to "/Users/scottknight/.rbenv/versions/2.1.1/bin/ruby".
> Architecture set to: x86_64-apple-macosx.
> 
> When I tried using GetValueForVariablePath I got 'No value' back. See the output below.
> 
> (lldb) v
> lldb-310.2.37
> (lldb) script
> Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
> >>> print lldb.frame.EvaluateExpression('ruby_current_vm')
> (rb_vm_t *) $1 = 0x00007f9a01003000
> >>> print lldb.frame.GetValueForVariablePath('ruby_current_vm')
> No value
> 
> Since ruby_current_vm is a global variable is there something different I would need to do to access it?
> 
> Thanks,
> Scott Knight
> 
> 
> On Thu, Apr 17, 2014 at 1:45 PM, Greg Clayton <gclayton at apple.com> wrote:
> Running expressions has all sorts of side effects like storing data in the inferior program and it also involves running the clang expression parser which can be expensive.
> 
> You can, from a frame, get a SBValue for a variable without using the expression parser:
> 
>     lldb::SBValue
>     SBFrame.GetValueForVariablePath (const char *var_path);
> 
> So you can change your code to this:
> 
> heaps_used = lldb.frame.GetValueForVariablePath('ruby_current_vm->objspace->heap_pages.used').GetValueAsUnsigned(0)
> 
> for i in xrange(heaps_used):
>     page = lldb.frame.GetValueForVariablePath('*ruby_current_vm->objspace->heap_pages.sorted[%i]' % i)
> 
> The GetValueForVariablePath() will find the variable and not create a temporary each time. It also doesn't use the expression parser at all so it won't call any code. The objects you access must be available in the hierarchy of the struct or class and the struct or class can't override the "->" operator. Other than that, the GetValueForVariablePath() knows how to access members ("ruby_current_vm->objspace->heap_pages.sorted"), dereference pointers using the array syntax ("my_ptr[12]"), deref a pointer ("*this->other_ptr"), and take the address of something ("&ruby_current_vm->objspace->heap_pages.sorted[12]").
> 
> So give the GetValueForVariablePath a try. The SBValue returned is something that represents the live variable value, not a const result like you get back from expression. SBValue you get back is tied to the frame from which you got it, so it will continue to evaluate correctly and its value will change if you step between calling functions with it. If the frame it came from goes away (step out), then it won't return any valid values again as it will detect the frame is gone and stop answering any questions. So you should always fetch a fresh value from the frame each time you want to use it.
> 
> Greg
> 
> 
> On Apr 17, 2014, at 7:57 AM, Scott Knight <knightsc at gmail.com> wrote:
> 
> > I was recently using lldb to connect to a debug build of ruby to inspect the heap. In order to do this I was doing something like this
> >
> > -----------
> > heaps_used = lldb.frame.EvaluateExpression('ruby_current_vm->objspace->heap_pages.used').GetValueAsUnsigned(0)
> >
> > for i in xrange(heaps_used):
> >     page = lldb.frame.EvaluateExpression('*ruby_current_vm->objspace->heap_pages.sorted[%i]' % i)
> > -----------
> >
> > What I noticed was that for each EvaluateExpression a temporary $0, $1, $2, etc.. variable is created. If I ended up calling my python code multiple times more and more variables seemed to pile up and every EvaluateExpression call seemed to take longer and longer.
> >
> > I tried calling EvaluateExpression how I would call expr from the lldb command line setting my own variable, so something like
> >
> > lldb.frame.EvaluateExpression('int $test = 5')
> >
> > But that seemed to error out. So is there some other way in the API that is better for accessing global variables that won't slow down. Is this something actually wrong with the debugger? I can create an actual test case similar to the test suite in lldb if that would be helpful.
> >
> > Thanks,
> > Scott Knight
> >
> > _______________________________________________
> > lldb-dev mailing list
> > lldb-dev at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-dev
> 
> 




More information about the lldb-dev mailing list