8000 Merge pull request #17737 from seiko2plus/benchmark_simd_info · numpy/numpy@da6952f · GitHub
[go: up one dir, main page]

Skip to content

Commit da6952f

Browse files
authored
Merge pull request #17737 from seiko2plus/benchmark_simd_info
MAINT, Benchmark: print the supported CPU features during the run of performance tests
2 parents f4f261f + 472b152 commit da6952f

File tree

3 files changed

+89
-23
lines changed

3 files changed

+89
-23
lines changed

benchmarks/benchmarks/__init__.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,53 @@
11
from . import common
2+
import sys
3+
import os
4+
5+
def show_cpu_features():
6+
from numpy.lib.utils import _opt_info
7+
info = _opt_info()
8+
info = "NumPy CPU features: " + (info if info else 'nothing enabled')
9+
# ASV wrapping stdout & stderr, so we assume having a tty here
10+
if 'SHELL' in os.environ and sys.platform != 'win32':
11+
# to avoid the red color that imposed by ASV
12+
print(f"\033[33m{info}\033[0m")
13+
else:
14+
print(info)
15+
16+
def dirty_lock(lock_name, lock_on_count=1):
17+
# this lock occurred before each round to avoid duplicate printing
18+
if not hasattr(os, "getppid"):
19+
return False
20+
ppid = os.getppid()
21+
if not ppid or ppid == os.getpid():
22+
# not sure if this gonna happen, but ASV run each round in
23+
# a separate process so the lock should be based on the parent
24+
# process id only
25+
return False
26+
lock_path = os.path.abspath(os.path.join(
27+
os.path.dirname(__file__), "..", "env", lock_name)
28+
)
29+
# ASV load the 'benchmark_dir' to discovering the available benchmarks
30+
# the issue here is ASV doesn't capture any strings from stdout or stderr
31+
# during this stage so we escape it and lock on the second increment
32+
try:
33+
with open(lock_path, 'a+') as f:
34+
f.seek(0)
35+
count, _ppid = (f.read().split() + [0, 0])[:2]
36+
count, _ppid = int(count), int(_ppid)
37+
if _ppid == ppid:
38+
if count >= lock_on_count:
39+
return True
40+
count += 1
41+
else:
42+
count = 0
43+
f.seek(0)
44+
f.truncate()
45+
f.write(f"{str(count)} {str(ppid)}")
46+
except IOError:
47+
pass
48+
return False
49+
50+
51+
# FIXME: there's no official way to provide extra information to the test log
52+
if not dirty_lock("print_cpu_features.lock"):
53+
show_cpu_features()

numpy/_pytesttester.py

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,13 @@
3535

3636

3737
def _show_numpy_info():
38-
from numpy.core._multiarray_umath import (
39-
__cpu_features__, __cpu_baseline__, __cpu_dispatch__
40-
)
4138
import numpy as np
4239

4340
print("NumPy version %s" % np.__version__)
4441
relaxed_strides = np.ones((10, 1), order="C").flags.f_contiguous
4542
print("NumPy relaxed strides checking option:", relaxed_strides)
46-
47-
if len(__cpu_baseline__) == 0 and len(__cpu_dispatch__) == 0:
48-
enabled_features = "nothing enabled"
49-
else:
50-
enabled_features = ' '.join(__cpu_baseline__)
51-
for feature in __cpu_dispatch__:
52-
if __cpu_features__[feature]:
53-
enabled_features += " %s*" % feature
54-
else:
55-
enabled_features += " %s?" % feature
56-
print("NumPy CPU features:", enabled_features)
43+
info = np.lib.utils._opt_info()
44+
print("NumPy CPU features: ", (info if info else 'nothing enabled'))
5745

5846

5947

numpy/lib/utils.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,28 +197,28 @@ def deprecate(*args, **kwargs):
197197
def deprecate_with_doc(msg):
198198
"""
199199
Deprecates a function and includes the deprecation in its docstring.
200-
201-
This function is used as a decorator. It returns an object that can be
202-
used to issue a DeprecationWarning, by passing the to-be decorated
203-
function as argument, this adds warning to the to-be decorated function's
200+
201+
This function is used as a decorator. It returns an object that can be
202+
used to issue a DeprecationWarning, by passing the to-be decorated
203+
function as argument, this adds warning to the to-be decorated function's
204204
docstring and returns the new function object.
205-
205+
206206
See Also
207207
--------
208-
deprecate : Decorate a function such that it issues a `DeprecationWarning`
209-
208+
deprecate : Decorate a function such that it issues a `DeprecationWarning`
209+
210210
Parameters
211211
----------
212212
msg : str
213-
Additional explanation of the deprecation. Displayed in the
213+
Additional explanation of the deprecation. Displayed in the
214214
docstring after the warning.
215215
216216
Returns
217217
-------
218218
obj : object
219219
220220
"""
221-
return _Deprecate(message=msg)
221+
return _Deprecate(message=msg)
222222

223223

224224
#--------------------------------------------
@@ -1042,4 +1042,30 @@ def _median_nancheck(data, result, axis, out):
10421042
result[n] = np.nan
10431043
return result
10441044

1045+
def _opt_info():
1046+
"""
1047+
Returns a string contains the supported CPU features by the current build.
1048+
1049+
The string format can be explained as follows:
1050+
- dispatched features that are supported by the running machine
1051+
end with `*`.
1052+
- dispatched features that are "not" supported by the running machine
1053+
end with `?`.
1054+
- remained features are representing the baseline.
1055+
"""
1056+
from numpy.core._multiarray_umath import (
1057+
__cpu_features__, __cpu_baseline__, __cpu_dispatch__
1058+
)
1059+
1060+
if len(__cpu_baseline__) == 0 and len(__cpu_dispatch__) == 0:
1061+
return ''
1062+
1063+
enabled_features = ' '.join(__cpu_baseline__)
1064+
for feature in __cpu_dispatch__:
1065+
if __cpu_features__[feature]:
1066+
enabled_features += f" {feature}*"
1067+
else:
1068+
enabled_features += f" {feature}?"
1069+
1070+
return enabled_features
10451071
#-----------------------------------------------------------------------------

0 commit comments

Comments
 (0)
0