11from math import sin
22import unittest
33import numpy as np
4+ from unittest .mock import patch
45
56from pytest import importorskip
67
78from ..config import get_config , use_config
89from ..array import wrap
9- from ..jit import get_binop_return_type , AnnotationHelper
10+ from ..jit import (
11+ AnnotationHelper , ElementwiseJIT , ReductionJIT , ScanJIT ,
12+ get_binop_return_type
13+ )
1014from ..types import annotate
1115from ..parallel import Elementwise , Reduction , Scan
1216
@@ -32,6 +36,91 @@ def undeclared_f(a, b):
3236 return g (h_ab )
3337
3438
39+ class TestCUDAJITSynchronization (unittest .TestCase ):
40+ def _patch_cuda_event (self ):
41+ sync_calls = []
42+
43+ class FakeEvent :
44+ def record (self ):
45+ pass
46+
47+ def synchronize (self ):
48+ sync_calls .append ("sync" )
49+
50+ return sync_calls , patch ("pycuda.driver.Event" , FakeEvent )
51+
52+ def test_cuda_elementwise_jit_does_not_synchronize_without_profile (self ):
53+ importorskip ("pycuda" )
54+
55+ @annotate
56+ def axpb (i , x ):
57+ x [i ] = x [i ] + 1.0
58+
59+ kernel = ElementwiseJIT (axpb , backend = "cuda" )
60+ kernel ._generate_kernel = lambda * args : lambda * c_args , ** kw : None
61+ sync_calls , event_patch = self ._patch_cuda_event ()
62+
63+ with use_config (profile = False ), event_patch :
64+ kernel (np .zeros (8 ))
65+
66+ assert sync_calls == []
67+
68+ def test_cuda_scan_jit_does_not_synchronize_without_profile (self ):
69+ importorskip ("pycuda" )
70+
71+ @annotate (input = "doublep" , return_ = "double" )
72+ def input_expr (i , input ):
73+ return input [i ]
74+
75+ @annotate (output = "doublep" , item = "double" )
76+ def output_expr (i , item , output ):
77+ output [i ] = item
78+
79+ scan = ScanJIT (input = input_expr , output = output_expr , backend = "cuda" )
80+ output_expr .arg_keys = {scan ._get_backend_key (): ["input" , "output" ]}
81+ scan ._generate_kernel = lambda ** kwargs : lambda * c_args : None
82+ sync_calls , event_patch = self ._patch_cuda_event ()
83+
84+ with use_config (profile = False ), event_patch :
85+ scan (input = np .zeros (8 ), output = np .zeros (8 ))
86+
87+ assert sync_calls == []
88+
89+ def test_cuda_reduction_jit_does_not_event_synchronize_without_profile (self ):
90+ importorskip ("pycuda" )
91+
92+ class FakeResult :
93+ def get (self ):
94+ return 1.0
95+
96+ reduction = ReductionJIT ("a+b" , backend = "cuda" )
97+ reduction ._generate_kernel = (
98+ lambda * args : lambda * c_args , ** kw : FakeResult ()
99+ )
100+ sync_calls , event_patch = self ._patch_cuda_event ()
101+
102+ with use_config (profile = False ), event_patch :
103+ assert reduction (np .zeros (8 )) == 1.0
104+
105+ assert sync_calls == []
106+
107+ def test_cuda_elementwise_jit_synchronizes_with_profile (self ):
108+ importorskip ("pycuda" )
109+
110+ @annotate
111+ def axpb (i , x ):
112+ x [i ] = x [i ] + 1.0
113+
114+ kernel = ElementwiseJIT (axpb , backend = "cuda" )
115+ kernel ._generate_kernel = lambda * args : lambda * c_args , ** kw : None
116+ sync_calls , event_patch = self ._patch_cuda_event ()
117+
118+ with use_config (profile = True ), event_patch :
119+ kernel (np .zeros (8 ))
120+
121+ assert sync_calls == ["sync" ]
122+
123+
35124class TestAnnotationHelper (unittest .TestCase ):
36125 def test_const_as_call_arg (self ):
37126 # Given
0 commit comments