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

128 statements  

« prev     ^ index     » next       coverage.py v7.15.0, created at 2026-07-03 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.stddef cimport size_t 

9from libc.string cimport memcpy 

10from cuda.bindings cimport cydriver 

11from cuda.core._context cimport Context 

12from cuda.core._resource_handles cimport ( 

13 ContextHandle, 

14 EventHandle, 

15 create_event_handle, 

16 create_event_handle_ipc, 

17 get_event_timing_enabled, 

18 get_event_is_blocking_sync, 

19 get_event_ipc_enabled, 

20 get_event_device_id, 

21 get_event_context, 

22 as_intptr, 

23 as_cu, 

24 as_py, 

25) 

26  

27from cuda.core._utils.cuda_utils cimport ( 

28 check_or_create_options, 

29 HANDLE_RETURN 

30) 

31  

32import cython 

33from dataclasses import dataclass 

34import multiprocessing 

35from typing import TYPE_CHECKING 

36  

37from cuda.core._utils.cuda_utils import ( 

38 CUDAError, 

39 check_multiprocessing_start_method, 

40) 

41  

42if TYPE_CHECKING: 

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

44 from cuda.core._device import Device 

45  

46  

47@dataclass 

48cdef class EventOptions: 

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

50  

51 Attributes 

52 ---------- 

53 timing_enabled : bool, optional 

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

55 blocking_sync : bool, optional 

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

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

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

59 thread busy-waits until the event has completed. 

60 (Default to False) 

61 ipc_enabled : bool, optional 

62 Event will be suitable for interprocess use. 

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

64  

65 """ 

66  

67 timing_enabled: bool | None = False 

68 blocking_sync: bool | None = False 

69 ipc_enabled: bool | None = False 

70  

71  

72cdef class Event: 

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

74  

75 Applications can asynchronously record events at any point in 

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

77 the last recorded stream. 

78  

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

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

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

82 on GPU: 

83  

84 .. code-block:: python 

85  

86 # To create events and record the timing: 

87 s = Device().create_stream() 

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

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

90 s.record(e1) 

91 # ... run some GPU works ... 

92 s.record(e2) 

93 e2.sync() 

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

95  

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

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

98  

99 """ 

100  

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

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

103  

104 @staticmethod 

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

106 cdef Event self = cls.__new__(cls) 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

107 cdef EventOptions opts = check_or_create_options(EventOptions, options, "Event options") 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

108 cdef unsigned int flags = 0x0 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

109 cdef bint timing_enabled = True 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

110 cdef bint is_blocking_sync = False 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

111 cdef bint ipc_enabled = False 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

112 self._ipc_descriptor = None 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

113 if not opts.timing_enabled: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

114 flags |= cydriver.CUevent_flags.CU_EVENT_DISABLE_TIMING 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbs WbXbt q Yb~ i j e a f b g c h d n abr B ZbC bbJ cbD K E w dbebfbN L F x y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

115 timing_enabled = False 2A $ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbs WbXbt q Yb~ i j e a f b g c h d n abr B ZbC bbJ cbD K E w dbebfbN L F x y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

116 if opts.blocking_sync: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

117 flags |= cydriver.CUevent_flags.CU_EVENT_BLOCKING_SYNC 1poabcdL

118 is_blocking_sync = True 1poabcdL

