Coverage for cuda/core/_event.pyx: 89.34%

122 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-13 01:38 +0000

1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 

2# 

3# SPDX-License-Identifier: Apache-2.0 

4  

5from __future__ import annotations 

6  

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) 

25  

26from cuda.core._utils.cuda_utils cimport ( 

27 check_or_create_options, 

28 HANDLE_RETURN 

29) 

30  

31import cython 

32from dataclasses import dataclass 

33import multiprocessing 

34from typing import TYPE_CHECKING 

35  

36from cuda.core._utils.cuda_utils import ( 

37 CUDAError, 

38 check_multiprocessing_start_method, 

39) 

40  

41if TYPE_CHECKING: 

42 import cuda.bindings.driver # no-cython-lint 

43 from cuda.core._device import Device 

44  

45  

46@dataclass 

47cdef class EventOptions: 

48 """Customizable :obj:`~_event.Event` options. 

49  

50 Attributes 

51 ---------- 

52 timing_enabled : bool, optional 

53 Event will record timing data. (Default to False) 

54 blocking_sync : bool, optional 

55 If True, the event uses blocking synchronization: a CPU 

56 thread that calls :meth:`Event.sync` blocks (yields) until 

57 the event has completed. Otherwise (the default), the CPU 

58 thread busy-waits until the event has completed. 

59 (Default to False) 

60 ipc_enabled : bool, optional 

61 Event will be suitable for interprocess use. 

62 Note that timing_enabled must be False. (Default to False) 

63  

64 """ 

65  

66 timing_enabled: bool | None = False 

67 blocking_sync: bool | None = False 

68 ipc_enabled: bool | None = False 

69  

70  

71cdef class Event: 

72 """Represent a record at a specific point of execution within a CUDA stream. 

73  

74 Applications can asynchronously record events at any point in 

75 the program. An event keeps a record of all previous work within 

76 the last recorded stream. 

77  

78 Events can be used to monitor device's progress, query completion 

79 of work up to event's record, help establish dependencies 

80 between GPU work submissions, and record the elapsed time (in milliseconds) 

81 on GPU: 

82  

83 .. code-block:: python 

84  

85 # To create events and record the timing: 

86 s = Device().create_stream() 

87 e1 = Device().create_event({"timing_enabled": True}) 

88 e2 = Device().create_event({"timing_enabled": True}) 

89 s.record(e1) 

90 # ... run some GPU works ... 

91 s.record(e2) 

92 e2.sync() 

93 print(f"time = {e2 - e1} milliseconds") 

94  

95 Directly creating an :obj:`~_event.Event` is not supported due to ambiguity, 

96 and they should instead be created through a :obj:`~_stream.Stream` object. 

97  

98 """ 

99  

100 def __init__(self, *args, **kwargs) -> None: 

101 raise RuntimeError("Event objects cannot be instantiated directly. Please use Stream APIs (record).") 2bd

102  

103 @staticmethod 

104 cdef Event _init(type cls, int device_id, ContextHandle h_context, options, bint is_free): 

105 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

106 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

107 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

108 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

109 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

110 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

111 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

112 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

113 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 B XbC ~ J abD K E w bbcbdbN L F 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

114 timing_enabled = False 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbs UbVbt q Wb| i j e a f b g c h d n } r B XbC ~ J abD K E w bbcbdbN L F 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

115 if opts.blocking_sync: 2A $ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n =c?c} r u v B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

116 flags |= cydriver.CUevent_flags.CU_EVENT_BLOCKING_SYNC 1poabcdL

117 is_blocking_sync = True 1poabcdL

118 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

119 if is_free: 2i j e a f b g c h d n =c?ck l m

120 raise TypeError( 1n

121 "IPC-enabled events must be bound; use Stream.record for creation." 

122 ) 

123 flags |= cydriver.CUevent_flags.CU_EVENT_INTERPROCESS 2i j e a f b g c h d n =c?ck l m

124 ipc_enabled = True 2i j e a f b g c h d n =c?ck l m

125 if timing_enabled: 2i j e a f b g c h d n =c?ck l m

126 raise TypeError("IPC-enabled events cannot use timing.") 2=c?c

127 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

128 h_context, flags, timing_enabled, is_blocking_sync, ipc_enabled, device_id) 

129 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

130 raise RuntimeError("Failed to create CUDA event") 

131 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 B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

132 if ipc_enabled: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

133 _ = self.ipc_descriptor # eagerly populate the descriptor cache 1Aijeafbgchdnklm

134 return self 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { HbIbJbKbLbMbNbObPbQbRbSbTbp s o UbVbt q Wb| i j e a f b g c h d n } r u v B XbC ~ J abD K E w bbcbdbN L F x G 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~bacbcccdcecfcgchcCbicjcDbkclcmcncocpcqcrcsctcucvcO wcxcyczcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! AcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c# 3c4cl m Eb5c6cM 7c8cFb9c!cGb#c$cH %c'cI (c)c*c+c,c-c.c/c:c;c

135  

136 @staticmethod 

137 cdef Event _from_handle(EventHandle h_event): 

