Skip to content

Commit 944b838

Browse files
authored
Merge pull request #123 from Flamefire/ctrace-default
Make cProfile the default where available (Python 3) and add support for PyPy
2 parents 4f64498 + ba86364 commit 944b838

9 files changed

Lines changed: 50 additions & 11 deletions

File tree

.github/workflows/unit_tests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ jobs:
99
runs-on: ubuntu-latest
1010
strategy:
1111
matrix:
12-
python: [2.7, 3.5, 3.6, 3.7, 3.8]
12+
python: [2.7, 3.5, 3.6, 3.7, 3.8, 'pypy-2.7', 'pypy-3.6', 'pypy-3.7']
1313
fail-fast: false
1414

1515
steps:
@@ -41,4 +41,4 @@ jobs:
4141
run: pip install .
4242
- name: Run tests
4343
working-directory: test
44-
run: pytest
44+
run: pytest

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ find_package(Python REQUIRED COMPONENTS Interpreter Development)
1919
Python_add_library(_bindings
2020
src/methods.cpp src/scorep_bindings.cpp src/scorepy/events.cpp
2121
)
22-
if(Python_VERSION_MAJOR GREATER_EQUAL 3)
22+
if(Python_VERSION_MAJOR GREATER_EQUAL 3 AND NOT Python_INTERPRETER_ID STREQUAL "PyPy")
2323
target_sources(_bindings PRIVATE
2424
src/classes.cpp
2525
src/scorepy/cInstrumenter.cpp
2626
src/scorepy/pathUtils.cpp
2727
src/scorepy/pythonHelpers.cpp
2828
)
29+
target_compile_definitions(_bindings PRIVATE SCOREPY_ENABLE_CINSTRUMENTER=1)
30+
else()
31+
target_compile_definitions(_bindings PRIVATE SCOREPY_ENABLE_CINSTRUMENTER=0)
2932
endif()
3033
target_link_libraries(_bindings PRIVATE Scorep::Plugin)
3134
target_compile_features(_bindings PRIVATE cxx_std_11)

scorep/__main__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ def scorep_main(argv=None):
2424
no_default_threads = False
2525
no_default_compiler = False
2626
no_instrumenter = False
27-
instrumenter_type = "profile"
27+
if scorep.instrumenter.has_c_instrumenter():
28+
instrumenter_type = "cProfile"
29+
else:
30+
instrumenter_type = "profile"
2831

2932
for elem in argv[1:]:
3033
if parse_scorep_commands:

scorep/instrumenter.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
import inspect
22
import os
3+
import platform
4+
import sys
35

46
global_instrumenter = None
57

68

