FazBrowse GitHub Viewer
|
Trending
|
URL:
|
Home
Tools:
[Download Repo ZIP]
[View Raw Code]
[Original HTTPS Page]
cpython/Tools/scripts/combinerefs.py at master · python-emscripten/cpython · GitHub
python-emscripten
cpython
Repository navigation
Code
Pull requests
Actions
Projects
Security and quality
Insights
Expand file tree
Breadcrumbs
cpython
/
Tools
/
scripts
/
combinerefs.py
Copy path
More file actions
More file actions
Latest commit
History
History
History
executable file
·
129 lines (98 loc) · 4.35 KB
Breadcrumbs
cpython
/
Tools
/
scripts
/
combinerefs.py
Copy path
File metadata and controls
executable file
·
129 lines (98 loc) · 4.35 KB
Raw
Copy raw file
Download raw file
Open symbols panel
Edit and raw actions
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#! /usr/bin/env python3
"""
combinerefs path
A helper for analyzing PYTHONDUMPREFS output.
When the PYTHONDUMPREFS envar is set in a debug build, at Python shutdown
time Py_FinalizeEx() prints the list of all live objects twice: first it
prints the repr() of each object while the interpreter is still fully intact.
After cleaning up everything it can, it prints all remaining live objects
again, but the second time just prints their addresses, refcounts, and type
names (because the interpreter has been torn down, calling repr methods at
this point can get into infinite loops or blow up).
Save all this output into a file, then run this script passing the path to
that file. The script finds both output chunks, combines them, then prints
a line of output for each object still alive at the end:
address refcnt typename repr
address is the address of the object, in whatever format the platform C
produces for a %p format code.
refcnt is of the form
"[" ref "]"
when the object's refcount is the same in both PYTHONDUMPREFS output blocks,
or
"[" ref_before "->" ref_after "]"
if the refcount changed.
typename is object->ob_type->tp_name, extracted from the second PYTHONDUMPREFS
output block.
repr is repr(object), extracted from the first PYTHONDUMPREFS output block.
CAUTION: If object is a container type, it may not actually contain all the
objects shown in the repr: the repr was captured from the first output block,
and some of the containees may have been released since then. For example,
it's common for the line showing the dict of interned strings to display
strings that no longer exist at the end of Py_FinalizeEx; this can be recognized
(albeit painfully) because such containees don't have a line of their own.
The objects are listed in allocation order, with most-recently allocated
printed first, and the first object allocated printed last.
Simple examples:
00857060 [14] str '__len__'
The str object '__len__' is alive at shutdown time, and both PYTHONDUMPREFS
output blocks said there were 14 references to it. This is probably due to
C modules that intern the string "__len__" and keep a reference to it in a
file static.
00857038 [46->5] tuple ()
46-5 = 41 references to the empty tuple were removed by the cleanup actions
between the times PYTHONDUMPREFS produced output.
00858028 [1025->1456] str '<dummy key>'
The string '<dummy key>', which is used in dictobject.c to overwrite a real
key that gets deleted, grew several hundred references during cleanup. It
suggests that stuff did get removed from dicts by cleanup, but that the dicts
themselves are staying alive for some reason. """
import
re
import
sys
# Generate lines from fileiter. If whilematch is true, continue reading
# while the regexp object pat matches line. If whilematch is false, lines
# are read so long as pat doesn't match them. In any case, the first line
# that doesn't match pat (when whilematch is true), or that does match pat
# (when whilematch is false), is lost, and fileiter will resume at the line
# following it.
def
read
(
fileiter
,
pat
,
whilematch
):
for
line
in
fileiter
:
if
bool
(
pat
.
match
(
line
))
==
whilematch
:
yield
line
else
:
break
def
combinefile
(
f
):
fi
=
iter
(
f
)
for
line
in
read
(
fi
,
re
.
compile
(
r'^Remaining objects:$'
),
False
):
pass
crack
=
re
.
compile
(
r'([a-zA-Z\d]+) \[(\d+)\] (.*)'
)
addr2rc
=
{}
addr2guts
=
{}
before
=
0
for
line
in
read
(
fi
,
re
.
compile
(
r'^Remaining object addresses:$'
),
False
):
m
=
crack
.
match
(
line
)
if
m
:
addr
,
addr2rc
[
addr
],
addr2guts
[
addr
]
=
m
.
groups
()
before
+=
1
else
:
print
(
'??? skipped:'
,
line
)
after
=
0
for
line
in
read
(
fi
,
crack
,
True
):
after
+=
1
m
=
crack
.
match
(
line
)
assert
m
addr
,
rc
,
guts
=
m
.
groups
()
# guts is type name here
if
addr
not
in
addr2rc
:
print
(
'??? new object created while tearing down:'
,
line
.
rstrip
())
continue
print
(
addr
,
end
=
' '
)
if
rc
==
addr2rc
[
addr
]:
print
(
'[%s]'
%
rc
,
end
=
' '
)
else
:
print
(
'[%s->%s]'
%
(
addr2rc
[
addr
],
rc
),
end
=
' '
)
print
(
guts
,
addr2guts
[
addr
])
print
(
"%d objects before, %d after"
%
(
before
,
after
))
def
combine
(
fname
):
with
open
(
fname
)
as
f
:
combinefile
(
f
)
if
__name__
==
'__main__'
:
combine
(
sys
.
argv
[
1
])
Back
|
FazBrowse Home
|
New Git URL