Skip to content
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

Improve debug context usability #314

Merged
merged 15 commits into from
May 25, 2022

Conversation

steve-s
Copy link
Contributor

@steve-s steve-s commented Apr 14, 2022

  • document the LeakDetector and hpy_debug fixture
  • support activation via env variable HPY_DEBUG_CONTEXT
  • support capturing stack traces of handle allocations (for now simple implementation using backtrace)

On high level:

  • DebugHandle has new field char *allocation_stacktrace;, filled in when it is created or reused
  • debug module has new public functions to disable the stack trace capturing and to set the traces size limit (which implicitly enables the trace capturing)
  • by default this is turned off, but __repr__ on DebugHandle tells the user that it can be turned on and how
  • when it is turned on, the __repr__ on DebugHandle also includes the stack trace

@steve-s
Copy link
Contributor Author

steve-s commented Apr 20, 2022

@antocuni if you have some spare cycles on your hands, this one is probably best suited for you to review... :-)

Copy link
Collaborator

@antocuni antocuni left a comment

Choose a reason for hiding this comment

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

wow, I like this functionality! When it's merged, it's worth a blog post

modules are loaded with debug context. Alternatively ``HPY_DEBUG_CONTEXT``
can be set to a comma separated list of names of the modules that should
be loaded in the debug mode.

Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe this should be put earlier? It looks like HPY_DEBUG_CONTEXT=1 becomes the main and most convenient way to enable the debug mode.

Also, what about calling it HPY_DEBUG?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Originally I used HPY_DEBUG, but this env variable is also used internally for something else in our setup.py, so I wanted to avoid confusion.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think that the user-facing name is more important, so I vote for renaming the variable inside setup.py and use HPY_DEBUG for this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. So the internal one could be HPY_DEBUG_BUILD

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, it's HPY_DEBUG and I also added HPY_LOG also described in the docs

.. literalinclude:: examples/tests.py
:language: python
:start-at: hpy.debug.disable_handle_stack_traces
:end-at: hpy.debug.disable_handle_stack_traces
Copy link
Collaborator

Choose a reason for hiding this comment

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

brilliant, I like it!
Maybe for the future, we could add an env variable to enable it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

you should also show an example of the output, and maybe write a separate section which explains what to expect.
For example, I tried to modify test_stacktrace.c like this:

void bar(void) {
    char *trace;
    create_stacktrace(&trace, 16);
    if (trace != NULL) {
        printf("\n\nTRACE:\n%s\n\n", trace);
        free(trace);
    }
}

void foo(void) {
    bar();
}

void test_create_stacktrace(void)
{
    foo();
}

But by default, it doesn't show the function names:

TRACE:
./test_stacktrace(+0x56a6) [0x563ee1af86a6]
./test_stacktrace(+0x56b6) [0x563ee1af86b6]
./test_stacktrace(+0x3b3c) [0x563ee1af6b3c]
./test_stacktrace(+0x3f43) [0x563ee1af6f43]
./test_stacktrace(+0x52d5) [0x563ee1af82d5]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7ffa2cc0a0b3]
./test_stacktrace(+0x260e) [0x563ee1af560e]

To get the function names, I had to use -rdynamic in the link step of the Makefile, but I had to read to source code and the backtrace manpage to understand why; now I get this:

TRACE:
./test_stacktrace(foo+0xd) [0x560e3e7bc6a6]
./test_stacktrace(test_create_stacktrace+0xd) [0x560e3e7bc6b6]
./test_stacktrace(+0x3b3c) [0x560e3e7bab3c]
./test_stacktrace(+0x3f43) [0x560e3e7baf43]
./test_stacktrace(main+0x231) [0x560e3e7bc2d5]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3) [0x7f4e595650b3]
./test_stacktrace(_start+0x2e) [0x560e3e7b960e]

Eventually, we should probably switch to libunwind which AFAIK does not require -rdynamic, but for now backtrace is still very valuable!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, you're right. I am using add2line, which seem to work w/o -rdynamic. Maybe the __repr__ that prints the stack trace could also include a link to the docs where we'd document all those tricks.

Copy link
Collaborator

Choose a reason for hiding this comment

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

ah, so you get the "raw" stacktrace and convert it manually after it's printed?
This also works, although it would be nice to have it automatically of course.
+1 to add a link to some docs/howto

docs/examples/tests.py Outdated Show resolved Hide resolved
hpy/debug/src/_debugmod.c Show resolved Hide resolved
return a > b ? a : b;
}

void create_stacktrace(char **target, HPy_ssize_t max_frames_count) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suppose this is fine for now but also probably very slow and memory inefficient because it creates a textual representation of the stack trace for every handle.
I think it's possible to save only the addresses here, and delay the calls to backtrace_symbols and the construction of the textual repr only if/when it's really needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. I wanted to make it generic such that we can easily swap the backend. Thinking about it now, we may also have something like this:

void *stracktrace_create(HPy_ssize_t max_frames_count);
void stacktrace_print(void *stacktrace, char **target, HPy_ssize_t max_frames_count);
void stacktrace_free(void *stacktrace);

but I'll leave that for future work.

Copy link
Collaborator

Choose a reason for hiding this comment

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

yes, +1 for both your suggestion and for doing it in the future

@steve-s steve-s force-pushed the add/improve-debug-ctx-usability branch 3 times, most recently from 2754a0c to 37a9248 Compare May 11, 2022 08:19
@steve-s
Copy link
Contributor Author

steve-s commented May 11, 2022

@antocuni I believe I addressed the comments and the PR is ready for second round of review

@steve-s
Copy link
Contributor Author

steve-s commented May 16, 2022

ping :-)

@steve-s
Copy link
Contributor Author

steve-s commented May 23, 2022

@antocuni ping :-)

if is_debug:
print("Loading {module_name!r} in HPy universal mode with a debug context")
else:
print("Loading {module_name!r} in HPy universal mode")
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm fine using the print for now to avoid blocking this PR forever, but eventually we should probably use logging module for that, and HPY_LOG should be used to select the desired log level

hpy/debug/src/_debugmod.c Show resolved Hide resolved
setup.py Outdated
print("WARNING: environment variable HPY_DEBUG used in setup.py was "
"renamed to HPY_DEBUG_BUILD. HPY_DEBUG is now used to activate "
"the HPy debug context when running HPy extensions in universal mode.")

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is not needed. HPY_DEBUG was just an internal only thing used by our Makefile, I don't think it's used by anyone else.
And, btw, you should modify the Makefile so that make debug still works :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@steve-s steve-s force-pushed the add/improve-debug-ctx-usability branch from 5935210 to 57160f1 Compare May 24, 2022 12:26
@steve-s
Copy link
Contributor Author

steve-s commented May 24, 2022

I rebased the the PR because of minor merge conflict. The real changes since the last review are still in the last two commits.

@antocuni
Copy link
Collaborator

LGTM, thanks for addressing my comments! Merging it

@antocuni antocuni merged commit f859692 into hpyproject:master May 25, 2022
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.

None yet

2 participants