9+
def has_c_instrumenter():
10+
"""Return true if the C instrumenter(s) are available"""
11+
# We are using the UTF-8 string features from Python 3
12+
# The C Instrumenter functions are not available on PyPy
13+
return sys.version_info.major >= 3 and platform.python_implementation() != 'PyPy'
14+
15+
716
def get_instrumenter(enable_instrumenter=False,
817
instrumenter_type="dummy"):
918
"""

setup.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import sys
33
from distutils.core import setup, Extension
44
import scorep.helper
5+
from scorep.instrumenter import has_c_instrumenter
56

67
if scorep.helper.get_scorep_version() < 5.0:
78
raise RuntimeError(
@@ -25,17 +26,23 @@
2526
src_folder = os.path.abspath('src')
2627
include += [src_folder]
2728
sources = ['src/methods.cpp', 'src/scorep_bindings.cpp', 'src/scorepy/events.cpp']
28-
if sys.version_info.major >= 3:
29+
define_macros = [('PY_SSIZE_T_CLEAN', '1')]
30+
# We are using the UTF-8 string features from Python 3
31+
# The C Instrumenter functions are not available on PyPy
32+
if has_c_instrumenter():
2933
sources.extend([
3034
'src/classes.cpp',
3135
'src/scorepy/cInstrumenter.cpp',
3236
'src/scorepy/pythonHelpers.cpp',
3337
'src/scorepy/pathUtils.cpp',
3438
])
39+
define_macros.append(('SCOREPY_ENABLE_CINSTRUMENTER', '1'))
40+
else:
41+
define_macros.append(('SCOREPY_ENABLE_CINSTRUMENTER', '0'))
3542

3643
cmodules.append(Extension('scorep._bindings',
3744
include_dirs=include,
38-
define_macros=[('PY_SSIZE_T_CLEAN', '1')],
45+
define_macros=define_macros,
3946
extra_compile_args=["-std=c++11"],
4047
sources=sources))
4148

@@ -70,6 +77,7 @@
7077
'Programming Language :: Python :: 3.8',
7178
'Programming Language :: Python :: 3.9',
7279
'Programming Language :: Python :: Implementation :: CPython',
80+
'Programming Language :: Python :: Implementation :: PyPy',
7381
'Operating System :: POSIX',
7482
'Operating System :: Unix',
7583
],

src/scorep_bindings.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ PyMODINIT_FUNC init_bindings(void)
77
{
88
(void)Py_InitModule("_bindings", scorepy::getMethodTable());
99
}
10-
#else /*python 3*/
10+
#else /*python 3*/
1111
static struct PyModuleDef scorepmodule = { PyModuleDef_HEAD_INIT, "_bindings", /* name of module */
1212
NULL, /* module documentation, may be NULL */
1313
-1, /* size of per-interpreter state of the module,
@@ -16,23 +16,27 @@ static struct PyModuleDef scorepmodule = { PyModuleDef_HEAD_INIT, "_bindings", /
1616
scorepy::getMethodTable() };
1717
PyMODINIT_FUNC PyInit__bindings(void)
1818
{
19+
#if SCOREPY_ENABLE_CINSTRUMENTER
1920
auto* ctracerType = &scorepy::getCInstrumenterType();
2021
if (PyType_Ready(ctracerType) < 0)
2122
return nullptr;
23+
#endif
2224

2325
auto* m = PyModule_Create(&scorepmodule);
2426
if (!m)
2527
{
2628
return nullptr;
2729
}
2830

31+
#if SCOREPY_ENABLE_CINSTRUMENTER
2932
Py_INCREF(ctracerType);
3033
if (PyModule_AddObject(m, "CInstrumenter", (PyObject*)ctracerType) < 0)
3134
{
3235
Py_DECREF(ctracerType);
3336
Py_DECREF(m);
3437
return nullptr;
3538
}
39+
#endif
3640

3741
return m;
3842
}
File renamed without changes.

test/cases/use_threads.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44
import instrumentation2
55

66

7+
lock = threading.Lock()
8+
9+
710
def worker(id, func):
8-
print("Thread %s started" % id)
11+
with lock:
12+
print("Thread %s started" % id)
913
# Use a random delay to add non-determinism to the output
1014
time.sleep(random.uniform(0.01, 0.9))
1115
func()

test/test_scorep.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
import os
44
import pkgutil
5+
import platform
6+
import pytest
57
import re
68
import subprocess
79
import sys
8-
import pytest
910

1011

1112
def call(arguments, expected_returncode=0, env=None):
@@ -50,7 +51,8 @@ def requires_package(name):
5051

5152

5253
cinstrumenter_skip_mark = pytest.mark.skipif(
53-
sys.version_info.major < 3, reason="CInstrumenter only available in Python 3"
54+
sys.version_info.major < 3 or platform.python_implementation() == 'PyPy',
55+
reason="CInstrumenter only available in Python 3 and not in PyPy"
5456
)
5557
# All instrumenters (except dummy which isn't a real one)
5658
ALL_INSTRUMENTERS = [
@@ -85,6 +87,12 @@ def test_has_version():
8587
assert scorep.__version__ is not None
8688

8789

90+
@cinstrumenter_skip_mark
91+
def test_has_c_instrumenter():
92+
from scorep.instrumenter import has_c_instrumenter
93+
assert has_c_instrumenter()
94+
95+
8896
@foreach_instrumenter
8997
def test_user_regions(scorep_env, instrumenter):
9098
trace_path = get_trace_path(scorep_env)
@@ -448,7 +456,7 @@ def test_io(scorep_env, instrumenter):
448456

449457
print("start")
450458
std_out, std_err = call_with_scorep(
451-
"cases/io.py",
459+
"cases/file_io.py",
452460
[
453461
"--nocompiler",
454462
"--instrumenter-type=" + instrumenter,

0 commit comments

Comments
 (0)