Skip to content

Commit

Permalink
Merge branch 'ccrouzet/printf-variadic-args' into 'main'
Browse files Browse the repository at this point in the history
Fix `wp.printf()` Erroring With No Variadic Args

Closes NVIDIAGH-333

See merge request omniverse/warp!867
  • Loading branch information
christophercrouzet committed Nov 18, 2024
2 parents a7af93a + bba2f40 commit ab3a73b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
`warp.fem.cells()`, `warp.fem.to_inner_cell()`, `warp.fem.to_outer_cell()` operators
- Show an error message when the type returned by a function differs from its annotation, which would have led to the compilation stage failing.
- Clarify that `randn()` samples a normal distribution of mean 0 and variance 1.
- Error when passing more than 32 variadic argument to the `wp.printf` built-in.

### Fixed

Expand All @@ -29,6 +30,7 @@
- Fix the OpenGL renderer's camera snapping to a different direction from the initial camera's orientation when first looking around.
- Fix an error when a `wp.kernel` or a `wp.func` object is annotated to return a `None` value.
- Fix error when reading multi-volume, BLOSC compressed .nvdb files.
- Fix `wp.printf()` erroring out when no variadic arguments are passed ([GH-333](https://github.com/NVIDIA/warp/issues/333)).

## [1.4.2] - 2024-11-13

Expand Down
11 changes: 10 additions & 1 deletion warp/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -4155,12 +4155,20 @@ def volume_sample_grad_index_value_func(arg_types: Mapping[str, type], arg_value
)


def printf_value_func(arg_types: Mapping[str, type], arg_values: Mapping[str, Any]):
if arg_types is not None:
if len(arg_types.get("args", ())) > 32:
raise RuntimeError("the maximum number of variadic arguments that can be passed to `printf` is 32")

return None


def printf_dispatch_func(input_types: Mapping[str, type], return_type: Any, args: Mapping[str, Var]):
# We're in the codegen stage where we emit the code calling the built-in.
# Further validate the given argument values if needed and map them
# to the underlying C++ function's runtime and template params.

func_args = (args["fmt"], *args["args"])
func_args = (args["fmt"], *args.get("args", ()))
template_args = ()
return (func_args, template_args)

Expand All @@ -4171,6 +4179,7 @@ def printf_dispatch_func(input_types: Mapping[str, type], return_type: Any, args
input_types={"fmt": str, "*args": Any},
namespace="",
variadic=True,
value_func=printf_value_func,
dispatch_func=printf_dispatch_func,
group="Utility",
doc="Allows printing formatted strings using C-style format specifiers.",
Expand Down
57 changes: 56 additions & 1 deletion warp/tests/test_print.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,22 @@
def test_print_kernel():
wp.print(1.0)
wp.print("this is a string")
wp.printf("this is another string\n")
wp.printf("this is a float %f\n", 457.5)
wp.printf("this is an int %d\n", 123)
# fmt: off
wp.printf(
"0=%d, 1=%d, 2=%d, 3=%d, 4=%d, 5=%d, 6=%d, 7=%d, "
"8=%d, 9=%d, 10=%d, 11=%d, 12=%d, 13=%d, 14=%d, 15=%d, "
"16=%d, 17=%d, 18=%d, 19=%d, 20=%d, 21=%d, 22=%d, 23=%d, "
"24=%d, 25=%d, 26=%d, 27=%d, 28=%d, 29=%d, 30=%d, 31=%d"
"\n",
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
)
# fmt: on


@wp.kernel
Expand Down Expand Up @@ -59,8 +73,13 @@ def test_print(test, device):
s,
rf"1{os.linesep}"
rf"this is a string{os.linesep}"
rf"this is another string{os.linesep}"
rf"this is a float 457\.500000{os.linesep}"
rf"this is an int 123",
rf"this is an int 123{os.linesep}"
rf"0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, "
rf"8=8, 9=9, 10=10, 11=11, 12=12, 13=13, 14=14, 15=15, "
rf"16=16, 17=17, 18=18, 19=19, 20=20, 21=21, 22=22, 23=23, "
rf"24=24, 25=25, 26=26, 27=27, 28=28, 29=29, 30=30, 31=31{os.linesep}",
)


Expand Down Expand Up @@ -260,6 +279,35 @@ def test_print_adjoint(test, device):
)


def test_print_error_variadic_arg_count(test, device):
@wp.kernel
def kernel():
# fmt: off
wp.printf(
"0=%d, 1=%d, 2=%d, 3=%d, 4=%d, 5=%d, 6=%d, 7=%d, "
"8=%d, 9=%d, 10=%d, 11=%d, 12=%d, 13=%d, 14=%d, 15=%d, "
"16=%d, 17=%d, 18=%d, 19=%d, 20=%d, 21=%d, 22=%d, 23=%d, "
"24=%d, 25=%d, 26=%d, 27=%d, 28=%d, 29=%d, 30=%d, 31=%d, "
"32=%d\n",
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32,
)
# fmt: on

with test.assertRaisesRegex(
RuntimeError,
r"the maximum number of variadic arguments that can be passed to `printf` is 32$",
):
wp.launch(
kernel,
dim=1,
device=device,
)


class TestPrint(unittest.TestCase):
pass

Expand All @@ -269,6 +317,13 @@ class TestPrint(unittest.TestCase):
add_function_test(TestPrint, "test_print_numeric", test_print_numeric, devices=devices, check_output=False)
add_function_test(TestPrint, "test_print_boolean", test_print_boolean, devices=devices, check_output=False)
add_function_test(TestPrint, "test_print_adjoint", test_print_adjoint, devices=devices, check_output=False)
add_function_test(
TestPrint,
"test_print_error_variadic_arg_count",
test_print_error_variadic_arg_count,
devices=devices,
check_output=False,
)


if __name__ == "__main__":
Expand Down

0 comments on commit ab3a73b

Please sign in to comment.