Skip to content

Commit e30b703

Browse files
authored
[mlir:python] Construct PyOperation objects in-place on the Python heap. (llvm#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.
1 parent d7fb4a2 commit e30b703

File tree

2 files changed

+22
-9
lines changed

2 files changed

+22
-9
lines changed

mlir/lib/Bindings/Python/IRCore.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,21 +1199,33 @@ PyOperation::~PyOperation() {
11991199
}
12001200
}
12011201

1202+
namespace {
1203+
1204+
// Constructs a new object of type T in-place on the Python heap, returning a
1205+
// PyObjectRef to it, loosely analogous to std::make_shared<T>().
1206+
template <typename T, class... Args>
1207+
PyObjectRef<T> makeObjectRef(Args &&...args) {
1208+
nb::handle type = nb::type<T>();
1209+
nb::object instance = nb::inst_alloc(type);
1210+
T *ptr = nb::inst_ptr<T>(instance);
1211+
new (ptr) T(std::forward<Args>(args)...);
1212+
nb::inst_mark_ready(instance);
1213+
return PyObjectRef<T>(ptr, std::move(instance));
1214+
}
1215+
1216+
} // namespace
1217+
12021218
PyOperationRef PyOperation::createInstance(PyMlirContextRef contextRef,
12031219
MlirOperation operation,
12041220
nb::object parentKeepAlive) {
12051221
// Create.
1206-
PyOperation *unownedOperation =
1207-
new PyOperation(std::move(contextRef), operation);
1208-
// Note that the default return value policy on cast is automatic_reference,
1209-
// which does not take ownership (delete will not be called).
1210-
// Just be explicit.
1211-
nb::object pyRef = nb::cast(unownedOperation, nb::rv_policy::take_ownership);
1212-
unownedOperation->handle = pyRef;
1222+
PyOperationRef unownedOperation =
1223+
makeObjectRef<PyOperation>(std::move(contextRef), operation);
1224+
unownedOperation->handle = unownedOperation.getObject();
12131225
if (parentKeepAlive) {
12141226
unownedOperation->parentKeepAlive = std::move(parentKeepAlive);
12151227
}
1216-
return PyOperationRef(unownedOperation, std::move(pyRef));
1228+
return unownedOperation;
12171229
}
12181230

12191231
PyOperationRef PyOperation::forOperation(PyMlirContextRef contextRef,

mlir/lib/Bindings/Python/IRModule.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -705,8 +705,9 @@ class PyOperation : public PyOperationBase, public BaseContextObject {
705705
/// Clones this operation.
706706
nanobind::object clone(const nanobind::object &ip);
707707

708-
private:
709708
PyOperation(PyMlirContextRef contextRef, MlirOperation operation);
709+
710+
private:
710711
static PyOperationRef createInstance(PyMlirContextRef contextRef,
711712
MlirOperation operation,
712713
nanobind::object parentKeepAlive);

0 commit comments

Comments
 (0)