Skip to content

Commit ca8e769

Browse files
authored
Merge pull request #1218 from IntelPython/feature/overload_syclevent
Add sycl event constructor overload
2 parents 6ca670d + 1fe4ad0 commit ca8e769

File tree

11 files changed

+213
-18
lines changed

11 files changed

+213
-18
lines changed

numba_dpex/core/datamodel/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ def __init__(self, dmm, fe_type):
179179
"meminfo",
180180
types.MemInfoPointer(types.pyobject),
181181
),
182+
(
183+
"parent",
184+
types.pyobject,
185+
),
182186
(
183187
"event_ref",
184188
types.CPointer(types.int8),

numba_dpex/core/runtime/_dpexrt_python.c

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ static PyObject *DPEXRT_sycl_queue_to_python(NRT_api_functions *nrt,
7474
queuestruct_t *queuestruct);
7575
static PyObject *DPEXRT_sycl_event_to_python(NRT_api_functions *nrt,
7676
eventstruct_t *eventstruct);
77+
static int DPEXRT_sycl_event_init(NRT_api_functions *nrt,
78+
DPCTLSyclEventRef event,
79+
eventstruct_t *eventstruct);
7780

7881
/** An NRT_external_malloc_func implementation using DPCTLmalloc_device.
7982
*
@@ -1359,6 +1362,7 @@ static int DPEXRT_sycl_event_from_python(NRT_api_functions *nrt,
13591362
Py_INCREF(event_obj);
13601363
event_struct->meminfo =
13611364
nrt->manage_memory(event_obj, NRT_MemInfo_pyobject_dtor);
1365+
event_struct->parent = (PyObject *)event_obj;
13621366
event_struct->event_ref = event_ref;
13631367

13641368
return 0;
@@ -1388,17 +1392,13 @@ static int DPEXRT_sycl_event_from_python(NRT_api_functions *nrt,
13881392
static PyObject *DPEXRT_sycl_event_to_python(NRT_api_functions *nrt,
13891393
eventstruct_t *eventstruct)
13901394
{
1391-
PyObject *event_obj = NULL;
1392-
PyGILState_STATE gstate;
1393-
1394-
event_obj = nrt->get_data(eventstruct->meminfo);
1395-
1396-
DPEXRT_DEBUG(
1397-
drt_debug_print("DPEXRT-DEBUG: In DPEXRT_sycl_event_to_python.\n"););
1395+
PyObject *event_obj = eventstruct->parent;
13981396

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

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

14161416
return event_obj;
14171417
}
14181418

1419+
/*!
1420+
* @brief A helper function that initializes Numba-dpex eventstruct_t object
1421+
* for the DPCTLSyclEventRef allocated inside dpjit. Parent is set to NULL.
1422+
*
1423+
* @param nrt A Numba pointer to public api functions.
1424+
* @param event A dpctl event reference.
1425+
* @param eventstruct A Numba-dpex eventstruct object (datamodel).
1426+
* @return {return} Nothing.
1427+
*/
1428+
static int DPEXRT_sycl_event_init(NRT_api_functions *nrt,
1429+
DPCTLSyclEventRef event,
1430+
eventstruct_t *eventstruct)
1431+
{
1432+
if (eventstruct == NULL) {
1433+
DPEXRT_DEBUG(drt_debug_print(
1434+
"DPEXRT-ERROR: Failed to initialize dpctl SyclEvent into a Numba "
1435+
"eventstruct at %s, line %d. eventstruct is NULL.\n",
1436+
__FILE__, __LINE__));
1437+
1438+
return -1;
1439+
}
1440+
1441+
DPEXRT_DEBUG(
1442+
drt_debug_print("DPEXRT-DEBUG: creating new dpctl event meminfo.\n"););
1443+
eventstruct->parent = NULL;
1444+
eventstruct->event_ref = (void *)event;
1445+
// manage_memory sets ref count to 1.
1446+
eventstruct->meminfo =
1447+
nrt->manage_memory(event, NRT_MemInfo_EventRef_Delete);
1448+
1449+
return 0;
1450+
}
1451+
14191452
/*----------------------------------------------------------------------------*/
14201453
/*--------------------- The _dpexrt_python Python extension module -- -------*/
14211454
/*----------------------------------------------------------------------------*/
@@ -1456,6 +1489,7 @@ static PyObject *build_c_helpers_dict(void)
14561489
_declpointer("DPEXRT_sycl_event_from_python",
14571490
&DPEXRT_sycl_event_from_python);
14581491
_declpointer("DPEXRT_sycl_event_to_python", &DPEXRT_sycl_event_to_python);
1492+
_declpointer("DPEXRT_sycl_event_init", &DPEXRT_sycl_event_init);
14591493

14601494
#undef _declpointer
14611495
return dct;
@@ -1511,7 +1545,8 @@ MOD_INIT(_dpexrt_python)
15111545
PyLong_FromVoidPtr(&DPEXRT_sycl_event_from_python));
15121546
PyModule_AddObject(m, "DPEXRT_sycl_event_to_python",
15131547
PyLong_FromVoidPtr(&DPEXRT_sycl_event_to_python));
1514-
1548+
PyModule_AddObject(m, "DPEXRT_sycl_event_init",
1549+
PyLong_FromVoidPtr(&DPEXRT_sycl_event_init));
15151550
PyModule_AddObject(m, "DPEXRTQueue_CreateFromFilterString",
15161551
PyLong_FromVoidPtr(&DPEXRTQueue_CreateFromFilterString));
15171552
PyModule_AddObject(m, "DpexrtQueue_SubmitRange",
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-FileCopyrightText: 2020 - 2023 Intel Corporation
2+
//
3+
// SPDX-License-Identifier: Apache-2.0
4+
5+
#include "_eventstruct.h"
6+
#include "_dbg_printer.h"
7+
8+
/*!
9+
* @brief A destructor that is called from NRT on object destruction. Deletes
10+
* dpctl event reference.
11+
*
12+
* @param data A dpctl event reference.
13+
* @return {return} Nothing.
14+
*/
15+
void NRT_MemInfo_EventRef_Delete(void *data)
16+
{
17+
DPCTLSyclEventRef eref = data;
18+
19+
DPCTLEvent_Delete(eref);
20+
21+
DPEXRT_DEBUG(
22+
drt_debug_print("DPEXRT-DEBUG: deleting dpctl event reference.\n"););
23+
}

numba_dpex/core/runtime/_eventstruct.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,21 @@
99
///
1010
//===----------------------------------------------------------------------===//
1111

12-
#pragma once
12+
#ifndef _EVENTSTRUCT_H_
13+
#define _EVENTSTRUCT_H_
1314

15+
#include "_nrt_helper.h"
16+
#include "dpctl_sycl_interface.h"
1417
#include "numba/core/runtime/nrt_external.h"
18+
#include <Python.h>
1519

1620
typedef struct
1721
{
1822
NRT_MemInfo *meminfo;
23+
PyObject *parent;
1924
void *event_ref;
2025
} eventstruct_t;
26+
27+
void NRT_MemInfo_EventRef_Delete(void *data);
28+
29+
#endif /* _EVENTSTRUCT_H_ */

numba_dpex/core/runtime/context.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,24 @@ def eventstruct_to_python(self, pyapi, val):
242242

243243
return self.error
244244

245+
def eventstruct_init(self, pyapi, event, struct):
246+
"""Calls the c function DPEXRT_sycl_event_init"""
247+
248+
fnty = llvmir.FunctionType(
249+
llvmir.IntType(32), [pyapi.voidptr, pyapi.voidptr, pyapi.voidptr]
250+
)
251+
nrt_api = self._context.nrt.get_nrt_api(pyapi.builder)
252+
253+
fn = pyapi._get_function(fnty, "DPEXRT_sycl_event_init")
254+
fn.args[0].add_attribute("nocapture")
255+
fn.args[1].add_attribute("nocapture")
256+
fn.args[2].add_attribute("nocapture")
257+
258+
ptr = pyapi.builder.bitcast(struct, pyapi.voidptr)
259+
self.error = pyapi.builder.call(fn, [nrt_api, event, ptr])
260+
261+
return self.error
262+
245263
def usm_ndarray_to_python_acqref(self, pyapi, aryty, ary, dtypeptr):
246264
"""Boxes a DpnpNdArray native object into a Python dpnp.ndarray.
247265

numba_dpex/core/types/dpctl_types.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ def box_sycl_event(typ, val, c):
176176
if not c.context.enable_nrt:
177177
raise UnreachableError
178178

179-
print("boxing...")
180-
181179
dpexrtCtx = dpexrt.DpexRTContext(c.context)
182180
event = dpexrtCtx.eventstruct_to_python(c.pyapi, val)
183181

numba_dpex/dpctl_iface/_intrinsic.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,56 @@
22
#
33
# SPDX-License-Identifier: Apache-2.0
44

5+
import dpctl
6+
from llvmlite.ir import IRBuilder
57
from numba import types
8+
from numba.core import cgutils, imputils
69
from numba.core.datamodel import default_manager
7-
from numba.extending import intrinsic, overload_method
10+
from numba.extending import intrinsic, overload, overload_method, type_callable
811

912
import numba_dpex.dpctl_iface.libsyclinterface_bindings as sycl
1013
from numba_dpex.core import types as dpex_types
14+
from numba_dpex.core.runtime import context as dpexrt
15+
16+
17+
@intrinsic
18+
def sycl_event_create(
19+
ty_context,
20+
):
21+
"""A numba "intrinsic" function to inject dpctl.SyclEvent constructor code.
22+
23+
Args:
24+
ty_context (numba.core.typing.context.Context): The typing context
25+
for the codegen.
26+
27+
Returns:
28+
tuple(numba.core.typing.templates.Signature, function): A tuple of
29+
numba function signature type and a function object.
30+
"""
31+
ty_event = dpex_types.DpctlSyclEvent()
32+
33+
sig = ty_event(types.void)
34+
35+
def codegen(context, builder: IRBuilder, sig, args: list):
36+
pyapi = context.get_python_api(builder)
37+
38+
event_struct_proxy = cgutils.create_struct_proxy(ty_event)(
39+
context, builder
40+
)
41+
42+
event = sycl.dpctl_event_create(builder)
43+
dpexrtCtx = dpexrt.DpexRTContext(context)
44+
45+
# Ref count after the call is equal to 1.
46+
dpexrtCtx.eventstruct_init(
47+
pyapi, event, event_struct_proxy._getpointer()
48+
)
49+
50+
event_value = event_struct_proxy._getvalue()
51+
52+
return event_value
53+
54+
return sig, codegen
1155

1256

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

2973

74+
@overload(dpctl.SyclEvent)
75+
def ol_dpctl_sycl_event_create():
76+
"""Implementation of an overload to support dpctl.SyclEvent() inside
77+
a dpjit function.
78+
"""
79+
return lambda: sycl_event_create()
80+
81+
3082
@overload_method(dpex_types.DpctlSyclEvent, "wait")
3183
def ol_dpctl_sycl_event_wait(
3284
event,
3385
):
34-
"""Implementation of an overload to support dpctl.SyclEvent() inside
86+
"""Implementation of an overload to support dpctl.SyclEvent.wait() inside
3587
a dpjit function.
3688
"""
3789
return lambda event: sycl_event_wait(event)

numba_dpex/dpctl_iface/libsyclinterface_bindings.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ def dpctl_queue_memcpy(builder: llvmir.IRBuilder, *args):
6969
return ret
7070

7171

72+
def dpctl_event_create(builder: llvmir.IRBuilder, *args):
73+
"""Inserts LLVM IR to call DPCTLEvent_Create."""
74+
mod = builder.module
75+
fn = _build_dpctl_function(
76+
llvm_module=mod,
77+
return_ty=cgutils.voidptr_t,
78+
arg_list=[],
79+
func_name="DPCTLEvent_Create",
80+
)
81+
ret = builder.call(fn, args)
82+
83+
return ret
84+
85+
7286
def dpctl_queue_delete(builder: llvmir.IRBuilder, *args):
7387
"""Inserts LLVM IR to call DPCTLQueue_Delete."""
7488
mod = builder.module
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# SPDX-FileCopyrightText: 2020 - 2023 Intel Corporation
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
"""
6+
Tests for boxing and allocating for dpctl.SyclEvent
7+
"""
8+
9+
import sys
10+
11+
from dpctl import SyclEvent
12+
13+
from numba_dpex import dpjit
14+
15+
16+
def test_dpjit_constructor():
17+
"""Test event delete that does not have parent"""
18+
19+
@dpjit
20+
def func() -> SyclEvent:
21+
SyclEvent()
22+
return None
23+
24+
# We just want to make sure execution did not crush. There are currently
25+
# no way to check if event wast destroyed, except manual run with debug
26+
# logs on.
27+
func()
28+
29+
30+
def test_boxing_without_parent():
31+
"""Test unboxing of the event that does not have parent"""
32+
33+
@dpjit
34+
def func() -> SyclEvent:
35+
event = SyclEvent()
36+
return event
37+
38+
e: SyclEvent = func()
39+
ref_cnt = sys.getrefcount(e)
40+
41+
assert isinstance(e, SyclEvent)
42+
assert ref_cnt == 2

numba_dpex/tests/core/types/DpctlSyclQueue/test_box.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# SPDX-License-Identifier: Apache-2.0
44

55
"""
6-
Tests for boxing for dpnp.ndarray
6+
Tests for boxing for dpctl.SyclQueue
77
"""
88

99
import dpnp

0 commit comments

Comments
 (0)