119 if opts.ipc_enabled: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n @c[cabr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

120 if is_free: 2i j e a f b g c h d n @c[ck l m

121 raise TypeError( 1n

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

123 ) 

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

125 ipc_enabled = True 2i j e a f b g c h d n @c[ck l m

126 if timing_enabled: 2i j e a f b g c h d n @c[ck l m

127 raise TypeError("IPC-enabled events cannot use timing.") 2@c[c

128 cdef EventHandle h_event = create_event_handle( 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n abr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

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

130 if not h_event: 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n abr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

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

132 self._h_event = h_event 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n abr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

133 if ipc_enabled: 2A $ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n abr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

134 _ = self.ipc_descriptor # eagerly populate the descriptor cache 1ijeafbgchdnklm

135 return self 2$ % ' ( ) * + , - . / : ; = ? @ [ ] ^ _ ` { | } JbKbLbMbNbObPbQbRbSbTbUbVbp s o WbXbt q Yb~ i j e a f b g c h d n abr u v B ZbC bbJ cbD K E w dbebfbN L F x G y k z 0b1bgb2b3b4b5b6b7b8b9b!b#b$b%bhb'b(b)b*bibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDb+b,b-b.b/b:b;b=b?b@b[b]b^b_b`b{b|b}b~bacbcccdcecfcgchcicjcEbkclcFbmcncocpcqcrcsctcucvcwcxcO yczcAcBcP Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 ! CcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c# 5c6cl m Gb7c8cM 9c!cHb#c$cIb%c'cH (c)cI *c+c,c-c.c/c:c;c=c?c

136  

137 @staticmethod 

138 cdef Event _from_handle(EventHandle h_event): 

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

140  

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

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

143 Event. 

144 """ 

145 cdef Event self = Event.__new__(Event) 2^c_c`c{cp s o t q

146 self._h_event = h_event 2^c_c`c{cp s o t q

147 self._ipc_descriptor = None 2^c_c`c{cp s o t q

148 return self 2^c_c`c{cp s o t q

149  

150 cpdef close(self): 

151 """Destroy the event. 

152  

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

154 when the last reference is released. 

155 """ 

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

157  

158 def __isub__(self, other: object): 

159 return NotImplemented 2db

160  

161 def __rsub__(self, other: object): 

162 return NotImplemented 2eb

163  

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

165 # return self - other (in milliseconds) 

166 cdef float timing 

167 with nogil: 1ruvG

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

169 if err == 0: 1ruvG

170 return timing 1uG

171 else: 

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

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

174 explanation = ( 

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

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

177 ) 

178 else: 

179 explanation = ( 

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

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

182 ) 

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

184 explanation = ( 

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

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

187 "before subtracting them." 

188 ) 

189 else: 

190 raise CUDAError(err) 

191 raise RuntimeError(explanation) 1ruv

192  

193 def __hash__(self) -> int: 

194 return hash(as_intptr(self._h_event)) 2bbcbD fbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbHbIbH I

195  

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

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

198 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

199 return NotImplemented 1NzOPQRSTUVWXYZ0123456789!#

200 cdef Event _other = <Event>other 2^c_c`c{cJ D K z M H I

201 return as_intptr(self._h_event) == as_intptr(_other._h_event) 2^c_c`c{cJ D K z M H I

202  

203 def __repr__(self) -> str: 

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

205  

206 @property 

207 def ipc_descriptor(self) -> IPCEventDescriptor: 

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

209 if self._ipc_descriptor is not None: 1ijeafbgchdnEklm

210 return self._ipc_descriptor 1ijeafbgchdklm

211 if not self.is_ipc_enabled: 1ijeafbgchdnEklm

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

213 cdef cydriver.CUipcEventHandle data 

214 with nogil: 1ijeafbgchdnklm

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

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

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

218 return self._ipc_descriptor 1ijeafbgchdnklm

219  

220 @classmethod 

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

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

223  

224 Parameters 

225 ---------- 

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

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

228 another process. 

229  

230 Returns 

231 ------- 

232 :obj:`~_event.Event` 

233 A new event backed by the imported IPC handle. 

234  

235 """ 

236 cdef size_t reserved_size = len(ipc_descriptor._reserved) 2]c

237 cdef size_t expected_size = sizeof(cydriver.CUipcEventHandle) 2]c

238 if reserved_size < expected_size: 2]c

239 raise ValueError( 2]c

240 f"IPC event descriptor reserved field is {reserved_size} bytes; " 2]c

241 f"expected at least {expected_size}" 2]c

242 ) 

243 cdef cydriver.CUipcEventHandle data 

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

245 cdef Event self = Event.__new__(cls) 

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

247 if not h_event: 

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

249 self._h_event = h_event 

250 self._ipc_descriptor = ipc_descriptor 

251 return self 

252  

253 @property 

254 def is_ipc_enabled(self) -> bool: 

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

256 return get_event_ipc_enabled(self._h_event) 1oijeafbgchdnEklm

257  

258 @property 

259 def is_timing_enabled(self) -> bool: 

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

261 return get_event_timing_enabled(self._h_event) 1poqeafbgchdrv

262  

263 @property 

264 def is_blocking_sync(self) -> bool: 

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

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

267 """ 

268 return get_event_is_blocking_sync(self._h_event) 1poqeafbgchdL

269  

270 def sync(self) -> None: 

271 """Synchronize until the event completes. 

272  

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

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

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

276 thread busy-waits until the event has completed. 

277  

278 """ 

279 with nogil: 1uwxGy

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

281  

282 @property 

283 def is_done(self) -> bool: 

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

285 with nogil: 1pstwFx

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

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

288 return True 1pstFx

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

290 return False 1w

291 HANDLE_RETURN(result) 

292  

293 @property 

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

295 """Return the underlying CUevent object. 

296  

297 .. caution:: 

298  

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

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

301 """ 

302 return as_py(self._h_event) 2i j abz

303  

304 @property 

305 def device(self) -> Device: 

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

307  

308 Note 

309 ---- 

310 The current context on the device may differ from this 

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

312 context is set current after a event is created. 

313  

314 """ 

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

316 if dev_id >= 0: 1oqC

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

318 return Device(dev_id) 1oqC

319  

320 @property 

321 def context(self) -> Context: 

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

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

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

325 if h_ctx and dev_id >= 0: 1By

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

327  

328  

329cdef class IPCEventDescriptor: 

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

331  

332 cdef: 

333 bytes _reserved 

334 bint _is_blocking_sync 

335  

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

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

338  

339 @staticmethod 

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

341 cdef IPCEventDescriptor self = IPCEventDescriptor.__new__(IPCEventDescriptor) 2i j e a f b g c h d n ]c|c}c~cadbdcdddk l m

342 self._reserved = reserved 2i j e a f b g c h d n ]c|c}c~cadbdcdddk l m

343 self._is_blocking_sync = is_blocking_sync 2i j e a f b g c h d n ]c|c}c~cadbdcdddk l m

344 return self 2i j e a f b g c h d n ]c|c}c~cadbdcdddk l m

345  

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

347 if not isinstance(other, IPCEventDescriptor): 2e a f b g c h d |c}c~cadbdcddd

348 return NotImplemented 2|c}c~cadbdcd

349 # No need to check self._is_blocking_sync. 

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

351  

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

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

354  

355  

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

357 check_multiprocessing_start_method() 1ijeafbgchdk

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

359  

360multiprocessing.reduction.register(Event, _reduce_event)