Source code for hidet.cuda.event
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# pylint: disable=no-name-in-module, c-extension-no-member
from __future__ import annotations
from cuda import cudart
from cuda.cudart import cudaEvent_t
from hidet.utils import exiting
[docs]class Event:
"""
A CUDA event.
Parameters
----------
enable_timing: bool
When enabled, the event is able to record the time between itself and another event.
blocking: bool
When enabled, we can use the :meth:`synchronize` method to block the current host thread until the event
completes.
"""
def __init__(self, enable_timing: bool = False, blocking: bool = False):
self._enable_timing: bool = enable_timing
self._blocking: bool = blocking
self._handle: cudaEvent_t
if not enable_timing:
flags = cudart.cudaEventDisableTiming
else:
flags = cudart.cudaEventDefault
err, self._handle = cudart.cudaEventCreateWithFlags(flags)
assert err == 0, err
def __del__(self, is_exiting=exiting.is_exiting):
if is_exiting():
return
(err,) = cudart.cudaEventDestroy(self._handle)
assert err == 0, err
[docs] def handle(self) -> cudaEvent_t:
"""
Get the handle of the event.
Returns
-------
handle: cudaEvent_t
The handle of the event.
"""
return self._handle
[docs] def elapsed_time(self, start_event: Event) -> float:
"""
Get the elapsed time between the start event and this event in milliseconds.
Parameters
----------
start_event: Event
The start event.
Returns
-------
elapsed_time: float
The elapsed time in milliseconds.
"""
# pylint: disable=protected-access
if not self._enable_timing or not start_event._enable_timing:
raise RuntimeError("Event does not have timing enabled")
err, elapsed_time = cudart.cudaEventElapsedTime(start_event._handle, self._handle)
assert err == 0, err
return elapsed_time
[docs] def record(self, stream=None):
"""
Record the event in the given stream.
After the event is recorded:
- We can synchronize the event to block the current host thread until all the tasks before the event are
completed via :meth:`Event.synchronize`.
- We can also get the elapsed time between the event and another event via :meth:`Event.elapsed_time` (when
`enable_timing` is `True`).
- We can also let another stream to wait for the event via :meth:`Stream.wait_event`.
Parameters
----------
stream: Stream, optional
The stream where the event is recorded.
"""
from hidet.cuda.stream import Stream, current_stream
if stream is None:
stream = current_stream()
if not isinstance(stream, Stream):
raise TypeError("stream must be a Stream")
(err,) = cudart.cudaEventRecord(self._handle, stream.handle())
assert err == 0, err
[docs] def synchronize(self):
"""
Block the current host thread until the tasks before the event are completed. This method is only available
when `blocking` is `True` when creating the event, and the event is recorded in a stream.
"""
if not self._blocking:
raise RuntimeError("Event does not have blocking enabled")
(err,) = cudart.cudaEventSynchronize(self._handle)
if err != 0:
raise RuntimeError("cudaEventSynchronize failed with error: {}".format(err.name))