Skip to content
This repository was archived by the owner on Jan 25, 2023. It is now read-only.

Commit 97fe221

Browse files
authored
Merge pull request numba#6866 from esc/misc/0.53.1
Changes for 0.53.1
2 parents f23ef8f + 8e7a0ef commit 97fe221

8 files changed

Lines changed: 232 additions & 6 deletions

File tree

‎CHANGE_LOG‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
Version 0.53.1 (25 March, 2021)
2+
-------------------------------
3+
4+
This is a bugfix release for 0.53.0. It contains the following four
5+
pull-requests which fix two critical regressions and two build failures
6+
reported by the openSuSe team:
7+
8+
* PR #6851 set non-reported llvm timing values to 0.0
9+
* PR #6837 Ignore warnings from packaging module when testing import behaviour.
10+
* PR #6828 Fix regression in CUDA: Set stream in mapped and managed array
11+
device_setup
12+
* PR #6826 Fix regression on gufunc serialization
13+
14+
Authors:
15+
16+
* Ben Greiner
17+
* Graham Markall
18+
* Siu Kwan Lam
19+
* Stuart Archibald
20+
121
Version 0.53.0 (11 March, 2021)
222
-------------------------------
323

‎numba/cuda/cudadrv/devicearray.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@ class MappedNDArray(DeviceNDArrayBase, np.ndarray):
678678

679679
def device_setup(self, gpu_data, stream=0):
680680
self.gpu_data = gpu_data
681+
self.stream = stream
681682

682683

683684
class ManagedNDArray(DeviceNDArrayBase, np.ndarray):
@@ -687,6 +688,7 @@ class ManagedNDArray(DeviceNDArrayBase, np.ndarray):
687688

688689
def device_setup(self, gpu_data, stream=0):
689690
self.gpu_data = gpu_data
691+
self.stream = stream
690692

691693

692694
def from_array_like(ary, stream=0, gpu_data=None):

‎numba/cuda/tests/cudapy/test_cuda_array_interface.py‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from numba import cuda
55
from numba.cuda.testing import unittest, ContextResettingTestCase, ForeignArray
66
from numba.cuda.testing import skip_on_cudasim, skip_if_external_memmgr
7-
from numba.tests.support import override_config
7+
from numba.tests.support import linux_only, override_config
88
from unittest.mock import call, patch
99

1010

@@ -261,12 +261,32 @@ def test_produce_no_stream(self):
261261
c_arr = cuda.device_array(10)
262262
self.assertIsNone(c_arr.__cuda_array_interface__['stream'])
263263

264+
mapped_arr = cuda.mapped_array(10)
265+
self.assertIsNone(mapped_arr.__cuda_array_interface__['stream'])
266+
267+
@linux_only
268+
def test_produce_managed_no_stream(self):
269+
managed_arr = cuda.managed_array(10)
270+
self.assertIsNone(managed_arr.__cuda_array_interface__['stream'])
271+
264272
def test_produce_stream(self):
265273
s = cuda.stream()
266274
c_arr = cuda.device_array(10, stream=s)
267275
cai_stream = c_arr.__cuda_array_interface__['stream']
268276
self.assertEqual(s.handle.value, cai_stream)
269277

278+
s = cuda.stream()
279+
mapped_arr = cuda.mapped_array(10, stream=s)
280+
cai_stream = mapped_arr.__cuda_array_interface__['stream']
281+
self.assertEqual(s.handle.value, cai_stream)
282+
283+
@linux_only
284+
def test_produce_managed_stream(self):
285+
s = cuda.stream()
286+
managed_arr = cuda.managed_array(10, stream=s)
287+
cai_stream = managed_arr.__cuda_array_interface__['stream']
288+
self.assertEqual(s.handle.value, cai_stream)
289+
270290
def test_consume_no_stream(self):
271291
# Create a foreign array with no stream
272292
f_arr = ForeignArray(cuda.device_array(10))

