[Mlir-commits] [mlir] e30b703 - [mlir:python] Construct PyOperation objects in-place on the Python heap. (#123813)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jan 22 06:26:48 PST 2025
Author: Peter Hawkins
Date: 2025-01-22T06:26:44-08:00
New Revision: e30b703060bb6741fb5e5e05e6b37802bc29b4ce
URL: https://github.com/llvm/llvm-project/commit/e30b703060bb6741fb5e5e05e6b37802bc29b4ce
DIFF: https://github.com/llvm/llvm-project/commit/e30b703060bb6741fb5e5e05e6b37802bc29b4ce.diff
LOG: [mlir:python] Construct PyOperation objects in-place on the Python heap. (#123813)
Currently we make two memory allocations for each PyOperation: a Python
object, and the PyOperation class itself. With some care we can allocate
the PyOperation inline inside the Python object, saving us a malloc()
call per object and perhaps improving cache locality.
Added:
Modified:
mlir/lib/Bindings/Python/IRCore.cpp
mlir/lib/Bindings/Python/IRModule.h
Removed:
################################################################################
diff --git a/mlir/lib/Bindings/Python/IRCore.cpp b/mlir/lib/Bindings/Python/IRCore.cpp
index 1c9fb3d2abf557..c862ec84fcbc55 100644
--- a/mlir/lib/Bindings/Python/IRCore.cpp
+++ b/mlir/lib/Bindings/Python/IRCore.cpp
@@ -1199,21 +1199,33 @@ PyOperation::~PyOperation() {
}
}
+namespace {
+
+// Constructs a new object of type T in-place on the Python heap, returning a
+// PyObjectRef to it, loosely analogous to std::make_shared<T>().
+template <typename T, class... Args>
+PyObjectRef<T> makeObjectRef(Args &&...args) {
+ nb::handle type = nb::type<T>();
+ nb::object instance = nb::inst_alloc(type);
+ T *ptr = nb::inst_ptr<T>(instance);
+ new (ptr) T(std::forward<Args>(args)...);
+ nb::inst_mark_ready(instance);
+ return PyObjectRef<T>(ptr, std::move(instance));
+}
+
+} // namespace
+
PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
MlirOperation operation,
nb::object parentKeepAlive) {
// Create.
- PyOperation *unownedOperation =
- new PyOperation(std::move(contextRef), operation);
- // Note that the default return value policy on cast is automatic_reference,
- // which does not take ownership (delete will not be called).
- // Just be explicit.
- nb::object pyRef = nb::cast(unownedOperation, nb::rv_policy::take_ownership);
- unownedOperation->handle = pyRef;
+ PyOperationRef unownedOperation =
+ makeObjectRef<PyOperation>(std::move(contextRef), operation);
+ unownedOperation->handle = unownedOperation.getObject();
if (parentKeepAlive) {
unownedOperation->parentKeepAlive = std::move(parentKeepAlive);
}
- return PyOperationRef(unownedOperation, std::move(pyRef));
+ return unownedOperation;
}
PyOperationRef PyOperation::forOperation(PyMlirContextRef contextRef,
diff --git a/mlir/lib/Bindings/Python/IRModule.h b/mlir/lib/Bindings/Python/IRModule.h
index 2228b55231b0bd..fd70ac7ac6ec39 100644
--- a/mlir/lib/Bindings/Python/IRModule.h
+++ b/mlir/lib/Bindings/Python/IRModule.h
@@ -705,8 +705,9 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
/// Clones this operation.
nanobind::object clone(const nanobind::object &ip);
-private:
PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
+
+private:
static PyOperationRef createInstance(PyMlirContextRef contextRef,
MlirOperation operation,
nanobind::object parentKeepAlive);
More information about the Mlir-commits
mailing list