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

Add .npy support to debug_to_file() #8177

Merged
merged 23 commits into from
Apr 11, 2024
Merged

Conversation

steven-johnson
Copy link
Contributor

Built on top of #8175, this adds .npy as an option. This is actually pretty great because it's easy to do something like

ss = numpy.load("my_file.npy")
print(ss)

in Python and get nicely-formatted output, which can sometimes be a lot easier for debugging that inserting lots of print() statements (see #8176)

Did a drive-by change to the correctness test to use this format instead of .mat.

The .npy format is NumPy's native format for storing multidimensional arrays (aka tensors/buffers). Being able to load/save in this format makes it (potentially) a lot easier to interchange data with the Python ecosystem, as well as providing a file format that support floating-point data more robustly than any of the others that we current support.

This adds load/save support for a useful subset:
- We support the int/uint/float types common in Halide (except for f16/bf16 for now)
- We don't support reading or writing files that are in `fortran_order`
- We don't support any object/struct/etc files, only numeric primitives
- We only support loading files that are in the host's endianness (typically little-endian)

Note that at present this doesn't support f16 / bf16 formats, but that could likely be added with minimal difficulty.

The tricky bit of this is that the reading code has to parse a (limited) Python dict in text form. Please review that part carefully.

TODO: we could probably add this as an option for `debug_to_file()` without too much pain in a followup PR.
Built on top of #8175, this adds .npy as an option. This is actually pretty great because it's easy to do something like

```
ss = numpy.load("my_file.npy")
print(ss)
```

in Python and get nicely-formatted output, which can sometimes be a lot easier for debugging that inserting lots of print() statements (see #8176)

Did a drive-by change to the correctness test to use this format instead of .mat.
char *dst = dict_string_buf;
char *end = dict_string_buf + kMaxDictStringSize - 1;

dst = halide_string_to_string(dst, end, "{'descr': '");
Copy link
Member

@abadams abadams Apr 4, 2024

Choose a reason for hiding this comment

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

Why not a StackStringStreamPrinter here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

...because I didn't think of it?

@abadams
Copy link
Member

abadams commented Apr 4, 2024

This function shouldn't call halide_error. Halide_error is called at the Halide IR level if it fails, with a more informative error message (it names the Func)

@abadams
Copy link
Member

abadams commented Apr 4, 2024

Would be nice to in some way distinguish in the type system which parts of the runtime should return an error code and have already called halide_error, vs which parts return an error code that still needs a call to halide_error to happen above.

@steven-johnson
Copy link
Contributor Author

Would be nice to in some way distinguish in the type system which parts of the runtime should return an error code and have already called halide_error, vs which parts return an error code that still needs a call to halide_error to happen above.

Yeah, everything about error handling in the runtime is messy. A few years ago I started work on a proposal to rationalize it but ended up abandoning it.

@steven-johnson
Copy link
Contributor Author

This function shouldn't call halide_error. Halide_error is called at the Halide IR level if it fails, with a more informative error message (it names the Func)

Surely you don't mean that we shouldn't call it anywhere in halide_debug_to_file()?

@steven-johnson
Copy link
Contributor Author

PTAL

@abadams
Copy link
Member

abadams commented Apr 4, 2024

I do mean that. It produces an error message with less information than if we just return an error code without calling halide_error, and if halide_error has been overridden to return instead of aborting. It produces two error messages for the same error.

Base automatically changed from srj/npy-format to main April 6, 2024 15:17
@steven-johnson
Copy link
Contributor Author

PTAL -- I can use StackStringPrinter if you prefer but the underlying codegen will likely be identical, LMK

@@ -42,6 +42,8 @@ class DebugToFile : public IRMutator {
num_elements *= bound.extent;
}

// TODO: why do we bother with this? halide_debug_to_file()
Copy link
Member

Choose a reason for hiding this comment

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

This code predates halide_buffer_t, and buffer_t only had an elem_size, not a type code. Feel free to fix.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This code predates halide_buffer_t, and buffer_t only had an elem_size, not a type code. Feel free to fix.

I'll do that as a followup.

@steven-johnson
Copy link
Contributor Author

Gentle Review Ping

@steven-johnson steven-johnson merged commit dc83707 into main Apr 11, 2024
19 checks passed
@steven-johnson steven-johnson deleted the srj/npy-debug-to-file branch April 11, 2024 18:04
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.

2 participants