Skip to content

Frame.f_trace, paving the way to support pdb debugging #1918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from

Conversation

alanjds
Copy link
Contributor

@alanjds alanjds commented May 8, 2020

f_trace is initialized with PyNone. I do not know if it would be better on memory/cpu to handle Option::None instead.

No tests for now, just wanting a feedback. Specially on the RwLock used.

alanjds added 4 commits May 5, 2020 21:45
Is guarded by a RwLock<PyObjectRef>. Is there a better option maybe?

Could use an RwLock<Option<PyObjectRef>> and provide a vm.get_none()
on each None::<PyObjectRef> found. I do not know what is better
on memory & cpu
@coolreader18
Copy link
Member

I think it would be a micro-optimization for PyObjectRef vs Option<PyObjectRef>, as they're the same size since Option::<Rc>::None is represented by a null pointer. vm.is_none(&obj) vs opt.is_none() is I think 1 asm instruction different, as it's basically ptr == 0 vs ptr == vm->none_address

@alanjds
Copy link
Contributor Author

alanjds commented May 9, 2020

I see. The part intriguing me is that Option::None codepath is followed by return vm.get_none()

But storing PyNone lead to return .unwrap().clone() and I could not dodge this refcount cost on .clone()

@alanjds
Copy link
Contributor Author

alanjds commented May 9, 2020

I may be overthinking this all. Will keep pushing "just work" code until pdb.set_trace() works and then get back to optimize.

What about the rwlock? Is it ok? The rational was that I expect it to be checked on every single line change, so should be fast. But also light on memory as will be on every frame created.

@alanjds
Copy link
Contributor Author

alanjds commented May 9, 2020

...and thanks for the attention @coolreader18.

@coolreader18
Copy link
Member

Yeah, I think the RwLock is good, it makes sense since you might occasionally be reading the f_trace property concurrently.

@alanjds
Copy link
Contributor Author

alanjds commented May 11, 2020

  • pdb.runcall() working, but not quite right. The 1st line stopped is into bdb yet 🤔
  • (pdb) args works, but also behaves as if I had (pdb) next too 🤔
  • Changed from RwLock to Mutex. On single-threaded is faster, on multiple it works IIUC.
  • Optimized a bit the codepath of vm::trace_event for the case of no trace function set, the default.

alanjds added 2 commits May 16, 2020 14:35
Implementation of sys.__displayhook__ from CPython 3.8.3 docs.
Is the pseudocode inlined on the docs copy-pasted.
See: https://docs.python.org/3/library/sys.html#sys.displayhook
This is the CPython behavior expected by bdb.py debugger.
Had not understood how does it work on CPython. Here has
implemented via frame.__delattr__ specially for f_trace.

Other `del frame.*` are actually noops for now
@alanjds
Copy link
Contributor Author

alanjds commented May 16, 2020

And this is the end of PyCon US 2020 sprint:

  • (pdb) continue works as expected, not breaking at some del frame.f_trace

Thanks @youknowone for the help on Gitter.
Had not found how do CPython implement del frame.f_trace. I implemented via frame.__delattr__. Yet I do not know how to call super() from Rust side. Will need help on this.

Now may need support for a setter on frame.lineno if wanting to have (pdb) jump to work. Maybe for (pdb) next too, as seems broken.

Good night.

@@ -24,6 +24,15 @@ impl FrameRef {
"<frame object at .. >".to_owned()
}

#[pymethod(name = "__delattr__")]
fn delattr(self, value: PyObjectRef, vm: &VirtualMachine) {
println!("Called: FrameRef::f_trace over {:?}", value);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice workaround for now. putting an incompatibility comment will be helpful for future work.

@youknowone
Copy link
Member

Do you want to work more for this or want to merge part of the work?

@alanjds
Copy link
Contributor Author

alanjds commented Jul 26, 2020

Both 😬.

Better to merge the actual progress for this to not get rotten when I find the time to finish it.

@alanjds alanjds marked this pull request as ready for review July 26, 2020 22:04
@youknowone
Copy link
Member

Will you make a new PR with finished commits after rebase?

@alanjds
Copy link
Contributor Author

alanjds commented Jul 27, 2020

Will you make a new PR with finished commits after rebase?

I am not used to rebase stuff, but can learn to.

Should I go cherry-picking over master and send a new PR? Is this the way?

@youknowone
Copy link
Member

Oh, yep. Because this one is very aged, cherry-pick could be easier than rebase. That sounds very reasonable.

Also got its pure-python dependencies bdb.py and cmd.py
Also stubbed the C-based gc.py using `pystubber` (https://pypi.org/project/pystubber/)
@coolreader18
Copy link
Member

Oh, right -- looks like the errors are from .lock().unwrap(); we switched to parking_lot Mutexs since this PR was opened, so the .unwrap()s shouldn't be necessary.

@coolreader18
Copy link
Member

Is the gc.py module necessary if everything raises a NotImplementedError anyway? We've mostly just been commenting out gc imports and function calls in modules that have them, is there a reason that can't work for pdb?

@alanjds
Copy link
Contributor Author

alanjds commented Aug 11, 2020

Is the gc.py module necessary if everything raises a NotImplementedError anyway? We've mostly just been commenting out gc imports and function calls in modules that have them, is there a reason that can't work for pdb?

bdb.py imports it to use somewhere, but I had not hit the case when it calls gc for real.

Anyway I do not feel bad by stubbing C-based stuff that we want not to implement right now.

(I need to say that sometimes I am missing the ability of calling rust code directly from python code. Maybe on future a custom importhook can do the trick.)

@coolreader18
Copy link
Member

@youknowone what do you think?

@alanjds
Copy link
Contributor Author

alanjds commented Aug 11, 2020

We've mostly just been commenting out gc imports and function calls in modules that have them

My approach on this is to try to do the lowest number of changes possible on foreign code, if we want to get back to the original somewhere in future. That is why I am trying to provide a bogus gc instead of messing with bdb.py original code.

Less changes to track upstream on bdb.py and keep patching here until a fully compatible gc is ready.

@alanjds
Copy link
Contributor Author

alanjds commented Aug 11, 2020

https://github.com/RustPython/RustPython/pull/1918/checks?check_run_id=973313037#step:10:7685

AttributeError: module 'sys' has no attribute 'stdout'

What? I though that this was been fixed before 🤔. I saw a PR about this!

@alanjds
Copy link
Contributor Author

alanjds commented Aug 12, 2020

Looks like sys.displayhook was natively implemented in meantime. Removing my hack from site.py and waiting for CI completion.

For some reason my local tests passed without changes. I may have a local environment messed up.

@alanjds
Copy link
Contributor Author

alanjds commented Aug 12, 2020

Yay! Got green.

Now pdb.set_trace() "works" but stops on the wrong place.
Then works:

  • a(rgs)
  • c(ontinue)
  • h(elp)
  • l(ist)
  • w(here)
  • s(tep) into
  • local evaluation also works

Yet broken:

  • n(ext): Is ignored, showing the very same line forever
  • r(eturn): Is ignored, showing the very same line forever
  • j(ump): Is ignored, and a follow c(ontinue) raises AttributeError: attribute 'f_lineno' of 'frame' objects is not writable

This PR is good to go. At least locals() and globals() variables inspection are working. Closure variables inspection seemed broken.

Lets get this merged and open another to fix j(ump) and n(ext)

@coolreader18
Copy link
Member

I'm merging this manually to fix this weird lf->crlf change in frame.rs

@coolreader18
Copy link
Member

Alright, this is merged to master even though github doesn't show it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants