4 use File::Basename qw(&dirname);
7 use Statistics::Basic::StdDev;
14 open F,"$fname" or die $fname;
16 defined(my $r=<F>) or die $fname;
17 close F or die $fname;
22 if (($ARGV[0]||"") eq "-r") {
25 $R{$1}=1 while $r=~s/^(.*?)\n//;
30 # ==> build/Cadence-1.0.0-0.12.20200504git5787908.fc33.src.rpm.dtneeded <==
31 # /usr/lib/debug/.dwz/Cadence isdwzcommon 479079 NA
32 # /usr/bin/cadence-jackmeter /usr/lib/debug/.dwz/Cadence 717792 1329040
33 # /usr/bin/cadence-xycontroller /usr/lib/debug/.dwz/Cadence 1763616 2369832
34 # ==> build/CVector-1.0.3.1-21.fc33.src.rpm.dtneeded <==
35 # /usr/lib64/libCVector-1.0.3.so.2.0.0 nodwzcommon 28088 28896
36 for my $dtneededfn (glob "build/*.dtneeded") {
37 next if %R && !$R{($dtneededfn=~m{^build/(.*?)-[^-]*-[^-]*$})[0]."-debuginfo"};
39 open F,$dtneededfn or die "$dtneededfn: $1";
43 my($fn,$dwzcommon,$dwzsize,$dtsize)=/^(\S+) (\S+) (\S+) (\S+)$/ or die "$dtneededfn: $_";
44 die if $dwzcommon eq "isdwzcommon" && $dtsize ne "NA";
47 die if $dwzcommon eq "isdwzcommon";
50 $$ref=[$dwzcommon,$dwzsize,$dtsize];
53 close F or die "close $dtneededfn: $1";
56 chdir "dtneeded.out" or die "dtneeded.out: $!";
65 die $File::Find::dir if $File::Find::dir=~m{/$};
66 my $binfn=$File::Find::name;
68 my $target=readlink $binfn or die $binfn;
73 #warn "$binfn,target=rel=$$ref\n";
75 my $base=dirname(".$binfn");
76 my $abs=File::Spec->rel2abs($target,$base);
77 $final="/".File::Spec->abs2rel($abs);
78 #warn "$binfn,base=$base,target=$target,abs=$abs,rel=$$ref\n";
80 1 while $final=~s{/[^/]+/[.][.]/}{/};
81 1 while $final=~s{/[^/]+/[.][.]$}{};
82 if ($final=~m{/[.][.]}) {
83 warn "$binfn,target=$target,final=$final\n";
86 my $ref=\$SYMLINK{$binfn};
92 die $binfn if $binfn!~m{^[.]/};
93 my $bin=readfile $binfn;
94 $binfn=~s{^[.]}{} or die;
95 my $rpath=($bin=~m{^.*\Q(R\E(?:UN)?\QPATH)\E\s*Library r(?:un)?path: \Q[\E(.*)\Q]\E$}m)[0];
97 my $dirname=$File::Find::dir;
98 die if $dirname!~s{^[.]/}{/};
99 $rpath=~s{\$ORIGIN}{$dirname}g;
101 my $soname=($bin=~m{^.*\Q(SONAME)\E\s*Library soname: \Q[\E(.*)\Q]\E$}m)[0];
104 "needed"=>[$bin=~m{^\s*0x0000000000000001\s*\Q(NEEDED)\E\s*\QShared library: [\E(.*)\Q]\E$}gm],
106 $h->{"rpath"}=$rpath if $rpath;
108 #warn "$binfn=".Dumper($h)."\n" if $binfn=~/libc.so.6/;
109 # my $total=keys %F; warn "$total...\n" if 0==$total%1000;
111 my $sonamefn=$File::Find::dir."/".$soname;
112 $sonamefn=~s{^[.]/}{/} or die $sonamefn;
113 my $ref=\$SONAME{$sonamefn};
114 # warn "soname=<$sonamefn> <$binfn> vs. <".$$ref->{"binfn"}.">\n" if $$ref;
117 push @DEBUG,$binfn if $bin=~m{ \Q(DEBUG) \E };
121 #while (my($src,$target)=each %SYMLINK) {
122 # die "$src->$target" if exists $SYMLINK{$target};
126 my $dwzsizeduplall=0;
131 BINFN: for my $binfn (@DEBUG) {
132 # warn "$binfn...\n".Dumper([sort @{$F{$binfn}{"needed"}}]);
133 die $binfn if exists $SYMLINK{$binfn};
139 for my $needed (@{$h->{"needed"}}) {
141 if ($needed=~m{^/}) {
142 $needed=$SYMLINK{$needed} while exists $SYMLINK{$needed};
145 # die "$binfn: $l: $needed" if $needed=~m{/};
147 my $rpath=$h->{"rpath"};
148 push @rpath,split /:/,$rpath if $rpath;
149 push @rpath,qw(/lib64 /usr/lib64);
150 for my $rpath (@rpath) {
152 warn "$binfn: $l: $rpath";
155 my $fn="$rpath/$needed";
156 $fn=$SYMLINK{$fn} while exists $SYMLINK{$fn};
157 next if !$SONAME{$fn};
161 warn "$binfn: $l: $needed not found; rpath=".join(":",@rpath)."\n" if !$found;
163 push @l,$found if $found&&!$l{$found}++;
166 #warn Dumper $binfn,\%l;
168 my $dwzsizedupltot=0;
171 for my $l (keys(%l)) {
174 warn "$binfn: $l: missing\n";
178 warn "$binfn: $l: ambiguous\n";
181 my $dtsize=$ref->[2];
182 die if !defined $dtsize;
184 my $dwzsize=$ref->[1];
185 die if !defined $dwzsize;
186 $dwzsizetot+=$dwzsize;
187 $dwzsizedupltot+=$dwzsize;
189 my $dwzcommon=$ref->[0];
190 next if $dwzcommon eq "nodwzcommon";
191 die if $dwzcommon eq "isdwzcommon";
192 my $duplicate=$dwzcommons{$dwzcommon}++;
193 my $dwzcommonref=$D{$dwzcommon};
194 die if !$dwzcommonref;
195 die if $dwzcommonref->[0] ne "isdwzcommon";
196 die if $dwzcommonref->[2] ne "NA";
197 my $dwzcommonsize=$dwzcommonref->[1];
198 $dwzsizetot+=$dwzcommonsize if !$duplicate;
199 $dwzsizedupltot+=$dwzcommonsize;
201 print "$binfn: dwzsizetot=$dwzsizetot dtsizetot=$dtsizetot\n";
202 warn "$binfn: ".Dumper(\%dwzcommons);
203 $dwzsizeall+=$dwzsizetot;
204 $dwzsizeduplall+=$dwzsizedupltot;
205 $dtsizeall+=$dtsizetot;
206 push @ratioall ,$dwzsizetot /$dtsizetot;
207 push @ratioduplall,$dwzsizedupltot/$dtsizetot;
208 # warn "$binfn done\n".Dumper([sort keys(%l)]);
210 print "dwzsizeall =$dwzsizeall" ." dtsizeall=$dtsizeall =".$dwzsizeall /$dtsizeall." avg=".List::Util::sum(@ratioall )/@ratioall ." stddev=".Statistics::Basic::stddev(\@ratioall )."\n";
211 print "dwzsizeduplall=$dwzsizeduplall"." dtsizeall=$dtsizeall =".$dwzsizeduplall/$dtsizeall." avg=".List::Util::sum(@ratioduplall)/@ratioduplall." stddev=".Statistics::Basic::stddev(\@ratioduplall)."\n";
212 print "computed=$computed of DEBUG=".(0+@DEBUG)." =".$computed/@DEBUG."\n";
213 #print Dumper \@ratioall;