Skip to content

Commit c1f341a

Browse files
committed
using instrumenters as decorators
1 parent 35581ef commit c1f341a

3 files changed

Lines changed: 95 additions & 4 deletions

File tree

scorep/instrumenter.py

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import platform
44
import sys
5+
import functools
56

67
global_instrumenter = None
78

@@ -74,8 +75,30 @@ class enable():
7475
If a region name is given, the region the contextmanager is active will be marked in the trace or profile
7576
"""
7677

77-
def __init__(self, region_name=None):
78+
def __init__(self, region_name=""):
7879
self.region_name = region_name
80+
if region_name == "":
81+
self.user_region_name = False
82+
else:
83+
self.user_region_name = True
84+
self.module_name = ""
85+
self.func = None
86+
87+
def _recreate_cm(self):
88+
return self
89+
90+
def __call__(self, func):
91+
get_instrumenter().unregister()
92+
try:
93+
self.func = func
94+
95+
@functools.wraps(func)
96+
def inner(*args, **kwds):
97+
with self._recreate_cm():
98+
return func(*args, **kwds)
99+
finally:
100+
get_instrumenter().register()
101+
return inner
79102

80103
def __enter__(self):
81104
self.tracer_registered = get_instrumenter().get_registered()
@@ -94,6 +117,22 @@ def __enter__(self):
94117
self.module_name, self.region_name, full_file_name,
95118
line_number)
96119

120+
elif callable(self.func):
121+
# The user did not specify a region name, and it's a callable, so it's a semi instrumented region
122+
self.region_name = self.func.__name__
123+
self.module_name = self.func.__module__
124+
self.code_obj = self.func.__code__
125+
file_name = self.func.__code__.co_filename
126+
line_number = self.func.__code__.co_firstlineno
127+
128+
if file_name is not None:
129+
full_file_name = os.path.abspath(file_name)
130+
else:
131+
full_file_name = "None"
132+
133+
scorep.instrumenter.get_instrumenter().region_begin(
134+
self.module_name, self.region_name, full_file_name, line_number, self.code_obj)
135+
97136
get_instrumenter().register()
98137

99138
def __exit__(self, exc_type, exc_value, traceback):
@@ -103,6 +142,9 @@ def __exit__(self, exc_type, exc_value, traceback):
103142
if self.region_name is not None:
104143
get_instrumenter().region_end(
105144
self.module_name, self.region_name)
145+
elif callable(self.func):
146+
get_instrumenter().region_end(
147+
self.module_name, self.region_name, self.code_obj)
106148

107149

108150
class disable():
@@ -116,8 +158,30 @@ class disable():
116158
If a region name is given, the region the contextmanager is active will be marked in the trace or profile
117159
"""
118160

119-
def __init__(self, region_name=None):
161+
def __init__(self, region_name=""):
120162
self.region_name = region_name
163+
if region_name == "":
164+
self.user_region_name = False
165+
else:
166+
self.user_region_name = True
167+
self.module_name = ""
168+
self.func = None
169+
170+
def _recreate_cm(self):
171+
return self
172+
173+
def __call__(self, func):
174+
get_instrumenter().unregister()
175+
try:
176+
self.func = func
177+
178+
@functools.wraps(func)
179+
def inner(*args, **kwds):
180+
with self._recreate_cm():
181+
return func(*args, **kwds)
182+
finally:
183+
get_instrumenter().register()
184+
return inner
121185

122186
def __enter__(self):
123187
self.tracer_registered = get_instrumenter().get_registered()
@@ -137,11 +201,29 @@ def __enter__(self):
137201
get_instrumenter().region_begin(
138202
self.module_name, self.region_name, full_file_name,
139203
line_number)
204+
elif callable(self.func):
205+
# The user did not specify a region name, and it's a callable, so it's a semi instrumented region
206+
self.region_name = self.func.__name__
207+
self.module_name = self.func.__module__
208+
self.code_obj = self.func.__code__
209+
file_name = self.func.__code__.co_filename
210+
line_number = self.func.__code__.co_firstlineno
211+
212+
if file_name is not None:
213+
full_file_name = os.path.abspath(file_name)
214+
else:
215+
full_file_name = "None"
216+
217+
scorep.instrumenter.get_instrumenter().region_begin(
218+
self.module_name, self.region_name, full_file_name, line_number, self.code_obj)
140219

141220
def __exit__(self, exc_type, exc_value, traceback):
142221
if self.tracer_registered:
143222
if self.region_name is not None:
144223
get_instrumenter().region_end(
145224
self.module_name, self.region_name)
225+
elif callable(self.func):
226+
get_instrumenter().region_end(
227+
self.module_name, self.region_name, self.code_obj)
146228

147229
get_instrumenter().register()

test/cases/user_instrumentation.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@
44

55
def foo():
66
print("hello world")
7-
instrumentation2.baz()
87
instrumentation2.bar()
98

109

10+
@scorep.instrumenter.enable()
11+
def foo2():
12+
print("hello world2")
13+
instrumentation2.baz()
14+
15+
1116
with scorep.instrumenter.enable():
1217
foo()
18+
19+
foo2()

test/test_scorep.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,15 @@ def test_user_instrumentation(scorep_env, instrumenter):
254254
)
255255

256256
assert std_err == ""
257-
assert std_out == "hello world\nbaz\nbar\n"
257+
assert std_out == "hello world\nbar\nhello world2\nbaz"
258258

259259
std_out, std_err = call(["otf2-print", trace_path])
260260

261261
assert std_err == ""
262262
assert re.search('ENTER[ ]*[0-9 ]*[0-9 ]*Region: "__main__:foo"', std_out)
263263
assert re.search('LEAVE[ ]*[0-9 ]*[0-9 ]*Region: "__main__:foo"', std_out)
264+
assert re.search('ENTER[ ]*[0-9 ]*[0-9 ]*Region: "__main__:foo2"', std_out)
265+
assert re.search('LEAVE[ ]*[0-9 ]*[0-9 ]*Region: "__main__:foo2"', std_out)
264266

265267

266268
@foreach_instrumenter

0 commit comments

Comments
 (0)