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 sycl event constructor overload #1218

Merged
merged 3 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions numba_dpex/core/datamodel/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ def __init__(self, dmm, fe_type):
"meminfo",
types.MemInfoPointer(types.pyobject),
),
(
"parent",
types.pyobject,
),
(
"event_ref",
types.CPointer(types.int8),
Expand Down
57 changes: 46 additions & 11 deletions numba_dpex/core/runtime/_dpexrt_python.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ static PyObject *DPEXRT_sycl_queue_to_python(NRT_api_functions *nrt,
queuestruct_t *queuestruct);
static PyObject *DPEXRT_sycl_event_to_python(NRT_api_functions *nrt,
eventstruct_t *eventstruct);
static int DPEXRT_sycl_event_init(NRT_api_functions *nrt,
DPCTLSyclEventRef event,
eventstruct_t *eventstruct);

/** An NRT_external_malloc_func implementation using DPCTLmalloc_device.
*
Expand Down Expand Up @@ -1359,6 +1362,7 @@ static int DPEXRT_sycl_event_from_python(NRT_api_functions *nrt,
Py_INCREF(event_obj);
event_struct->meminfo =
nrt->manage_memory(event_obj, NRT_MemInfo_pyobject_dtor);
event_struct->parent = (PyObject *)event_obj;
event_struct->event_ref = event_ref;

return 0;
Expand Down Expand Up @@ -1388,17 +1392,13 @@ static int DPEXRT_sycl_event_from_python(NRT_api_functions *nrt,
static PyObject *DPEXRT_sycl_event_to_python(NRT_api_functions *nrt,
eventstruct_t *eventstruct)
{
PyObject *event_obj = NULL;
PyGILState_STATE gstate;

event_obj = nrt->get_data(eventstruct->meminfo);

DPEXRT_DEBUG(
drt_debug_print("DPEXRT-DEBUG: In DPEXRT_sycl_event_to_python.\n"););
PyObject *event_obj = eventstruct->parent;

if (event_obj == NULL) {
// Make create copy of event_ref so we don't need to manage nrt lifetime
// from python object.
DPEXRT_DEBUG(
drt_debug_print("DPEXRT-DEBUG: creating new event object.\n"););
// SyclEvent_Make creates copy of event_ref so we don't need to manage
// nrt lifetime from python object.
event_obj = (PyObject *)SyclEvent_Make(eventstruct->event_ref);
}
else {
Expand All @@ -1410,12 +1410,45 @@ static PyObject *DPEXRT_sycl_event_to_python(NRT_api_functions *nrt,
Py_INCREF(event_obj);
}

// We need to release meminfo since we are taking ownership back.
// We need to release meminfo since we no longer need this reference in nrt.
nrt->release(eventstruct->meminfo);

return event_obj;
}

/*!
* @brief A helper function that initializes Numba-dpex eventstruct_t object
* for the DPCTLSyclEventRef allocated inside dpjit. Parent is set to NULL.
*
* @param nrt A Numba pointer to public api functions.
* @param event A dpctl event reference.
* @param eventstruct A Numba-dpex eventstruct object (datamodel).
* @return {return} Nothing.
*/
static int DPEXRT_sycl_event_init(NRT_api_functions *nrt,
DPCTLSyclEventRef event,
eventstruct_t *eventstruct)
{
if (eventstruct == NULL) {
DPEXRT_DEBUG(drt_debug_print(
"DPEXRT-ERROR: Failed to initialize dpctl SyclEvent into a Numba "
"eventstruct at %s, line %d. eventstruct is NULL.\n",
__FILE__, __LINE__));

return -1;
}

DPEXRT_DEBUG(
drt_debug_print("DPEXRT-DEBUG: creating new dpctl event meminfo.\n"););
eventstruct->parent = NULL;
eventstruct->event_ref = (void *)event;
// manage_memory sets ref count to 1.
eventstruct->meminfo =
nrt->manage_memory(event, NRT_MemInfo_EventRef_Delete);

return 0;
}

/*----------------------------------------------------------------------------*/
/*--------------------- The _dpexrt_python Python extension module -- -------*/
/*----------------------------------------------------------------------------*/
Expand Down Expand Up @@ -1456,6 +1489,7 @@ static PyObject *build_c_helpers_dict(void)
_declpointer("DPEXRT_sycl_event_from_python",
&DPEXRT_sycl_event_from_python);
_declpointer("DPEXRT_sycl_event_to_python", &DPEXRT_sycl_event_to_python);
_declpointer("DPEXRT_sycl_event_init", &DPEXRT_sycl_event_init);

#undef _declpointer
return dct;
Expand Down Expand Up @@ -1511,7 +1545,8 @@ MOD_INIT(_dpexrt_python)
PyLong_FromVoidPtr(&DPEXRT_sycl_event_from_python));
PyModule_AddObject(m, "DPEXRT_sycl_event_to_python",
PyLong_FromVoidPtr(&DPEXRT_sycl_event_to_python));

