Skip to content

Commit

Permalink
Switch jaxlib to use nanobind instead of pybind11.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 534535677
  • Loading branch information
hawkinsp authored and jax authors committed May 23, 2023
1 parent db87167 commit edb03cb
Show file tree
Hide file tree
Showing 21 changed files with 535 additions and 190 deletions.
8 changes: 7 additions & 1 deletion WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ xla_workspace1()
load("@xla//:workspace0.bzl", "xla_workspace0")
xla_workspace0()


load("//third_party/flatbuffers:workspace.bzl", flatbuffers = "repo")
flatbuffers()

load("//third_party/robin_map:workspace.bzl", robin_map = "repo")
robin_map()

load("//third_party/nanobind:workspace.bzl", nanobind = "repo")
nanobind()

4 changes: 2 additions & 2 deletions examples/jax_cpp/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ cc_binary(
"@xla//xla/pjrt:tfrt_cpu_pjrt_client",
"@xla//xla/service:hlo_proto_cc",
"@xla//xla/tools:hlo_module_loader",
"@tsl///platform:logging",
"@tsl///platform:platform_port",
"@tsl//tsl/platform:logging",
"@tsl//tsl/platform:platform_port",
],
)
23 changes: 19 additions & 4 deletions jaxlib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,32 @@ exports_files([
])

cc_library(
name = "kernel_pybind11_helpers",
hdrs = ["kernel_pybind11_helpers.h"],
name = "absl_status_casters",
hdrs = ["absl_status_casters.h"],
copts = [
"-fexceptions",
"-fno-strict-aliasing",
],
features = ["-use_header_modules"],
deps = [
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
],
)

cc_library(
name = "kernel_nanobind_helpers",
hdrs = ["kernel_nanobind_helpers.h"],
copts = [
"-fexceptions",
"-fno-strict-aliasing",
],
features = ["-use_header_modules"],
deps = [
":kernel_helpers",
"@tsl//tsl/python/lib/core:numpy",
"@com_google_absl//absl/base",
"@pybind11",
"@nanobind",
],
)

Expand Down Expand Up @@ -159,7 +174,7 @@ pybind_extension(
"@xla//third_party/python_runtime:headers",
"@com_google_absl//absl/cleanup",
"@com_google_absl//absl/container:inlined_vector",
"@pybind11",
"@nanobind",
],
)