‎numba/misc/llvm_pass_timings.py‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,14 @@ def parse(raw_data):
239239
missing[k] = 0.0
240240
# parse timings
241241
n = r"\s*((?:[0-9]+\.)?[0-9]+)"
242-
pat = f"\\s+{n}\\s*\\({n}%\\)" * (len(headers) - 1) + r"\s*(.*)"
242+
pat = f"\\s+(?:{n}\\s*\\({n}%\\)|-+)" * (len(headers) - 1)
243+
pat += r"\s*(.*)"
243244
for ln in line_iter:
244245
m = re.match(pat, ln)
245246
if m is not None:
246247
raw_data = list(m.groups())
247-
data = {k: float(v) for k, v in zip(attrs, raw_data)}
248+
data = {k: float(v) if v is not None else 0.0
249+
for k, v in zip(attrs, raw_data)}
248250
data.update(missing)
249251
pass_name = raw_data[-1]
250252
rec = PassTimingRecord(

‎numba/np/ufunc/gufunc.py‎

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
from numba.np.ufunc.ufuncbuilder import GUFuncBuilder
44
from numba.np.ufunc.sigparse import parse_signature
55
from numba.np.numpy_support import ufunc_find_matching_loop
6+
from numba.core import serialize
67

78

8-
class GUFunc(object):
9+
class GUFunc(serialize.ReduceMixin):
910
"""
1011
Dynamic generalized universal function (GUFunc)
1112
intended to act like a normal Numpy gufunc, but capable
@@ -18,13 +19,40 @@ def __init__(self, py_func, signature, identity=None, cache=None,
1819
self.ufunc = None
1920
self._frozen = False
2021
self._is_dynamic = is_dynamic
22+
self._identity = identity
2123

2224
# GUFunc cannot inherit from GUFuncBuilder because "identity"
2325
# is a property of GUFunc. Thus, we hold a reference to a GUFuncBuilder
2426
# object here
2527
self.gufunc_builder = GUFuncBuilder(
2628
py_func, signature, identity, cache, targetoptions)
2729

30+
def _reduce_states(self):
31+
gb = self.gufunc_builder
32+
dct = dict(
33+
py_func=gb.py_func,
34+
signature=gb.signature,
35+
identity=self._identity,
36+
cache=gb.cache,
37+
is_dynamic=self._is_dynamic,
38+
targetoptions=gb.targetoptions,
39+
typesigs=gb._sigs,
40+
frozen=self._frozen,
41+
)
42+
return dct
43+
44+
@classmethod
45+
def _rebuild(cls, py_func, signature, identity, cache, is_dynamic,
46+
targetoptions, typesigs, frozen):
47+
self = cls(py_func=py_func, signature=signature, identity=identity,
48+
cache=cache, is_dynamic=is_dynamic,
49+
targetoptions=targetoptions)
50+
for sig in typesigs:
51+
self.add(sig)
52+
self.build_ufunc()
53+
self._frozen = frozen
54+
return self
55+
2856
def __repr__(self):
2957
return f"<numba._GUFunc '{self.__name__}'>"
3058

‎numba/tests/npyufunc/test_gufunc.py‎

Lines changed: 117 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import unittest
2+
import pickle
3+
14
import numpy as np
25
import numpy.core.umath_tests as ut
36

47
from numba import void, float32, jit, guvectorize
58
from numba.np.ufunc import GUVectorize
69
from numba.tests.support import tag, TestCase
7-
import unittest
810

911

1012
def matmulcore(A, B, C):
@@ -281,5 +283,119 @@ class TestGUVectorizeScalarParallel(TestGUVectorizeScalar):
281283
target = 'parallel'
282284

283285

286+
class TestGUVectorizePickling(TestCase):
287+
def test_pickle_gufunc_non_dyanmic(self):
288+
"""Non-dynamic gufunc.
289+
"""
290+
@guvectorize(["f8,f8[:]"], "()->()")
291+
def double(x, out):
292+
out[:] = x * 2
293+
294+
# pickle
295+
ser = pickle.dumps(double)
296+
cloned = pickle.loads(ser)
297+
298+
# attributes carried over
299+
self.assertEqual(cloned._frozen, double._frozen)
300+
self.assertEqual(cloned.identity, double.identity)
301+
self.assertEqual(cloned.is_dynamic, double.is_dynamic)
302+
self.assertEqual(cloned.gufunc_builder._sigs,
303+
double.gufunc_builder._sigs)
304+
# expected value of attributes
305+
self.assertTrue(cloned._frozen)
306+
307+
cloned.disable_compile()
308+
self.assertTrue(cloned._frozen)
309+
310+
# scalar version
311+
self.assertPreciseEqual(double(0.5), cloned(0.5))
312+
# array version
313+
arr = np.arange(10)
314+
self.assertPreciseEqual(double(arr), cloned(arr))
315+
316+
def test_pickle_gufunc_dyanmic_null_init(self):
317+
"""Dynamic gufunc w/o prepopulating before pickling.
318+
"""
319+
@guvectorize("()->()", identity=1)
320+
def double(x, out):
321+
out[:] = x * 2
322+
323+
# pickle
324+
ser = pickle.dumps(double)
325+
cloned = pickle.loads(ser)
326+
327+
# attributes carried over
328+
self.assertEqual(cloned._frozen, double._frozen)
329+
self.assertEqual(cloned.identity, double.identity)
330+
self.assertEqual(cloned.is_dynamic, double.is_dynamic)
331+
self.assertEqual(cloned.gufunc_builder._sigs,
332+
double.gufunc_builder._sigs)
333+
# expected value of attributes
334+
self.assertFalse(cloned._frozen)
335+
336+
# scalar version
337+
expect = np.zeros(1)
338+
got = np.zeros(1)
339+
double(0.5, out=expect)
340+
cloned(0.5, out=got)
341+
self.assertPreciseEqual(expect, got)
342+
# array version
343+
arr = np.arange(10)
344+
expect = np.zeros_like(arr)
345+
got = np.zeros_like(arr)
346+
double(arr, out=expect)
347+
cloned(arr, out=got)
348+
self.assertPreciseEqual(expect, got)
349+
350+
def test_pickle_gufunc_dyanmic_initialized(self):
351+
"""Dynamic gufunc prepopulated before pickling.
352+
353+
Once unpickled, we disable compilation to verify that the gufunc
354+
compilation state is carried over.
355+
"""
356+
@guvectorize("()->()", identity=1)
357+
def double(x, out):
358+
out[:] = x * 2
359+
360+
# prepopulate scalar
361+
expect = np.zeros(1)
362+
got = np.zeros(1)
363+
double(0.5, out=expect)
364+
# prepopulate array
365+
arr = np.arange(10)
366+
expect = np.zeros_like(arr)
367+
got = np.zeros_like(arr)
368+
double(arr, out=expect)
369+
370+
# pickle
371+
ser = pickle.dumps(double)
372+
cloned = pickle.loads(ser)
373+
374+
# attributes carried over
375+
self.assertEqual(cloned._frozen, double._frozen)
376+
self.assertEqual(cloned.identity, double.identity)
377+
self.assertEqual(cloned.is_dynamic, double.is_dynamic)
378+
self.assertEqual(cloned.gufunc_builder._sigs,
379+
double.gufunc_builder._sigs)
380+
# expected value of attributes
381+
self.assertFalse(cloned._frozen)
382+
383+
# disable compilation
384+
cloned.disable_compile()
385+
self.assertTrue(cloned._frozen)
386+
# scalar version
387+
expect = np.zeros(1)
388+
got = np.zeros(1)
389+
double(0.5, out=expect)
390+
cloned(0.5, out=got)
391+
self.assertPreciseEqual(expect, got)
392+
# array version
393+
expect = np.zeros_like(arr)
394+
got = np.zeros_like(arr)
395+
double(arr, out=expect)
396+
cloned(arr, out=got)
397+
self.assertPreciseEqual(expect, got)
398+
399+
284400
if __name__ == '__main__':
285401
unittest.main()

‎numba/tests/test_import.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ def test_no_accidental_warnings(self):
5858
# checks that importing Numba isn't accidentally triggering warnings due
5959
# to e.g. deprecated use of import locations from Python's stdlib
6060
code = "import numba"
61-
flags = ["-Werror",]
61+
# See: https://github.com/numba/numba/issues/6831
62+
# bug in setuptools/packaging causing a deprecation warning
63+
flags = ["-Werror", "-Wignore::DeprecationWarning:packaging.version:"]
6264
self.run_in_subproc(code, flags)
6365

6466
def test_import_star(self):

‎numba/tests/test_llvm_pass_timings.py‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,33 @@
55
from numba.misc import llvm_pass_timings as lpt
66

77

8+
timings_raw1 = """
9+
===-------------------------------------------------------------------------===
10+
... Pass execution timing report ...
11+
===-------------------------------------------------------------------------===
12+
Total Execution Time: 0.0001 seconds (0.0001 wall clock)
13+
14+
---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
15+
0.0001 ( 90.1%) 0.0001 ( 90.1%) 0.0001 ( 90.1%) 0.0001 ( 90.1%) A1
16+
0.0000 ( 9.9%) 0.0000 ( 9.9%) 0.0000 ( 9.9%) 0.0000 ( 9.9%) A2
17+
0.0001 (100.0%) 0.0001 (100.0%) 0.0001 (100.0%) 0.0001 (100.0%) Total
18+
19+
""" # noqa: E501
20+
21+
timings_raw2 = """
22+
===-------------------------------------------------------------------------===
23+
... Pass execution timing report ...
24+
===-------------------------------------------------------------------------===
25+
Total Execution Time: 0.0001 seconds (0.0001 wall clock)
26+
27+
---User Time--- --System Time-- --User+System-- ---Wall Time--- --- Name ---
28+
0.0001 ( 90.1%) ----- 0.0001 ( 90.1%) 0.0001 ( 90.1%) A1
29+
0.0000 ( 9.9%) ----- 0.0000 ( 9.9%) 0.0000 ( 9.9%) A2
30+
0.0001 (100.0%) ----- 0.0001 (100.0%) 0.0001 (100.0%) Total
31+
32+
""" # noqa: E501
33+
34+
835
class TestLLVMPassTimings(TestCase):
936

1037
def test_usage(self):
@@ -61,6 +88,15 @@ def foo(n):
6188
self.assertGreaterEqual(last, cur)
6289
cur = last
6390

91+
def test_parse_raw(self):
92+
timings1 = lpt.ProcessedPassTimings(timings_raw1)
93+
self.assertAlmostEqual(timings1.get_total_time(), 0.0001)
94+
self.assertIsInstance(timings1.summary(), str)
95+
96+
timings2 = lpt.ProcessedPassTimings(timings_raw2)
97+
self.assertAlmostEqual(timings2.get_total_time(), 0.0001)
98+
self.assertIsInstance(timings2.summary(), str)
99+
64100

65101
class TestLLVMPassTimingsDisabled(TestCase):
66102
def test_disabled_behavior(self):

0 commit comments

Comments
 (0)