138 """Create an Event wrapping an existing EventHandle. 

139  

140 Metadata (timing, blocking_sync, ipc, device_id) is read from 

141 the EventBox via pointer arithmetic — no fields are cached on 

142 Event. 

143 """ 

144 cdef Event self = Event.__new__(Event) 2@c[c]c^cp s o t q

145 self._h_event = h_event 2@c[c]c^cp s o t q

146 self._ipc_descriptor = None 2@c[c]c^cp s o t q

147 return self 2@c[c]c^cp s o t q

148  

149 cpdef close(self): 

150 """Destroy the event. 

151  

152 Releases the event handle. The underlying CUDA event is destroyed 

153 when the last reference is released. 

154 """ 

155 self._h_event.reset() 1$%'()*+,-./:;=?@[]^_`{|k

156  

157 def __isub__(self, other: object): 

158 return NotImplemented 2bb

159  

160 def __rsub__(self, other: object): 

161 return NotImplemented 2cb

162  

163 def __sub__(self, other: Event) -> float: 

164 # return self - other (in milliseconds) 

165 cdef float timing 

166 with nogil: 1ruvG

167 err = cydriver.cuEventElapsedTime(&timing, as_cu((<Event>other)._h_event), as_cu(self._h_event)) 1ruvG

168 if err == 0: 1ruvG

169 return timing 1uG

170 else: 

171 if err == cydriver.CUresult.CUDA_ERROR_INVALID_HANDLE: 1ruv

172 if not self.is_timing_enabled or not other.is_timing_enabled: 1rv

173 explanation = ( 

174 "Both Events must be created with timing enabled in order to subtract them; " 1r

175 "use EventOptions(timing_enabled=True) when creating both events." 

176 ) 

177 else: 

178 explanation = ( 

179 "Both Events must be recorded before they can be subtracted; " 1v

180 "use Stream.record() to record both events to a stream." 

181 ) 

182 elif err == cydriver.CUresult.CUDA_ERROR_NOT_READY: 1ruv

183 explanation = ( 

184 "One or both events have not completed; " 1u

185 "use Event.sync(), Stream.sync(), or Device.sync() to wait for the events to complete " 

186 "before subtracting them." 

187 ) 

188 else: 

189 raise CUDAError(err) 

190 raise RuntimeError(explanation) 1ruv

191  

192 def __hash__(self) -> int: 

193 return hash(as_intptr(self._h_event)) 2~ abD dbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbFbGbH I

194  

195 def __eq__(self, other: object) -> bool: 

196 # Note: using isinstance because `Event` can be subclassed. 

197 if not isinstance(other, Event): 2@c[c]c^cJ D K N z O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! # M H I

198 return NotImplemented 1NzOPQRSTUVWXYZ0123456789!#

199 cdef Event _other = <Event>other 2@c[c]c^cJ D K z M H I

200 return as_intptr(self._h_event) == as_intptr(_other._h_event) 2@c[c]c^cJ D K z M H I

201  

202 def __repr__(self) -> str: 

203 return f"<Event handle={as_intptr(self._h_event):#x}>" 2i j e a f b g c h d Eb

204  

205 @property 

206 def ipc_descriptor(self) -> IPCEventDescriptor: 

207 """Descriptor for sharing this event with other processes.""" 

208 if self._ipc_descriptor is not None: 1ijeafbgchdnEklm

209 return self._ipc_descriptor 1ijeafbgchdklm

210 if not self.is_ipc_enabled: 1ijeafbgchdnEklm

211 raise RuntimeError("Event is not IPC-enabled") 1E

212 cdef cydriver.CUipcEventHandle data 

213 with nogil: 1ijeafbgchdnklm

214 HANDLE_RETURN(cydriver.cuIpcGetEventHandle(&data, as_cu(self._h_event))) 1ijeafbgchdnklm

215 cdef bytes data_b = cpython.PyBytes_FromStringAndSize(<char*>(data.reserved), sizeof(data.reserved)) 1ijeafbgchdnklm

216 self._ipc_descriptor = IPCEventDescriptor._init(data_b, get_event_is_blocking_sync(self._h_event)) 1ijeafbgchdnklm

217 return self._ipc_descriptor 1ijeafbgchdnklm

218  

219 @classmethod 

220 def from_ipc_descriptor(cls, ipc_descriptor: IPCEventDescriptor) -> Event: 

221 """Import an event that was exported from another process. 

222  

223 Parameters 

224 ---------- 

225 ipc_descriptor : :obj:`~_memory._ipc.IPCEventDescriptor` 

226 The IPC descriptor obtained from :attr:`~Event.ipc_descriptor` in 

227 another process. 

228  

229 Returns 

230 ------- 

231 :obj:`~_event.Event` 

232 A new event backed by the imported IPC handle. 

233  

234 """ 

235 cdef cydriver.CUipcEventHandle data 

236 memcpy(data.reserved, <const void*><const char*>(ipc_descriptor._reserved), sizeof(data.reserved)) 

237 cdef Event self = Event.__new__(cls) 

