Skip to content

Commit

Permalink
Add sycl event custructor overload
Browse files Browse the repository at this point in the history
  • Loading branch information
ZzEeKkAa committed Nov 15, 2023
1 parent f38d005 commit f305147
Show file tree
Hide file tree
Showing 9 changed files with 196 additions and 13 deletions.
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
44 changes: 35 additions & 9 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_new(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,15 +1392,11 @@ 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) {
DPEXRT_DEBUG(
drt_debug_print("DPEXRT-DEBUG: creating new event object.\n"););
// Make create copy of event_ref so we don't need to manage nrt lifetime
// from python object.
event_obj = (PyObject *)SyclEvent_Make(eventstruct->event_ref);
Expand All @@ -1410,12 +1410,36 @@ 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_new(NRT_api_functions *nrt,
DPCTLSyclEventRef event,
eventstruct_t *eventstruct)
{
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 +1480,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_new", &DPEXRT_sycl_event_new);

#undef _declpointer
return dct;
Expand Down Expand Up @@ -1511,7 +1536,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_new",
PyLong_FromVoidPtr(&DPEXRT_sycl_event_new));
PyModule_AddObject(m, "DPEXRTQueue_CreateFromFilterString",
PyLong_FromVoidPtr(&DPEXRTQueue_CreateFromFilterString));
PyModule_AddObject(m, "DpexrtQueue_SubmitRange",
Expand Down
30 changes: 30 additions & 0 deletions numba_dpex/core/runtime/_eventstruct.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: 2020 - 2023 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0

//===----------------------------------------------------------------------===//
///
/// \file
/// Defines the numba-dpex native representation for a dpctl.SyclEvent
///
//===----------------------------------------------------------------------===//

#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_new(self, pyapi, event, struct):
"""Calls the c function DPEXRT_sycl_event_new"""

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_new")
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
44 changes: 43 additions & 1 deletion numba_dpex/dpctl_iface/_intrinsic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
#
# 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
Expand All @@ -27,6 +31,36 @@ def codegen(context, builder, signature, args):
return sig, codegen


@intrinsic
def sycl_event_create(
ty_context,
):
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_new(
pyapi, event, event_struct_proxy._getpointer()
)

event_value = event_struct_proxy._getvalue()

return event_value

return sig, codegen


@overload_method(dpex_types.DpctlSyclEvent, "wait")
def ol_dpctl_sycl_event_wait(
event,
Expand All @@ -37,6 +71,14 @@ def ol_dpctl_sycl_event_wait(
return lambda event: sycl_event_wait(event)


@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()


# We don't want user to call sycl_event_wait(event), instead it must be called
# with event.wait(). In that way we guarantee the argument type by the
# @overload_method.
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 for dpnp.ndarray
"""

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

0 comments on commit f305147

Please sign in to comment.