@@ -5,18 +5,98 @@ function version()
55end
66
77
8+ #
9+ # callback API
10+ #
11+
12+ # multiple subscribers aren't supported, so make sure we only call CUPTI once
13+ const callback_lock = ReentrantLock ()
14+
15+ function callback (userdata:: Ptr{Cvoid} , domain:: CUpti_CallbackDomain ,
16+ id:: CUpti_CallbackId , data_ptr:: Ptr{Cvoid} )
17+ cfg = Base. unsafe_pointer_to_objref (userdata):: CallbackConfig
18+
19+ # decode the callback data
20+ datatype = if domain in (CUPTI_CB_DOMAIN_DRIVER_API, CUPTI_CB_DOMAIN_RUNTIME_API)
21+ CUpti_CallbackData
22+ elseif domain == CUPTI_CB_DOMAIN_RESOURCE
23+ CUpti_ResourceData
24+ elseif domain == CUPTI_CB_DOMAIN_SYNCHRONIZE
25+ CUpti_SynchronizeData
26+ elseif domain == CUPTI_CB_DOMAIN_NVTX
27+ CUpti_NvtxData
28+ else
29+ @warn """ Unsupported callback domain: $(domain) .
30+ Please file an issue, or extend the implementation of `CUPTI.callback` to handle this callback kind."""
31+ return
32+ end
33+ data = unsafe_load (convert (Ptr{datatype}, data_ptr))
34+
35+ # invoke the actual user callback
36+ cfg. callback (domain, id, data)
37+
38+ return
39+ end
40+
41+ """
42+ cfg = CUPTI.CallbackConfig(callback_kinds) do domain, id, data
43+ # inspect data
44+ end
45+
46+ CUPTI.enable!(cfg) do
47+ # do stuff
48+ end
49+ """
50+ mutable struct CallbackConfig
51+ callback:: Function
52+ callback_kinds:: Vector{CUpti_CallbackDomain}
53+ end
54+
55+ function enable! (f:: Base.Callable , cfg:: CallbackConfig )
56+ @lock callback_lock begin
57+ callback_ptr =
58+ @cfunction (callback, Cvoid,
59+ (Ptr{Cvoid}, CUpti_CallbackDomain, CUpti_CallbackId, Ptr{Cvoid}))
60+
61+ GC. @preserve cfg begin
62+ # set-up subscriber
63+ subscriber_ref = Ref {CUpti_SubscriberHandle} ()
64+ cuptiSubscribe (subscriber_ref, callback_ptr, Base. pointer_from_objref (cfg))
65+ subscriber = subscriber_ref[]
66+
67+ # enable domains
68+ for callback_kind in cfg. callback_kinds
69+ CUPTI. cuptiEnableDomain (true , subscriber, callback_kind)
70+ end
71+
72+ try
73+ f ()
74+ finally
75+ # disable callback kinds
76+ for callback_kind in cfg. callback_kinds
77+ CUPTI. cuptiEnableDomain (false , subscriber, callback_kind)
78+ end
79+
80+ # disable the subscriber
81+ CUPTI. cuptiUnsubscribe (subscriber)
82+ end
83+ end
84+ end
85+ end
86+
87+
888#
989# activity API
1090#
1191
1292"""
13- cfg = ActvitiyConfig (activity_kinds)
93+ cfg = CUPTI.ActivityConfig (activity_kinds)
1494
15- enable!(cfg)
16- # do stuff
17- disable!(cfg)
95+ CUPTI. enable!(cfg) do
96+ # do stuff
97+ end
1898
19- process(cfg) do ( ctx, stream , record)
99+ CUPTI. process(cfg) do ctx, stream_id , record
20100 # inspect record
21101 end
22102
@@ -43,6 +123,7 @@ function allocate_buffer()
43123 Array {UInt8} (undef, 8 * 1024 * 1024 ) # 8 MB
44124end
45125
126+ const activity_lock = ReentrantLock ()
46127const activity_config = Ref {Union{Nothing,ActivityConfig}} (nothing )
47128
48129function request_buffer (dest_ptr, sz_ptr, max_num_records_ptr)
@@ -93,41 +174,40 @@ function complete_buffer(ctx_handle, stream_id, buf_ptr, sz, valid_sz)
93174 return
94175end
95176
96- function enable! (cfg:: ActivityConfig )
97- activity_config[] === nothing ||
98- error (" Only one profiling session can be active at a time." )
99-
100- # set-up callbacks
101- request_buffer_ptr = @cfunction (request_buffer, Cvoid,
102- (Ptr{Ptr{UInt8}}, Ptr{Csize_t}, Ptr{Csize_t}))
103- complete_buffer_ptr = @cfunction (complete_buffer, Cvoid,
104- (CUDA. CUcontext, UInt32, Ptr{UInt8}, Csize_t, Csize_t))
105- cuptiActivityRegisterCallbacks (request_buffer_ptr, complete_buffer_ptr)
177+ function enable! (f:: Base.Callable , cfg:: ActivityConfig )
178+ @lock activity_lock begin
179+ activity_config[] = cfg
106180
107- activity_config[] = cfg
181+ # set-up callbacks
182+ request_buffer_ptr =
183+ @cfunction (request_buffer, Cvoid,
184+ (Ptr{Ptr{UInt8}}, Ptr{Csize_t}, Ptr{Csize_t}))
185+ complete_buffer_ptr =
186+ @cfunction (complete_buffer, Cvoid,
187+ (CUDA. CUcontext, UInt32, Ptr{UInt8}, Csize_t, Csize_t))
188+ cuptiActivityRegisterCallbacks (request_buffer_ptr, complete_buffer_ptr)
108189
109- # enable requested activity kinds
110- for activity_kind in cfg. activity_kinds
111- cuptiActivityEnable (activity_kind)
112- end
113- end
190+ activity_config[] = cfg
114191
115- function disable! (cfg:: ActivityConfig )
116- if activity_config[] != = cfg
117- error (" This profiling session is not active." )
118- end
119-
120- # disable activity kinds
121- for activity_kind in cfg. activity_kinds
122- cuptiActivityDisable (activity_kind)
123- end
192+ # enable requested activity kinds
193+ for activity_kind in cfg. activity_kinds
194+ cuptiActivityEnable (activity_kind)
195+ end
124196
125- # flush all activity records, even incomplete ones
126- cuptiActivityFlushAll (CUPTI_ACTIVITY_FLAG_FLUSH_FORCED)
197+ try
198+ f ()
199+ finally
200+ # disable activity kinds
201+ for activity_kind in cfg. activity_kinds
202+ cuptiActivityDisable (activity_kind)
203+ end
127204
128- activity_config[] = nothing
205+ # flush all activity records, even incomplete ones
206+ cuptiActivityFlushAll (CUPTI_ACTIVITY_FLAG_FLUSH_FORCED)
129207
130- return
208+ activity_config[] = nothing
209+ end
210+ end
131211end
132212
133213function process (f, cfg:: ActivityConfig )
0 commit comments