238 cdef EventHandle h_event = create_event_handle_ipc(data, ipc_descriptor._is_blocking_sync) 

239 if not h_event: 

240 raise RuntimeError("Failed to open IPC event handle") 

241 self._h_event = h_event 

242 self._ipc_descriptor = ipc_descriptor 

243 return self 

244  

245 @property 

246 def is_ipc_enabled(self) -> bool: 

247 """Return True if the event can be shared across process boundaries, otherwise False.""" 

248 return get_event_ipc_enabled(self._h_event) 1oijeafbgchdnEklm

249  

250 @property 

251 def is_timing_enabled(self) -> bool: 

252 """Return True if the event records timing data, otherwise False.""" 

253 return get_event_timing_enabled(self._h_event) 1poqeafbgchdrv

254  

255 @property 

256 def is_blocking_sync(self) -> bool: 

257 """Return True if the event uses blocking synchronization (the CPU 

258 thread blocks on :meth:`sync` instead of busy-waiting), otherwise False. 

259 """ 

260 return get_event_is_blocking_sync(self._h_event) 1poqeafbgchdL

261  

262 def sync(self) -> None: 

263 """Synchronize until the event completes. 

264  

265 If the event was created with ``blocking_sync=True``, the 

266 calling CPU thread blocks (yields) until the event has been 

267 completed by the device. Otherwise (the default) the CPU 

268 thread busy-waits until the event has completed. 

269  

270 """ 

271 with nogil: 1uwxGy

272 HANDLE_RETURN(cydriver.cuEventSynchronize(as_cu(self._h_event))) 1uwxGy

273  

274 @property 

275 def is_done(self) -> bool: 

276 """Return True if all captured works have been completed, otherwise False.""" 

277 with nogil: 1pstwFx

278 result = cydriver.cuEventQuery(as_cu(self._h_event)) 1pstwFx

279 if result == cydriver.CUresult.CUDA_SUCCESS: 1pstwFx

280 return True 1pstFx

281 if result == cydriver.CUresult.CUDA_ERROR_NOT_READY: 1w

282 return False 1w

283 HANDLE_RETURN(result) 

284  

285 @property 

286 def handle(self) -> cuda.bindings.driver.CUevent: 

287 """Return the underlying CUevent object. 

288  

289 .. caution:: 

290  

291 This handle is a Python object. To get the memory address of the underlying C 

292 handle, call ``int(Event.handle)``. 

293 """ 

294 return as_py(self._h_event) 1ij}z

295  

296 @property 

297 def device(self) -> Device: 

298 """Return the :obj:`~_device.Device` singleton associated with this event. 

299  

300 Note 

301 ---- 

302 The current context on the device may differ from this 

303 event's context. This case occurs when a different CUDA 

304 context is set current after a event is created. 

305  

306 """ 

307 cdef int dev_id = get_event_device_id(self._h_event) 1oqC

308 if dev_id >= 0: 1oqC

309 from ._device import Device # avoid circular import 1oqC

310 return Device(dev_id) 1oqC

311  

312 @property 

313 def context(self) -> Context: 

314 """Return the :obj:`~_context.Context` associated with this event.""" 

315 cdef ContextHandle h_ctx = get_event_context(self._h_event) 1By

316 cdef int dev_id = get_event_device_id(self._h_event) 1By

317 if h_ctx and dev_id >= 0: 1By

318 return Context._from_handle(Context, h_ctx, dev_id) 1By

319  

320  

321cdef class IPCEventDescriptor: 

322 """Serializable object describing an event that can be shared between processes.""" 

323  

324 cdef: 

325 bytes _reserved 

326 bint _is_blocking_sync 

327  

328 def __init__(self, *arg, **kwargs) -> None: 

329 raise RuntimeError("IPCEventDescriptor objects cannot be instantiated directly. Please use Event APIs.") 2cd

330  

331 @staticmethod 

332 def _init(reserved: bytes, is_blocking_sync: cython.bint) -> IPCEventDescriptor: 

333 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

334 self._reserved = reserved 2i j e a f b g c h d n _c`c{c|c}c~cadk l m

335 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

336 return self 2i j e a f b g c h d n _c`c{c|c}c~cadk l m

337  

338 def __eq__(self, other: object) -> bool: 

339 if not isinstance(other, IPCEventDescriptor): 2e a f b g c h d _c`c{c|c}c~cad

340 return NotImplemented 2_c`c{c|c}c~c

341 # No need to check self._is_blocking_sync. 

342 return self._reserved == (<IPCEventDescriptor>other)._reserved 2e a f b g c h d ad

343  

344 def __reduce__(self) -> tuple[object, ...]: 

345 return IPCEventDescriptor._init, (self._reserved, self._is_blocking_sync) 1ijeafbgchdlm

346  

347  

348def _reduce_event(event: Event) -> tuple[object, ...]: 

349 check_multiprocessing_start_method() 1ijeafbgchdk

350 return event.from_ipc_descriptor, (event.ipc_descriptor,) 1ijeafbgchdk

351  

352multiprocessing.reduction.register(Event, _reduce_event)