Skip to content

Commit 0b2d5fe

Browse files
chore(profiling): remove '_self_' prefixes from attributes after 'unwrapting' Lock Profiler code
1 parent d297d5b commit 0b2d5fe

File tree

2 files changed

+40
-41
lines changed

2 files changed

+40
-41
lines changed

ddtrace/profiling/collector/_lock.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ class _ProfiledLock:
4646

4747
__slots__ = (
4848
"__wrapped__",
49-
"_self_tracer",
50-
"_self_max_nframes",
51-
"_self_capture_sampler",
52-
"_self_init_loc",
53-
"_self_acquired_at",
54-
"_self_name",
49+
"tracer",
50+
"max_nframes",
51+
"capture_sampler",
52+
"init_location",
53+
"acquired_time",
54+
"name",
5555
)
5656

5757
def __init__(
@@ -62,15 +62,15 @@ def __init__(
6262
capture_sampler: collector.CaptureSampler,
6363
) -> None:
6464
self.__wrapped__: Any = wrapped
65-
self._self_tracer: Optional[Tracer] = tracer
66-
self._self_max_nframes: int = max_nframes
67-
self._self_capture_sampler: collector.CaptureSampler = capture_sampler
65+
self.tracer: Optional[Tracer] = tracer
66+
self.max_nframes: int = max_nframes
67+
self.capture_sampler: collector.CaptureSampler = capture_sampler
6868
# Frame depth: 0=__init__, 1=_profiled_allocate_lock, 2=_LockAllocatorWrapper.__call__, 3=caller
6969
frame: FrameType = sys._getframe(3)
7070
code: CodeType = frame.f_code
71-
self._self_init_loc: str = "%s:%d" % (os.path.basename(code.co_filename), frame.f_lineno)
72-
self._self_acquired_at: int = 0
73-
self._self_name: Optional[str] = None
71+
self.init_location: str = f"{os.path.basename(code.co_filename)}:{frame.f_lineno}"
72+
self.acquired_time: int = 0
73+
self.name: Optional[str] = None
7474

7575
### DUNDER methods ###
7676

@@ -87,7 +87,7 @@ def __hash__(self) -> int:
8787
return hash(self.__wrapped__)
8888

8989
def __repr__(self) -> str:
90-
return f"<_ProfiledLock({self.__wrapped__!r}) at {self._self_init_loc}>"
90+
return f"<_ProfiledLock({self.__wrapped__!r}) at {self.init_location}>"
9191

9292
### Regular methods ###
9393

@@ -105,17 +105,17 @@ def __aenter__(self, *args: Any, **kwargs: Any) -> Any:
105105
return self._acquire(self.__wrapped__.__aenter__, *args, **kwargs)
106106

107107
def _acquire(self, inner_func: Callable[..., Any], *args: Any, **kwargs: Any) -> Any:
108-
if not self._self_capture_sampler.capture():
108+
if not self.capture_sampler.capture():
109109
return inner_func(*args, **kwargs)
110110

111111
start: int = time.monotonic_ns()
112112
try:
113113
return inner_func(*args, **kwargs)
114114
finally:
115115
end: int = time.monotonic_ns()
116-
self._self_acquired_at = end
116+
self.acquired_time = end
117117
try:
118-
self._maybe_update_self_name()
118+
self._update_name()
119119
self._flush_sample(start, end, is_acquire=True)
120120
except AssertionError:
121121
if config.enable_asserts:
@@ -135,15 +135,15 @@ def __aexit__(self, *args: Any, **kwargs: Any) -> Any:
135135
return self._release(self.__wrapped__.__aexit__, *args, **kwargs)
136136

137137
def _release(self, inner_func: Callable[..., Any], *args: Any, **kwargs: Any) -> None:
138-
start: Optional[int] = getattr(self, "_self_acquired_at", None)
138+
start: Optional[int] = getattr(self, "acquired_time", None)
139139
try:
140140
# Though it should generally be avoided to call release() from
141141
# multiple threads, it is possible to do so. In that scenario, the
142142
# following statement code will raise an AttributeError. This should
143143
# not be propagated to the caller and to the users. The inner_func
144144
# will raise an RuntimeError as the threads are trying to release()
145145
# and unlocked lock, and the expected behavior is to propagate that.
146-
del self._self_acquired_at
146+
del self.acquired_time
147147
except AttributeError:
148148
pass
149149

@@ -165,7 +165,7 @@ def _flush_sample(self, start: int, end: int, is_acquire: bool) -> None:
165165

166166
handle.push_monotonic_ns(end)
167167

168-
lock_name: str = f"{self._self_init_loc}:{self._self_name}" if self._self_name else self._self_init_loc
168+
lock_name: str = f"{self.init_location}:{self.name}" if self.name else self.init_location
169169
handle.push_lock_name(lock_name)
170170

171171
duration_ns: int = end - start
@@ -189,20 +189,20 @@ def _flush_sample(self, start: int, end: int, is_acquire: bool) -> None:
189189
thread_native_id: int = _threading.get_thread_native_id(thread_id)
190190
handle.push_threadinfo(thread_id, thread_native_id, thread_name)
191191

192-
if self._self_tracer is not None:
193-
handle.push_span(self._self_tracer.current_span())
192+
if self.tracer is not None:
193+
handle.push_span(self.tracer.current_span())
194194

195195
# If we can't get the task frame, we use the caller frame.
196196
# Call stack: 0: _flush_sample, 1: _acquire/_release, 2: acquire/release/__enter__/__exit__, 3: caller
197197
frame: FrameType = task_frame or sys._getframe(3)
198198
frames: List[DDFrame]
199-
frames, _ = _traceback.pyframe_to_frames(frame, self._self_max_nframes)
199+
frames, _ = _traceback.pyframe_to_frames(frame, self.max_nframes)
200200
for ddframe in frames:
201201
handle.push_frame(ddframe.function_name, ddframe.file_name, 0, ddframe.lineno)
202202

203203
handle.flush_sample()
204204

205-
def _find_self_name(self, var_dict: Dict[str, Any]) -> Optional[str]:
205+
def _find_name(self, var_dict: Dict[str, Any]) -> Optional[str]:
206206
for name, value in var_dict.items():
207207
if name.startswith("__") or isinstance(value, ModuleType):
208208
continue
@@ -212,7 +212,6 @@ def _find_self_name(self, var_dict: Dict[str, Any]) -> Optional[str]:
212212
for attribute in dir(value):
213213
try:
214214
if not attribute.startswith("__") and getattr(value, attribute) is self:
215-
self._self_name = attribute
216215
return attribute
217216
except AttributeError:
218217
# Accessing unset attributes in __slots__ raises AttributeError.
@@ -221,8 +220,8 @@ def _find_self_name(self, var_dict: Dict[str, Any]) -> Optional[str]:
221220

222221
# Get lock acquire/release call location and variable name the lock is assigned to
223222
# This function propagates ValueError if the frame depth is <= 3.
224-
def _maybe_update_self_name(self) -> None:
225-
if self._self_name is not None:
223+
def _update_name(self) -> None:
224+
if self.name is not None:
226225
return
227226
# We expect the call stack to be like this:
228227
# 0: this
@@ -240,7 +239,7 @@ def _maybe_update_self_name(self) -> None:
240239

241240
# First, look at the local variables of the caller frame, and then the global variables
242241
frame = sys._getframe(3)
243-
self._self_name = self._find_self_name(frame.f_locals) or self._find_self_name(frame.f_globals) or ""
242+
self.name = self._find_name(frame.f_locals) or self._find_name(frame.f_globals) or ""
244243

245244

246245
class _LockAllocatorWrapper:

tests/profiling_v2/collector/test_threading.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -351,8 +351,8 @@ def test_assertion_error_raised_with_enable_asserts():
351351
with ThreadingLockCollector(capture_pct=100):
352352
lock = threading.Lock()
353353

354-
# Patch _maybe_update_self_name to raise AssertionError
355-
lock._maybe_update_self_name = mock.Mock(side_effect=AssertionError("test: unexpected frame in stack"))
354+
# Patch _update_name to raise AssertionError
355+
lock._update_name = mock.Mock(side_effect=AssertionError("test: unexpected frame in stack"))
356356

357357
with pytest.raises(AssertionError):
358358
# AssertionError should be propagated when enable_asserts=True
@@ -380,18 +380,18 @@ def test_all_exceptions_suppressed_by_default() -> None:
380380
with ThreadingLockCollector(capture_pct=100):
381381
lock = threading.Lock()
382382

383-
# Patch _maybe_update_self_name to raise AssertionError
384-
lock._maybe_update_self_name = mock.Mock(side_effect=AssertionError("Unexpected frame in stack: 'fubar'"))
383+
# Patch _update_name to raise AssertionError
384+
lock._update_name = mock.Mock(side_effect=AssertionError("Unexpected frame in stack: 'fubar'"))
385385
lock.acquire()
386386
lock.release()
387387

388-
# Patch _maybe_update_self_name to raise RuntimeError
389-
lock._maybe_update_self_name = mock.Mock(side_effect=RuntimeError("Some profiling error"))
388+
# Patch _update_name to raise RuntimeError
389+
lock._update_name = mock.Mock(side_effect=RuntimeError("Some profiling error"))
390390
lock.acquire()
391391
lock.release()
392392

393-
# Patch _maybe_update_self_name to raise Exception
394-
lock._maybe_update_self_name = mock.Mock(side_effect=Exception("Wut happened?!?!"))
393+
# Patch _update_name to raise Exception
394+
lock._update_name = mock.Mock(side_effect=Exception("Wut happened?!?!"))
395395
lock.acquire()
396396
lock.release()
397397

@@ -1157,12 +1157,12 @@ def test_lock_slots_enforced(self) -> None:
11571157
# Verify all expected attributes are in __slots__
11581158
expected_slots: set[str] = {
11591159
"__wrapped__",
1160-
"_self_tracer",
1161-
"_self_max_nframes",
1162-
"_self_capture_sampler",
1163-
"_self_init_loc",
1164-
"_self_acquired_at",
1165-
"_self_name",
1160+
"tracer",
1161+
"max_nframes",
1162+
"capture_sampler",
1163+
"init_location",
1164+
"acquired_time",
1165+
"name",
11661166
}
11671167
assert set(_ProfiledLock.__slots__) == expected_slots
11681168

0 commit comments

Comments
 (0)