10
10
from use_lldb_suite import lldb_root
11
11
12
12
parser = argparse .ArgumentParser (
13
- description = 'Analyze LLDB project #include dependencies.' )
14
- parser .add_argument ('--show-counts' , default = False , action = 'store_true' ,
15
- help = 'When true, show the number of dependencies from each subproject' )
16
- parser .add_argument ('--discover-cycles' , default = False , action = 'store_true' ,
17
- help = 'When true, find and display all project dependency cycles. Note,'
18
- 'this option is very slow' )
13
+ description = "Analyze LLDB project #include dependencies."
14
+ )
15
+ parser .add_argument (
16
+ "--show-counts" ,
17
+ default = False ,
18
+ action = "store_true" ,
19
+ help = "When true, show the number of dependencies from each subproject" ,
20
+ )
21
+ parser .add_argument (
22
+ "--discover-cycles" ,
23
+ default = False ,
24
+ action = "store_true" ,
25
+ help = "When true, find and display all project dependency cycles. Note,"
26
+ "this option is very slow" ,
27
+ )
19
28
20
29
args = parser .parse_args ()
21
30
24
33
25
34
src_map = {}
26
35
27
- include_regex = re .compile ('#include \" ((lldb|Plugins|clang)(.*/)+).*\" ' )
36
+ include_regex = re .compile ('#include "((lldb|Plugins|clang)(.*/)+).*"' )
37
+
28
38
29
39
def is_sublist (small , big ):
30
40
it = iter (big )
31
41
return all (c in it for c in small )
32
42
43
+
33
44
def normalize_host (str ):
34
45
if str .startswith ("lldb/Host" ):
35
46
return "lldb/Host"
@@ -39,6 +50,7 @@ def normalize_host(str):
39
50
return str .replace ("lldb/../../source" , "lldb" )
40
51
return str
41
52
53
+
42
54
def scan_deps (this_dir , file ):
43
55
global src_map
44
56
deps = {}
@@ -62,7 +74,8 @@ def scan_deps(this_dir, file):
62
74
if this_dir not in src_map and len (deps ) > 0 :
63
75
src_map [this_dir ] = deps
64
76
65
- for (base , dirs , files ) in os .walk (inc_dir ):
77
+
78
+ for base , dirs , files in os .walk (inc_dir ):
66
79
dir = os .path .basename (base )
67
80
relative = os .path .relpath (base , inc_dir )
68
81
inc_files = [x for x in files if os .path .splitext (x )[1 ] in [".h" ]]
@@ -71,7 +84,7 @@ def scan_deps(this_dir, file):
71
84
inc_path = os .path .join (base , inc )
72
85
scan_deps (relative , inc_path )
73
86
74
- for ( base , dirs , files ) in os .walk (src_dir ):
87
+ for base , dirs , files in os .walk (src_dir ):
75
88
dir = os .path .basename (base )
76
89
relative = os .path .relpath (base , src_dir )
77
90
src_files = [x for x in files if os .path .splitext (x )[1 ] in [".cpp" , ".h" , ".mm" ]]
@@ -82,6 +95,7 @@ def scan_deps(this_dir, file):
82
95
scan_deps (norm_base_path , src_path )
83
96
pass
84
97
98
+
85
99
def is_existing_cycle (path , cycles ):
86
100
# If we have a cycle like # A -> B -> C (with an implicit -> A at the end)
87
101
# then we don't just want to check for an occurrence of A -> B -> C in the
@@ -90,12 +104,13 @@ def is_existing_cycle(path, cycles):
90
104
# at the end), then A -> B -> C is also a cycle. This is an important
91
105
# optimization which reduces the search space by multiple orders of
92
106
# magnitude.
93
- for i in range (0 ,len (path )):
107
+ for i in range (0 , len (path )):
94
108
if any (is_sublist (x , path ) for x in cycles ):
95
109
return True
96
110
path = [path [- 1 ]] + path [0 :- 1 ]
97
111
return False
98
112
113
+
99
114
def expand (path_queue , path_lengths , cycles , src_map ):
100
115
# We do a breadth first search, to make sure we visit all paths in order
101
116
# of ascending length. This is an important optimization to make sure that
@@ -127,54 +142,57 @@ def expand(path_queue, path_lengths, cycles, src_map):
127
142
path_queue .append (cur_path + [item ])
128
143
pass
129
144
145
+
130
146
cycles = []
131
147
132
148
path_queue = [[x ] for x in iter (src_map )]
133
149
path_lens = [1 ] * len (path_queue )
134
150
135
151
items = list (src_map .items ())
136
- items .sort (key = lambda A : A [0 ])
152
+ items .sort (key = lambda A : A [0 ])
137
153
138
- for ( path , deps ) in items :
154
+ for path , deps in items :
139
155
print (path + ":" )
140
156
sorted_deps = list (deps .items ())
141
157
if args .show_counts :
142
- sorted_deps .sort (key = lambda A : (A [1 ], A [0 ]))
158
+ sorted_deps .sort (key = lambda A : (A [1 ], A [0 ]))
143
159
for dep in sorted_deps :
144
160
print ("\t {} [{}]" .format (dep [0 ], dep [1 ]))
145
161
else :
146
- sorted_deps .sort (key = lambda A : A [0 ])
162
+ sorted_deps .sort (key = lambda A : A [0 ])
147
163
for dep in sorted_deps :
148
164
print ("\t {}" .format (dep [0 ]))
149
165
166
+
150
167
def iter_cycles (cycles ):
151
168
global src_map
152
169
for cycle in cycles :
153
170
cycle .append (cycle [0 ])
154
171
zipper = list (zip (cycle [0 :- 1 ], cycle [1 :]))
155
- result = [(x , src_map [x ][y ], y ) for (x ,y ) in zipper ]
172
+ result = [(x , src_map [x ][y ], y ) for (x , y ) in zipper ]
156
173
total = 0
157
174
smallest = result [0 ][1 ]
158
- for ( first , value , last ) in result :
175
+ for first , value , last in result :
159
176
total += value
160
177
smallest = min (smallest , value )
161
178
yield (total , smallest , result )
162
179
180
+
163
181
if args .discover_cycles :
164
182
print ("Analyzing cycles..." )
165
183
166
184
expand (path_queue , path_lens , cycles , src_map )
167
185
168
- average = sum ([len (x )+ 1 for x in cycles ]) / len (cycles )
186
+ average = sum ([len (x ) + 1 for x in cycles ]) / len (cycles )
169
187
170
188
print ("Found {} cycles. Average cycle length = {}." .format (len (cycles ), average ))
171
189
counted = list (iter_cycles (cycles ))
172
190
if args .show_counts :
173
- counted .sort (key = lambda A : A [0 ])
174
- for ( total , smallest , cycle ) in counted :
191
+ counted .sort (key = lambda A : A [0 ])
192
+ for total , smallest , cycle in counted :
175
193
sys .stdout .write ("{} deps to break: " .format (total ))
176
194
sys .stdout .write (cycle [0 ][0 ])
177
- for ( first , count , last ) in cycle :
195
+ for first , count , last in cycle :
178
196
sys .stdout .write (" [{}->] {}" .format (count , last ))
179
197
sys .stdout .write ("\n " )
180
198
else :
@@ -186,8 +204,8 @@ def iter_cycles(cycles):
186
204
islands = []
187
205
outgoing_counts = defaultdict (int )
188
206
incoming_counts = defaultdict (int )
189
- for ( total , smallest , cycle ) in counted :
190
- for ( first , count , last ) in cycle :
207
+ for total , smallest , cycle in counted :
208
+ for first , count , last in cycle :
191
209
outgoing_counts [first ] += count
192
210
incoming_counts [last ] += count
193
211
for cycle in cycles :
@@ -201,8 +219,8 @@ def iter_cycles(cycles):
201
219
sorted = []
202
220
for node in island :
203
221
sorted .append ((node , incoming_counts [node ], outgoing_counts [node ]))
204
- sorted .sort (key = lambda x : x [1 ]+ x [2 ])
205
- for ( node , inc , outg ) in sorted :
222
+ sorted .sort (key = lambda x : x [1 ] + x [2 ])
223
+ for node , inc , outg in sorted :
206
224
print (" {} [{} in, {} out]" .format (node , inc , outg ))
207
225
sys .stdout .flush ()
208
226
pass
0 commit comments