Expand Down
216 changes: 216 additions & 0 deletions jaxlib/absl_status_casters.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/* Copyright 2023 The JAX Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#ifndef JAXLIB_ABSL_STATUS_CASTERS_H_
#define JAXLIB_ABSL_STATUS_CASTERS_H_

#include "absl/status/status.h"
#include "absl/status/statusor.h"

namespace jax {

// C++ -> Python caster helpers.
//
// Failing statuses become Python exceptions; OK Status() becomes None.
//
// Given there can be only a single global pybind11 type_caster for the
// `absl::Status` type, and given XLA wants a custom exception being raised,
// we use a dedicated helper to implement this feature without relying on a
// global `type_caster`.
//
// For example:
//
// - Functions without arguments:
// m.def("my_func", []() { ThrowIfError(MyFunc()); }
// - Classes with a single argument:
// py_class.def("delete", [](Buffer& self) {
// ThrowIfError(self.Delete());
// }
//
// For functions with more arguments, you can either inline the arguments,
// or use the `ThrowIfErrorWrapper` wrapper defined below:
//
// m.def("my_func", ThrowIfErrorWrapper(MyFunc));
//
// Nonstatic member functions can be wrapped by passing a
// pointer-to-member-function:
// ThrowIfErrorWrapper(&MyClass::MyMethod)

inline void ThrowIfError(absl::Status src) {
if (!src.ok()) {
throw std::runtime_error(src.ToString());
}
}

// If one does not want to have to define a lambda specifying the inputs
// arguments, on can use the `ThrowIfErrorWrapper` wrapper.
//
// There are three specializations:
// - For free functions, `Sig` is the function type and `F` is `Sig&`.
// - For callable types, `Sig` is the pointer to member function type
// and `F` is the type of the callable.
// - For a nonstatic member function of a class `C`, `Sig` is the function type
// and `F` is Sig C::*.
//
// In the first two cases, the wrapper returns a callable with signature `Sig`;
// in the third case, the wrapper returns callable with a modified signature
// that takes a C instance as the first argument.
template <typename Sig, typename F>
struct ThrowIfErrorWrapper;

// C++17 "deduction guide" that guides class template argument deduction (CTAD)
// For free functions.
template <typename F>
ThrowIfErrorWrapper(F) -> ThrowIfErrorWrapper<decltype(&F::operator()), F>;

// For callable types (with operator()).
template <typename... Args>
ThrowIfErrorWrapper(absl::Status (&)(Args...))
-> ThrowIfErrorWrapper<absl::Status(Args...), absl::Status (&)(Args...)>;

// For unbound nonstatic member functions.
template <typename C, typename... Args>
ThrowIfErrorWrapper(absl::Status (C::*)(Args...))
-> ThrowIfErrorWrapper<absl::Status(Args...), C>;

// Template specializations.

// For free functions.
template <typename... Args>
struct ThrowIfErrorWrapper<absl::Status(Args...), absl::Status (&)(Args...)> {
explicit ThrowIfErrorWrapper(absl::Status (&f)(Args...)) : func(f) {}
void operator()(Args... args) {
ThrowIfError(func(std::forward<Args>(args)...));
}
absl::Status (&func)(Args...);
};

// For callable types (with operator()), non-const and const versions.
template <typename C, typename... Args, typename F>
struct ThrowIfErrorWrapper<absl::Status (C::*)(Args...), F> {
explicit ThrowIfErrorWrapper(F&& f) : func(std::move(f)) {}
void operator()(Args... args) {
ThrowIfError(func(std::forward<Args>(args)...));
}
F func;
};
template <typename C, typename... Args, typename F>
struct ThrowIfErrorWrapper<absl::Status (C::*)(Args...) const, F> {
explicit ThrowIfErrorWrapper(F&& f) : func(std::move(f)) {}
void operator()(Args... args) const {
ThrowIfError(func(std::forward<Args>(args)...));
}
F func;
};

// For unbound nonstatic member functions, non-const and const versions.
// `ptmf` stands for "pointer to member function".
template <typename C, typename... Args>
struct ThrowIfErrorWrapper<absl::Status(Args...), C> {
explicit ThrowIfErrorWrapper(absl::Status (C::*ptmf)(Args...)) : ptmf(ptmf) {}
void operator()(C& instance, Args... args) {
ThrowIfError((instance.*ptmf)(std::forward<Args>(args)...));
}
absl::Status (C::*ptmf)(Args...);
};
template <typename C, typename... Args>
struct ThrowIfErrorWrapper<absl::Status(Args...) const, C> {
explicit ThrowIfErrorWrapper(absl::Status (C::*ptmf)(Args...) const)
: ptmf(ptmf) {}
void operator()(const C& instance, Args... args) const {
ThrowIfError((instance.*ptmf)(std::forward<Args>(args)...));
}
absl::Status (C::*ptmf)(Args...) const;
};

// Utilities for `StatusOr`.
template <typename T>
T ValueOrThrow(absl::StatusOr<T> v) {
if (!v.ok()) {
throw std::runtime_error(v.status().ToString());
}
return std::move(v).value();
}

template <typename Sig, typename F>
struct ValueOrThrowWrapper;

template <typename F>
ValueOrThrowWrapper(F) -> ValueOrThrowWrapper<decltype(&F::operator()), F>;

template <typename R, typename... Args>
ValueOrThrowWrapper(absl::StatusOr<R> (&)(Args...))
-> ValueOrThrowWrapper<absl::StatusOr<R>(Args...),
absl::StatusOr<R> (&)(Args...)>;

template <typename C, typename R, typename... Args>
ValueOrThrowWrapper(absl::StatusOr<R> (C::*)(Args...))
-> ValueOrThrowWrapper<absl::StatusOr<R>(Args...), C>;

// Deduction guide for const methods.
template <typename C, typename R, typename... Args>
ValueOrThrowWrapper(absl::StatusOr<R> (C::*)(Args...) const)
-> ValueOrThrowWrapper<absl::StatusOr<R>(Args...) const, C>;

template <typename R, typename... Args>
struct ValueOrThrowWrapper<absl::StatusOr<R>(Args...),
absl::StatusOr<R> (&)(Args...)> {
explicit ValueOrThrowWrapper(absl::StatusOr<R> (&f)(Args...)) : func(f) {}
R operator()(Args... args) const {
return ValueOrThrow(func(std::forward<Args>(args)...));
}
absl::StatusOr<R> (&func)(Args...);
};
template <typename R, typename C, typename... Args, typename F>
struct ValueOrThrowWrapper<absl::StatusOr<R> (C::*)(Args...), F> {
explicit ValueOrThrowWrapper(F&& f) : func(std::move(f)) {}
R operator()(Args... args) const {
return ValueOrThrow(func(std::forward<Args>(args)...));
}
F func;
};
template <typename R, typename C, typename... Args, typename F>
struct ValueOrThrowWrapper<absl::StatusOr<R> (C::*)(Args...) const, F> {
explicit ValueOrThrowWrapper(F&& f) : func(std::move(f)) {}
R operator()(Args... args) const {
return ValueOrThrow(func(std::forward<Args>(args)...));
}
F func;
};

// For unbound nonstatic member functions, non-const and const versions.
// `ptmf` stands for "pointer to member function".
template <typename R, typename C, typename... Args>
struct ValueOrThrowWrapper<absl::StatusOr<R>(Args...), C> {
explicit ValueOrThrowWrapper(absl::StatusOr<R> (C::*ptmf)(Args...))
: ptmf(ptmf) {}
R operator()(C& instance, Args... args) {
return ValueOrThrow((instance.*ptmf)(std::forward<Args>(args)...));
}
absl::StatusOr<R> (C::*ptmf)(Args...);
};
template <typename R, typename C, typename... Args>
struct ValueOrThrowWrapper<absl::StatusOr<R>(Args...) const, C> {
explicit ValueOrThrowWrapper(absl::StatusOr<R> (C::*ptmf)(Args...) const)
: ptmf(ptmf) {}
R operator()(const C& instance, Args... args) const {
return ValueOrThrow((instance.*ptmf)(std::forward<Args>(args)...));
}
absl::StatusOr<R> (C::*ptmf)(Args...) const;
};

} // namespace jax

#endif // JAXLIB_ABSL_STATUS_CASTERS_H_
8 changes: 4 additions & 4 deletions jaxlib/cpu/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ pybind_extension(
module_name = "_lapack",
deps = [
":lapack_kernels",
"//jaxlib:kernel_pybind11_helpers",
"@pybind11",
"//jaxlib:kernel_nanobind_helpers",
"@nanobind",
],
)

Expand Down Expand Up @@ -95,9 +95,9 @@ pybind_extension(
deps = [
":ducc_fft_flatbuffers_cc",
":ducc_fft_kernels",
"//jaxlib:kernel_pybind11_helpers",
"//jaxlib:kernel_nanobind_helpers",
"@flatbuffers//:runtime_cc",
"@pybind11",
"@nanobind",
],
)

Expand Down
26 changes: 13 additions & 13 deletions jaxlib/cpu/ducc_fft.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ limitations under the License.
#include <complex>
#include <vector>

#include "pybind11/pybind11.h"
#include "pybind11/stl.h"
#include "nanobind/nanobind.h"
#include "nanobind/stl/vector.h"
#include "jaxlib/cpu/ducc_fft_generated.h"
#include "jaxlib/cpu/ducc_fft_kernels.h"
#include "jaxlib/kernel_pybind11_helpers.h"
#include "jaxlib/kernel_nanobind_helpers.h"

namespace py = pybind11;
namespace nb = nanobind;

namespace jax {
namespace {

py::bytes BuildDuccFftDescriptor(const std::vector<uint64_t> &shape,
nb::bytes BuildDuccFftDescriptor(const std::vector<uint64_t> &shape,
bool is_double, int fft_type,
const std::vector<uint64_t> &fft_lengths,
const std::vector<uint64_t> &strides_in,
Expand All @@ -46,22 +46,22 @@ py::bytes BuildDuccFftDescriptor(const std::vector<uint64_t> &shape,
descriptor.scale = scale;
flatbuffers::FlatBufferBuilder fbb;
fbb.Finish(DuccFftDescriptor::Pack(fbb, &descriptor));
return py::bytes(reinterpret_cast<char *>(fbb.GetBufferPointer()),
return nb::bytes(reinterpret_cast<char *>(fbb.GetBufferPointer()),
fbb.GetSize());
}

py::dict Registrations() {
pybind11::dict dict;
nb::dict Registrations() {
nb::dict dict;
dict["ducc_fft"] = EncapsulateFunction(DuccFft);
return dict;
}

PYBIND11_MODULE(_ducc_fft, m) {
NB_MODULE(_ducc_fft, m) {
m.def("registrations", &Registrations);
m.def("ducc_fft_descriptor", &BuildDuccFftDescriptor, py::arg("shape"),
py::arg("is_double"), py::arg("fft_type"), py::arg("fft_lengths"),
py::arg("strides_in"), py::arg("strides_out"), py::arg("axes"),
py::arg("forward"), py::arg("scale"));
m.def("ducc_fft_descriptor", &BuildDuccFftDescriptor, nb::arg("shape"),
nb::arg("is_double"), nb::arg("fft_type"), nb::arg("fft_lengths"),
nb::arg("strides_in"), nb::arg("strides_out"), nb::arg("axes"),
nb::arg("forward"), nb::arg("scale"));
}

} // namespace
Expand Down
Loading

0 comments on commit edb03cb

Please sign in to comment.