45
45
46
46
# pylint: disable=unused-argument
47
47
48
- # $set_env.py: COVERAGE_LOG_SYSMON - Log sys.monitoring activity
49
- LOG = bool (int (os .getenv ("COVERAGE_LOG_SYSMON" , 0 )))
48
+ # $set_env.py: COVERAGE_SYSMON_LOG - Log sys.monitoring activity
49
+ LOG = bool (int (os .getenv ("COVERAGE_SYSMON_LOG" , 0 )))
50
+
51
+ # $set_env.py: COVERAGE_SYSMON_STATS - Collect sys.monitoring stats
52
+ COLLECT_STATS = bool (int (os .getenv ("COVERAGE_SYSMON_STATS" , 0 )))
50
53
51
54
# This module will be imported in all versions of Python, but only used in 3.12+
52
55
# It will be type-checked for 3.12, but not for earlier versions.
@@ -236,17 +239,17 @@ def populate_branch_trails(code: CodeType, code_info: CodeInfo) -> None:
236
239
arc from the original instruction's line to the new source line.
237
240
238
241
"""
239
- log (f"populate_branch_trails: { code } " )
242
+ # log(f"populate_branch_trails: {code}")
240
243
iwalker = InstructionWalker (code )
241
244
for inst in iwalker .walk (follow_jumps = False ):
242
- log (f"considering { inst = } " )
245
+ # log(f"considering {inst=}")
243
246
if not inst .jump_target :
244
247
# We only care about instructions with jump targets.
245
- log ("no jump_target" )
248
+ # log("no jump_target")
246
249
continue
247
250
if inst .opcode in ALWAYS_JUMPS :
248
251
# We don't care about unconditional jumps.
249
- log ("always jumps" )
252
+ # log("always jumps")
250
253
continue
251
254
252
255
from_line = inst .line_number
@@ -265,23 +268,23 @@ def walk_one_branch(
265
268
to_line = inst2 .line_number
266
269
break
267
270
elif inst2 .jump_target and (inst2 .opcode not in ALWAYS_JUMPS ):
268
- log (
269
- f"stop: { inst2 .jump_target = } , "
270
- + f"{ inst2 .opcode = } ({ dis .opname [inst2 .opcode ]} ), "
271
- + f"{ ALWAYS_JUMPS = } "
272
- )
271
+ # log(
272
+ # f"stop: {inst2.jump_target=}, "
273
+ # + f"{inst2.opcode=} ({dis.opname[inst2.opcode]}), "
274
+ # + f"{ALWAYS_JUMPS=}"
275
+ # )
273
276
break
274
277
elif inst2 .opcode in RETURNS :
275
278
to_line = - code .co_firstlineno
276
279
break
277
280
if to_line is not None :
278
- log (
279
- f"possible branch from @{ start_at } : "
280
- + f"{ inst_offsets } , { (from_line , to_line )} { code } "
281
- )
281
+ # log(
282
+ # f"possible branch from @{start_at}: "
283
+ # + f"{inst_offsets}, {(from_line, to_line)} {code}"
284
+ # )
282
285
return inst_offsets , (from_line , to_line )
283
286
else :
284
- log (f"no possible branch from @{ start_at } : { inst_offsets } " )
287
+ # log(f"no possible branch from @{start_at}: {inst_offsets}")
285
288
return [], None
286
289
287
290
# Calculate two trails: one from the next instruction, and one from the
@@ -302,6 +305,7 @@ def walk_one_branch(
302
305
code_info .branch_trails [offset ] = []
303
306
code_info .branch_trails [offset ].append (trail )
304
307
308
+
305
309
@dataclass
306
310
class CodeInfo :
307
311
"""The information we want about each code object."""
@@ -363,9 +367,11 @@ def __init__(self, tool_id: int) -> None:
363
367
self .sysmon_on = False
364
368
self .lock = threading .Lock ()
365
369
366
- self .stats = {
367
- "starts" : 0 ,
368
- }
370
+ self .stats : dict [str , int ] | None = None
371
+ if COLLECT_STATS :
372
+ self .stats = {
373
+ "starts" : 0 ,
374
+ }
369
375
370
376
self .stopped = False
371
377
self ._activity = False
@@ -431,7 +437,7 @@ def reset_activity(self) -> None:
431
437
432
438
def get_stats (self ) -> dict [str , int ] | None :
433
439
"""Return a dictionary of statistics, or None."""
434
- return None
440
+ return self . stats
435
441
436
442
@panopticon ("code" , "@" )
437
443
def sysmon_py_start ( # pylint: disable=useless-return
@@ -440,7 +446,8 @@ def sysmon_py_start( # pylint: disable=useless-return
440
446
"""Handle sys.monitoring.events.PY_START events."""
441
447
# Entering a new frame. Decide if we should trace in this file.
442
448
self ._activity = True
443
- self .stats ["starts" ] += 1
449
+ if self .stats is not None :
450
+ self .stats ["starts" ] += 1
444
451
445
452
code_info = self .code_infos .get (id (code ))
446
453
tracing_code : bool | None = None
@@ -483,9 +490,6 @@ def sysmon_py_start( # pylint: disable=useless-return
483
490
branch_trails = {},
484
491
)
485
492
self .code_infos [id (code )] = code_info
486
- if self .trace_arcs :
487
- populate_branch_trails (code , code_info )
488
- log (f"branch_trails for { code } :\n { code_info .branch_trails } " )
489
493
self .code_objects .append (code )
490
494
491
495
if tracing_code :
@@ -519,7 +523,7 @@ def sysmon_py_return( # pylint: disable=useless-return
519
523
if last_line is not None :
520
524
arc = (last_line , - code .co_firstlineno )
521
525
cast (set [TArc ], code_info .file_data ).add (arc )
522
- log (f"adding { arc = } " )
526
+ # log(f"adding {arc=}")
523
527
return None
524
528
525
529
@panopticon ("code" , "line" )
@@ -528,7 +532,7 @@ def sysmon_line_lines(self, code: CodeType, line_number: TLineNo) -> MonitorRetu
528
532
code_info = self .code_infos .get (id (code ))
529
533
if code_info is not None and code_info .file_data is not None :
530
534
cast (set [TLineNo ], code_info .file_data ).add (line_number )
531
- log (f"adding { line_number = } " )
535
+ # log(f"adding {line_number=}")
532
536
return DISABLE
533
537
534
538
@panopticon ("code" , "line" )
@@ -538,7 +542,7 @@ def sysmon_line_arcs(self, code: CodeType, line_number: TLineNo) -> MonitorRetur
538
542
if code_info .file_data is not None :
539
543
arc = (line_number , line_number )
540
544
cast (set [TArc ], code_info .file_data ).add (arc )
541
- log (f"adding { arc = } " )
545
+ # log(f"adding {arc=}")
542
546
return DISABLE
543
547
544
548
@panopticon ("code" , "@" , "@" )
@@ -547,28 +551,31 @@ def sysmon_branch_either(
547
551
) -> MonitorReturn :
548
552
"""Handle BRANCH_RIGHT and BRANCH_LEFT events."""
549
553
code_info = self .code_infos [id (code )]
550
- added_arc = False
551
554
if code_info .file_data is not None :
555
+ if not code_info .branch_trails :
556
+ populate_branch_trails (code , code_info )
557
+ # log(f"branch_trails for {code}:\n {code_info.branch_trails}")
558
+ added_arc = False
552
559
dest_info = code_info .branch_trails .get (instruction_offset )
553
- log (f"{ dest_info = } " )
560
+ # log(f"{dest_info = }")
554
561
if dest_info is not None :
555
562
for offsets , arc in dest_info :
556
563
if arc is None :
557
564
continue
558
565
if destination_offset in offsets :
559
566
cast (set [TArc ], code_info .file_data ).add (arc )
560
- log (f"adding { arc = } " )
567
+ # log(f"adding {arc=}")
561
568
added_arc = True
562
569
break
563
570
564
- if not added_arc :
565
- # This could be an exception jumping from line to line.
566
- assert code_info .byte_to_line is not None
567
- l1 = code_info .byte_to_line [instruction_offset ]
568
- l2 = code_info .byte_to_line [destination_offset ]
569
- if l1 != l2 :
570
- arc = (l1 , l2 )
571
- cast (set [TArc ], code_info .file_data ).add (arc )
572
- log (f"adding unforeseen { arc = } " )
571
+ if not added_arc :
572
+ # This could be an exception jumping from line to line.
573
+ assert code_info .byte_to_line is not None
574
+ l1 = code_info .byte_to_line [instruction_offset ]
575
+ l2 = code_info .byte_to_line [destination_offset ]
576
+ if l1 != l2 :
577
+ arc = (l1 , l2 )
578
+ cast (set [TArc ], code_info .file_data ).add (arc )
579
+ # log(f"adding unforeseen {arc=}")
573
580
574
581
return DISABLE
0 commit comments