4
4
import os
5
5
import sys
6
6
7
- def get_defined_symbols (fname : str ) -> Dict [str , int ]:
7
+
8
+ def get_defined_symbols (fname : str , verbose : bool = False ) -> Dict [str , int ]:
9
+ if verbose :
10
+ print (f"Processing { fname } ..." , end = '' , flush = True )
8
11
if sys .platform == 'darwin' :
9
12
lines = check_output (['nm' , '--defined-only' , '-n' , fname ]).decode ('ascii' ).split ("\n " )[:- 1 ]
10
13
rc = {}
11
14
for idx , line in enumerate (lines ):
12
- addr , stype , name = line .split (" " )
13
- size = 4 if idx + 1 == len (lines ) else (int (lines [idx + 1 ].split (" " )[0 ], 16 ) - int (addr , 16 ))
15
+ addr , stype , name = line .split (' ' )
16
+ size = 4 if idx + 1 == len (lines ) else (int (lines [idx + 1 ].split (' ' )[0 ], 16 ) - int (addr , 16 ))
14
17
rc [name ] = size
15
- return rc
16
- lines = check_output (['nm' , '--print-size' , '--defined-only' , fname ]).decode ('ascii' ).split ("\n " )
17
- return {e [3 ]:int (e [1 ], 16 ) for e in [l .split () for l in lines ] if len (e ) == 4 }
18
+ else :
19
+ lines = check_output (['nm' , '--print-size' , '--defined-only' , fname ]).decode ('ascii' ).split ('\n ' )
20
+ rc = {e [3 ]: int (e [1 ], 16 ) for e in [line .split () for line in lines ] if len (e ) == 4 }
21
+ if verbose :
22
+ print ("done" )
23
+ return rc
18
24
19
25
20
26
def get_deps (fname : str ) -> List [str ]:
@@ -24,12 +30,13 @@ def get_deps(fname: str) -> List[str]:
24
30
for idx , line in enumerate (lines ):
25
31
if line .strip () != 'cmd LC_LOAD_DYLIB' :
26
32
continue
27
- path = lines [idx + 2 ].strip ()
33
+ path = lines [idx + 2 ].strip ()
28
34
assert path .startswith ('name' )
29
- rc .append (os .path .basename (path .split (" " )[1 ]))
35
+ rc .append (os .path .basename (path .split (' ' )[1 ]))
30
36
return rc
31
- lines = check_output (['readelf' , '--dynamic' , fname ]).decode ('ascii' ).split ("\n " )
32
- return [line .split ("[" )[1 ][:- 1 ] for line in lines if '(NEEDED)' in line ]
37
+ lines = check_output (['readelf' , '--dynamic' , fname ]).decode ('ascii' ).split ('\n ' )
38
+ return [line .split ('[' )[1 ][:- 1 ] for line in lines if '(NEEDED)' in line ]
39
+
33
40
34
41
def humansize (size ):
35
42
if size < 1024 :
@@ -40,12 +47,11 @@ def humansize(size):
40
47
return f"{ size / (1024.0 ** 2 ):.2f} Mb"
41
48
return f"{ size / (1024.0 ** 3 ):.2f} Gb"
42
49
50
+
43
51
def print_sizes (libname , depth : int = 2 ) -> None :
44
52
libs = [libname ]
45
53
depth = 2
46
- print (f"Processing { libname } ..." , end = '' , flush = True )
47
- symbols = {os .path .basename (libname ): get_defined_symbols (libname )}
48
- print ("done" )
54
+ symbols = {os .path .basename (libname ): get_defined_symbols (libname , verbose = True )}
49
55
for _ in range (depth ):
50
56
for lib in libs :
51
57
dirname = os .path .dirname (lib )
@@ -55,9 +61,7 @@ def print_sizes(libname, depth: int = 2) -> None:
55
61
continue
56
62
if path not in libs :
57
63
libs .append (path )
58
- print (f"Processing { path } ..." , end = '' , flush = True )
59
- symbols [dep ] = get_defined_symbols (path )
60
- print ("done" )
64
+ symbols [dep ] = get_defined_symbols (path , verbose = True )
61
65
62
66
for lib in libs :
63
67
lib_symbols = symbols [os .path .basename (lib )]
@@ -72,5 +76,24 @@ def print_sizes(libname, depth: int = 2) -> None:
72
76
rc += f" { dep } overlap is { humansize (overlap_size )} "
73
77
print (rc )
74
78
79
+
80
+ def print_symbols_overlap (libname1 : str , libname2 : str ) -> None :
81
+ sym1 = get_defined_symbols (libname1 , verbose = True )
82
+ sym2 = get_defined_symbols (libname2 , verbose = True )
83
+ sym1_size = sum (sym1 .values ())
84
+ sym2_size = sum (sym2 .values ())
85
+ sym_overlap = set (sym1 .keys ()).intersection (set (sym2 .keys ()))
86
+ overlap_size = sum (sym1 [s ] for s in sym_overlap )
87
+ if overlap_size == 0 :
88
+ print (f"{ libname1 } symbols size { humansize (sym1_size )} does not overlap with { libname2 } " )
89
+ return
90
+ print (f"{ libname1 } symbols size { humansize (sym1_size )} overlap { humansize (overlap_size )} ({ 100.0 * overlap_size / sym1_size :.2f} %)" )
91
+ for sym in sym_overlap :
92
+ print (sym )
93
+
94
+
75
95
if __name__ == '__main__' :
76
- print_sizes (sys .argv [1 ] if len (sys .argv )> 1 else "lib/libtorch_cuda.so" )
96
+ if len (sys .argv ) == 3 :
97
+ print_symbols_overlap (sys .argv [1 ], sys .argv [2 ])
98
+ else :
99
+ print_sizes (sys .argv [1 ] if len (sys .argv ) > 1 else "lib/libtorch_cuda.so" )
0 commit comments