PyModule_AddObject(m, "DPEXRT_sycl_event_init",
PyLong_FromVoidPtr(&DPEXRT_sycl_event_init));
PyModule_AddObject(m, "DPEXRTQueue_CreateFromFilterString",
PyLong_FromVoidPtr(&DPEXRTQueue_CreateFromFilterString));
PyModule_AddObject(m, "DpexrtQueue_SubmitRange",
Expand Down
23 changes: 23 additions & 0 deletions numba_dpex/core/runtime/_eventstruct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2020 - 2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0

#include "_eventstruct.h"
#include "_dbg_printer.h"

/*!
* @brief A destructor that is called from NRT on object destruction. Deletes
* dpctl event reference.
*
* @param data A dpctl event reference.
* @return {return} Nothing.
*/
void NRT_MemInfo_EventRef_Delete(void *data)
{
DPCTLSyclEventRef eref = data;

DPCTLEvent_Delete(eref);

DPEXRT_DEBUG(
drt_debug_print("DPEXRT-DEBUG: deleting dpctl event reference.\n"););
}
11 changes: 10 additions & 1 deletion numba_dpex/core/runtime/_eventstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,21 @@
///
//===----------------------------------------------------------------------===//

#pragma once
#ifndef _EVENTSTRUCT_H_
#define _EVENTSTRUCT_H_

#include "_nrt_helper.h"
#include "dpctl_sycl_interface.h"
#include "numba/core/runtime/nrt_external.h"
#include <Python.h>

typedef struct
{
NRT_MemInfo *meminfo;
PyObject *parent;
void *event_ref;
} eventstruct_t;

void NRT_MemInfo_EventRef_Delete(void *data);

#endif /* _EVENTSTRUCT_H_ */
18 changes: 18 additions & 0 deletions numba_dpex/core/runtime/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,24 @@ def eventstruct_to_python(self, pyapi, val):

return self.error

def eventstruct_init(self, pyapi, event, struct):
"""Calls the c function DPEXRT_sycl_event_init"""

fnty = llvmir.FunctionType(
llvmir.IntType(32), [pyapi.voidptr, pyapi.voidptr, pyapi.voidptr]
)
nrt_api = self._context.nrt.get_nrt_api(pyapi.builder)

fn = pyapi._get_function(fnty, "DPEXRT_sycl_event_init")
fn.args[0].add_attribute("nocapture")
fn.args[1].add_attribute("nocapture")
fn.args[2].add_attribute("nocapture")

ptr = pyapi.builder.bitcast(struct, pyapi.voidptr)
self.error = pyapi.builder.call(fn, [nrt_api, event, ptr])

return self.error

def usm_ndarray_to_python_acqref(self, pyapi, aryty, ary, dtypeptr):
"""Boxes a DpnpNdArray native object into a Python dpnp.ndarray.

Expand Down
2 changes: 0 additions & 2 deletions numba_dpex/core/types/dpctl_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ def box_sycl_event(typ, val, c):
if not c.context.enable_nrt:
raise UnreachableError

print("boxing...")

dpexrtCtx = dpexrt.DpexRTContext(c.context)
event = dpexrtCtx.eventstruct_to_python(c.pyapi, val)

Expand Down
56 changes: 54 additions & 2 deletions numba_dpex/dpctl_iface/_intrinsic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,56 @@
#
# SPDX-License-Identifier: Apache-2.0

import dpctl
from llvmlite.ir import IRBuilder
from numba import types
from numba.core import cgutils, imputils
from numba.core.datamodel import default_manager
from numba.extending import intrinsic, overload_method
from numba.extending import intrinsic, overload, overload_method, type_callable

import numba_dpex.dpctl_iface.libsyclinterface_bindings as sycl
from numba_dpex.core import types as dpex_types
from numba_dpex.core.runtime import context as dpexrt


@intrinsic
def sycl_event_create(
ty_context,
):
"""A numba "intrinsic" function to inject dpctl.SyclEvent constructor code.

Args:
ty_context (numba.core.typing.context.Context): The typing context
for the codegen.

Returns:
tuple(numba.core.typing.templates.Signature, function): A tuple of
numba function signature type and a function object.
"""
ty_event = dpex_types.DpctlSyclEvent()

sig = ty_event(types.void)

def codegen(context, builder: IRBuilder, sig, args: list):
pyapi = context.get_python_api(builder)

event_struct_proxy = cgutils.create_struct_proxy(ty_event)(
context, builder
)

event = sycl.dpctl_event_create(builder)
dpexrtCtx = dpexrt.DpexRTContext(context)

# Ref count after the call is equal to 1.
dpexrtCtx.eventstruct_init(
pyapi, event, event_struct_proxy._getpointer()
)

event_value = event_struct_proxy._getvalue()

return event_value

return sig, codegen


@intrinsic
Expand All @@ -27,11 +71,19 @@ def codegen(context, builder, signature, args):
return sig, codegen


@overload(dpctl.SyclEvent)
def ol_dpctl_sycl_event_create():
"""Implementation of an overload to support dpctl.SyclEvent() inside
a dpjit function.
"""
return lambda: sycl_event_create()


@overload_method(dpex_types.DpctlSyclEvent, "wait")
def ol_dpctl_sycl_event_wait(
event,
):
"""Implementation of an overload to support dpctl.SyclEvent() inside
"""Implementation of an overload to support dpctl.SyclEvent.wait() inside
a dpjit function.
"""
return lambda event: sycl_event_wait(event)
Expand Down
14 changes: 14 additions & 0 deletions numba_dpex/dpctl_iface/libsyclinterface_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ def dpctl_queue_memcpy(builder: llvmir.IRBuilder, *args):
return ret


def dpctl_event_create(builder: llvmir.IRBuilder, *args):
"""Inserts LLVM IR to call DPCTLEvent_Create."""
mod = builder.module
fn = _build_dpctl_function(
llvm_module=mod,
return_ty=cgutils.voidptr_t,
arg_list=[],
func_name="DPCTLEvent_Create",
)
ret = builder.call(fn, args)

return ret


def dpctl_queue_delete(builder: llvmir.IRBuilder, *args):
"""Inserts LLVM IR to call DPCTLQueue_Delete."""
mod = builder.module
Expand Down
42 changes: 42 additions & 0 deletions numba_dpex/tests/core/types/DpctlSyclEvent/test_box.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# SPDX-FileCopyrightText: 2020 - 2023 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0

"""
Tests for boxing and allocating for dpctl.SyclEvent
"""

import sys

from dpctl import SyclEvent

from numba_dpex import dpjit


def test_dpjit_constructor():
"""Test event delete that does not have parent"""

@dpjit
def func() -> SyclEvent:
SyclEvent()
return None

# We just want to make sure execution did not crush. There are currently
# no way to check if event wast destroyed, except manual run with debug
# logs on.
func()


def test_boxing_without_parent():
"""Test unboxing of the event that does not have parent"""

@dpjit
def func() -> SyclEvent:
event = SyclEvent()
return event

e: SyclEvent = func()
ref_cnt = sys.getrefcount(e)

assert isinstance(e, SyclEvent)
assert ref_cnt == 2
2 changes: 1 addition & 1 deletion numba_dpex/tests/core/types/DpctlSyclQueue/test_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0

"""
Tests for boxing for dpnp.ndarray
Tests for boxing for dpctl.SyclQueue
"""

import dpnp
Expand Down
2 changes: 1 addition & 1 deletion numba_dpex/tests/dpjit_tests/test_slicing.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0

"""
Tests for boxing for dpnp.ndarray
Tests for slicing dpnp.ndarray
"""

import dpnp
Expand Down
Loading