Coverage for cuda / core / _event.pyx: 90.76%
119 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-22 01:37 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-22 01:37 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
7cimport cpython
8from libc.string cimport memcpy
9from cuda.bindings cimport cydriver
10from cuda.core._context cimport Context
11from cuda.core._resource_handles cimport (
12 ContextHandle,
13 EventHandle,
14 create_event_handle,
15 create_event_handle_ipc,
16 get_event_timing_enabled,
17 get_event_is_blocking_sync,
18 get_event_ipc_enabled,
19 get_event_device_id,
20 get_event_context,
21 as_intptr,
22 as_cu,
23 as_py,
24)
26from cuda.core._utils.cuda_utils cimport (
27 check_or_create_options,
28 HANDLE_RETURN
29)
31import cython
32from dataclasses import dataclass
33import multiprocessing
35from cuda.core._utils.cuda_utils import (
36 CUDAError,
37 check_multiprocessing_start_method,
38)
41@dataclass
42cdef class EventOptions:
43 """Customizable :obj:`~_event.Event` options.
45 Attributes
46 ----------
47 timing_enabled : bool, optional
48 Event will record timing data. (Default to False)
49 blocking_sync : bool, optional
50 If True, the event uses blocking synchronization: a CPU
51 thread that calls :meth:`Event.sync` blocks (yields) until
52 the event has completed. Otherwise (the default), the CPU
53 thread busy-waits until the event has completed.
54 (Default to False)
55 ipc_enabled : bool, optional
56 Event will be suitable for interprocess use.
57 Note that timing_enabled must be False. (Default to False)
59 """
61 timing_enabled: bool | None = False
62 blocking_sync: bool | None = False
63 ipc_enabled: bool | None = False
66cdef class Event:
67 """Represent a record at a specific point of execution within a CUDA stream.
69 Applications can asynchronously record events at any point in
70 the program. An event keeps a record of all previous work within
71 the last recorded stream.
73 Events can be used to monitor device's progress, query completion
74 of work up to event's record, help establish dependencies
75 between GPU work submissions, and record the elapsed time (in milliseconds)
76 on GPU:
78 .. code-block:: python
80 # To create events and record the timing:
81 s = Device().create_stream()
82 e1 = Device().create_event({"timing_enabled": True})
83 e2 = Device().create_event({"timing_enabled": True})
84 s.record(e1)
85 # ... run some GPU works ...
86 s.record(e2)
87 e2.sync()
88 print(f"time = {e2 - e1} milliseconds")
90 Directly creating an :obj:`~_event.Event` is not supported due to ambiguity,
91 and they should instead be created through a :obj:`~_stream.Stream` object.
93 """
95 def __init__(self, *args, **kwargs):
96 raise RuntimeError("Event objects cannot be instantiated directly. Please use Stream APIs (record).") 2bd
98 @staticmethod
99 cdef Event _init(type cls, int device_id, ContextHandle h_context, options, bint is_free):
100 cdef Event self = cls.__new__(cls) 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
101 cdef EventOptions opts = check_or_create_options(EventOptions, options, "Event options") 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
102 cdef unsigned int flags = 0x0 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
103 cdef bint timing_enabled = True 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
104 cdef bint is_blocking_sync = False 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
105 cdef bint ipc_enabled = False 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
106 self._ipc_descriptor = None 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
107 if not opts.timing_enabled: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
108 flags |= cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbs UbVbt q Wb| i j e a f b g c h d n } r A XbB ~ I abC J D w bbcbdbM K E x y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
109 timing_enabled = False 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbs UbVbt q Wb| i j e a f b g c h d n } r A XbB ~ I abC J D w bbcbdbM K E x y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
110 if opts.blocking_sync: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
111 flags |= cydriver.CUevent_flags.CU_EVENT_BLOCKING_SYNC 1poabcdK
112 is_blocking_sync = True 1poabcdK
113 if opts.ipc_enabled: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
114 if is_free: 2i j e a f b g c h d n =c?ck l m
115 raise TypeError( 1#n
116 "IPC-enabled events must be bound; use Stream.record for creation."
117 )
118 flags |= cydriver.CUevent_flags.CU_EVENT_INTERPROCESS 2i j e a f b g c h d n =c?ck l m
119 ipc_enabled = True 2i j e a f b g c h d n =c?ck l m
120 if timing_enabled: 2i j e a f b g c h d n =c?ck l m
121 raise TypeError("IPC-enabled events cannot use timing.") 2=c?c
122 cdef EventHandle h_event = create_event_handle( 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
123 h_context, flags, timing_enabled, is_blocking_sync, ipc_enabled, device_id)
124 if not h_event: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
125 raise RuntimeError("Failed to create CUDA event")
126 self._h_event = h_event 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
127 if ipc_enabled: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
128 _ = self.ipc_descriptor # eagerly populate the descriptor cache 1ijeafbgchdnklm
129 return self 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v A XbB ~ I abC J D w bbcbdbM K E x F y k z YbZbeb0b1b2b3b4b5b6b7b8b9b!b#bfb$b%b'b(bgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBb)b*b+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcN wcxcyczcO P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c! 3c4cl m Eb5c6cL 7c8cFb9c!cGb#c$cG %c'cH (c)c*c+c,c-c.c/c:c;c
131 @staticmethod
132 cdef Event _from_handle(EventHandle h_event):
133 """Create an Event wrapping an existing EventHandle.
135 Metadata (timing, blocking_sync, ipc, device_id) is read from
136 the EventBox via pointer arithmetic — no fields are cached on
137 Event.
138 """
139 cdef Event self = Event.__new__(Event) 2@c[c]c^cp s o t q
140 self._h_event = h_event 2@c[c]c^cp s o t q
141 self._ipc_descriptor = None 2@c[c]c^cp s o t q
142 return self 2@c[c]c^cp s o t q
144 cpdef close(self):
145 """Destroy the event.
147 Releases the event handle. The underlying CUDA event is destroyed
148 when the last reference is released.
149 """
150 self._h_event.reset() 1$%'()*+,-./:;=?@[]^_`{|k
152 def __isub__(self, other):
153 return NotImplemented 2bb
155 def __rsub__(self, other):
156 return NotImplemented 2cb
158 def __sub__(self, other: Event):
159 # return self - other (in milliseconds)
160 cdef float timing
161 with nogil: 1ruvF
162 err = cydriver.cuEventElapsedTime(&timing, as_cu((<Event>other)._h_event), as_cu(self._h_event)) 1ruvF
163 if err == 0: 1ruvF
164 return timing 1uF
165 else:
166 if err == cydriver.CUresult.CUDA_ERROR_INVALID_HANDLE: 1ruv
167 if not self.is_timing_enabled or not other.is_timing_enabled: 1rv
168 explanation = (
169 "Both Events must be created with timing enabled in order to subtract them; " 1r
170 "use EventOptions(timing_enabled=True) when creating both events."
171 )
172 else:
173 explanation = (
174 "Both Events must be recorded before they can be subtracted; " 1v
175 "use Stream.record() to record both events to a stream."
176 )
177 elif err == cydriver.CUresult.CUDA_ERROR_NOT_READY: 1ruv
178 explanation = (
179 "One or both events have not completed; " 1u
180 "use Event.sync(), Stream.sync(), or Device.sync() to wait for the events to complete "
181 "before subtracting them."
182 )
183 else:
184 raise CUDAError(err)
185 raise RuntimeError(explanation) 1ruv
187 def __hash__(self) -> int:
188 return hash(as_intptr(self._h_event)) 2~ abC dbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbFbGbG H
190 def __eq__(self, other) -> bool:
191 # Note: using isinstance because `Event` can be subclassed.
192 if not isinstance(other, Event): 2@c[c]c^cI C J M z N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! L G H
193 return NotImplemented 1MzNOPQRSTUVWXYZ0123456789!
194 cdef Event _other = <Event>other 2@c[c]c^cI C J z L G H
195 return as_intptr(self._h_event) == as_intptr(_other._h_event) 2@c[c]c^cI C J z L G H
197 def __repr__(self) -> str:
198 return f"<Event handle={as_intptr(self._h_event):#x}>" 2i j e a f b g c h d Eb
200 @property
201 def ipc_descriptor(self) -> IPCEventDescriptor:
202 """Descriptor for sharing this event with other processes."""
203 if self._ipc_descriptor is not None: 1ijeafbgchdnDklm
204 return self._ipc_descriptor 1ijeafbgchdklm
205 if not self.is_ipc_enabled: 1ijeafbgchdnDklm
206 raise RuntimeError("Event is not IPC-enabled") 1D
207 cdef cydriver.CUipcEventHandle data
208 with nogil: 1ijeafbgchdnklm
209 HANDLE_RETURN(cydriver.cuIpcGetEventHandle(&data, as_cu(self._h_event))) 1ijeafbgchdnklm
210 cdef bytes data_b = cpython.PyBytes_FromStringAndSize(<char*>(data.reserved), sizeof(data.reserved)) 1ijeafbgchdnklm
211 self._ipc_descriptor = IPCEventDescriptor._init(data_b, get_event_is_blocking_sync(self._h_event)) 1ijeafbgchdnklm
212 return self._ipc_descriptor 1ijeafbgchdnklm
214 @classmethod
215 def from_ipc_descriptor(cls, ipc_descriptor: IPCEventDescriptor) -> Event:
216 """Import an event that was exported from another process.
218 Parameters
219 ----------
220 ipc_descriptor : :obj:`~_memory._ipc.IPCEventDescriptor`
221 The IPC descriptor obtained from :attr:`~Event.ipc_descriptor` in
222 another process.
224 Returns
225 -------
226 :obj:`~_event.Event`
227 A new event backed by the imported IPC handle.
229 """
230 cdef cydriver.CUipcEventHandle data
231 memcpy(data.reserved, <const void*><const char*>(ipc_descriptor._reserved), sizeof(data.reserved))
232 cdef Event self = Event.__new__(cls)
233 cdef EventHandle h_event = create_event_handle_ipc(data, ipc_descriptor._is_blocking_sync)
234 if not h_event:
235 raise RuntimeError("Failed to open IPC event handle")
236 self._h_event = h_event
237 self._ipc_descriptor = ipc_descriptor
238 return self
240 @property
241 def is_ipc_enabled(self) -> bool:
242 """Return True if the event can be shared across process boundaries, otherwise False."""
243 return get_event_ipc_enabled(self._h_event) 1oijeafbgchdnDklm
245 @property
246 def is_timing_enabled(self) -> bool:
247 """Return True if the event records timing data, otherwise False."""
248 return get_event_timing_enabled(self._h_event) 1poqeafbgchdrv
250 @property
251 def is_blocking_sync(self) -> bool:
252 """Return True if the event uses blocking synchronization (the CPU
253 thread blocks on :meth:`sync` instead of busy-waiting), otherwise False.
254 """
255 return get_event_is_blocking_sync(self._h_event) 1poqeafbgchdK
257 def sync(self):
258 """Synchronize until the event completes.
260 If the event was created with ``blocking_sync=True``, the
261 calling CPU thread blocks (yields) until the event has been
262 completed by the device. Otherwise (the default) the CPU
263 thread busy-waits until the event has completed.
265 """
266 with nogil: 1uwxFy
267 HANDLE_RETURN(cydriver.cuEventSynchronize(as_cu(self._h_event))) 1uwxFy
269 @property
270 def is_done(self) -> bool:
271 """Return True if all captured works have been completed, otherwise False."""
272 with nogil: 1pstwEx
273 result = cydriver.cuEventQuery(as_cu(self._h_event)) 1pstwEx
274 if result == cydriver.CUresult.CUDA_SUCCESS: 1pstwEx
275 return True 1pstEx
276 if result == cydriver.CUresult.CUDA_ERROR_NOT_READY: 1w
277 return False 1w
278 HANDLE_RETURN(result)
280 @property
281 def handle(self) -> cuda.bindings.driver.CUevent:
282 """Return the underlying CUevent object.
284 .. caution::
286 This handle is a Python object. To get the memory address of the underlying C
287 handle, call ``int(Event.handle)``.
288 """
289 return as_py(self._h_event) 1ij}z
291 @property
292 def device(self) -> Device:
293 """Return the :obj:`~_device.Device` singleton associated with this event.
295 Note
296 ----
297 The current context on the device may differ from this
298 event's context. This case occurs when a different CUDA
299 context is set current after a event is created.
301 """
302 cdef int dev_id = get_event_device_id(self._h_event) 1oqB
303 if dev_id >= 0: 1oqB
304 from ._device import Device # avoid circular import 1oqB
305 return Device(dev_id) 1oqB
307 @property
308 def context(self) -> Context:
309 """Return the :obj:`~_context.Context` associated with this event."""
310 cdef ContextHandle h_ctx = get_event_context(self._h_event) 1Ay
311 cdef int dev_id = get_event_device_id(self._h_event) 1Ay
312 if h_ctx and dev_id >= 0: 1Ay
313 return Context._from_handle(Context, h_ctx, dev_id) 1Ay
316cdef class IPCEventDescriptor:
317 """Serializable object describing an event that can be shared between processes."""
319 cdef:
320 bytes _reserved
321 bint _is_blocking_sync
323 def __init__(self, *arg, **kwargs):
324 raise RuntimeError("IPCEventDescriptor objects cannot be instantiated directly. Please use Event APIs.") 2cd
326 @staticmethod
327 def _init(reserved: bytes, is_blocking_sync: cython.bint):
328 cdef IPCEventDescriptor self = IPCEventDescriptor.__new__(IPCEventDescriptor) 2i j e a f b g c h d n _c`c{c|c}c~cadk l m
329 self._reserved = reserved 2i j e a f b g c h d n _c`c{c|c}c~cadk l m
330 self._is_blocking_sync = is_blocking_sync 2i j e a f b g c h d n _c`c{c|c}c~cadk l m
331 return self 2i j e a f b g c h d n _c`c{c|c}c~cadk l m
333 def __eq__(self, other) -> bool:
334 if not isinstance(other, IPCEventDescriptor): 2e a f b g c h d _c`c{c|c}c~cad
335 return NotImplemented 2_c`c{c|c}c~c
336 # No need to check self._is_blocking_sync.
337 return self._reserved == (<IPCEventDescriptor>other)._reserved 2e a f b g c h d ad
339 def __reduce__(self):
340 return IPCEventDescriptor._init, (self._reserved, self._is_blocking_sync) 1ijeafbgchdlm
343def _reduce_event(event):
344 check_multiprocessing_start_method() 1ijeafbgchdk
345 return event.from_ipc_descriptor, (event.ipc_descriptor,) 1ijeafbgchdk
347multiprocessing.reduction.register(Event, _reduce_event)