61ea9b8294c5b69b70ce7a64bfee5558f5375461
[massrebuild.git] / dtneededsize
1 #! /usr/bin/perl
2 use strict;
3 use warnings;
4 use File::Basename qw(&dirname);
5 use File::Find;
6 use Data::Dumper;
7 use Statistics::Basic::StdDev;
8 use List::Util;
9
10 $|=1;
11 sub readfile {
12   my($fname)=@_;
13   local *F;
14   open F,"$fname" or die $fname;
15   local $/=undef();
16   defined(my $r=<F>) or die $fname;
17   close F or die $fname;
18   return $r;
19 }
20
21 my %D;
22 # ==> build/Cadence-1.0.0-0.12.20200504git5787908.fc33.src.rpm.dtneeded <==
23 # /usr/lib/debug/.dwz/Cadence isdwzcommon 479079 NA
24 # /usr/bin/cadence-jackmeter /usr/lib/debug/.dwz/Cadence 717792 1329040
25 # /usr/bin/cadence-xycontroller /usr/lib/debug/.dwz/Cadence 1763616 2369832
26 # ==> build/CVector-1.0.3.1-21.fc33.src.rpm.dtneeded <==
27 # /usr/lib64/libCVector-1.0.3.so.2.0.0 nodwzcommon 28088 28896
28 for my $dtneededfn (glob "build/*.dtneeded") {
29   local *F;
30   open F,$dtneededfn or die "$dtneededfn: $1";
31   local $_;
32   while (<F>) {
33     chomp;
34     my($fn,$dwzcommon,$dwzsize,$dtsize)=/^(\S+) (\S+) (\S+) (\S+)$/ or die "$dtneededfn: $_";
35     die if $dwzcommon eq "isdwzcommon" && $dtsize ne "NA";
36     my $ref=\$D{$fn};
37     if ($$ref) {
38       die if $dwzcommon eq "isdwzcommon";
39       $$ref=[];
40     } else {
41       $$ref=[$dwzcommon,$dwzsize,$dtsize];
42     }
43   }
44   close F or die "close $dtneededfn: $1";
45 }
46
47 chdir "dtneeded.out" or die "dtneeded.out: $!";
48
49 my %F;
50 my %SONAME;
51 my @DEBUG;
52 my %SYMLINK;
53 find {
54   "no_chdir"=>1,
55   "wanted"=>sub {
56     die $File::Find::dir if $File::Find::dir=~m{/$};
57     my $binfn=$File::Find::name;
58     if (-l $binfn) {
59       my $target=readlink $binfn or die $binfn;
60       $binfn=~s{^[.]}{};
61       my $final;
62       if ($target=~m{^/}) {
63         $final=$target;
64 #warn "$binfn,target=rel=$$ref\n";
65       } else {
66         my $base=dirname(".$binfn");
67         my $abs=File::Spec->rel2abs($target,$base);
68         $final="/".File::Spec->abs2rel($abs);
69 #warn "$binfn,base=$base,target=$target,abs=$abs,rel=$$ref\n";
70       }
71       1 while $final=~s{/[^/]+/[.][.]/}{/};
72       1 while $final=~s{/[^/]+/[.][.]$}{};
73       if ($final=~m{/[.][.]}) {
74         warn "$binfn,target=$target,final=$final\n";
75         return;
76       }
77       my $ref=\$SYMLINK{$binfn};
78       die if $$ref;
79       $$ref=$final;
80       return;
81     }
82     return if !-f $binfn;
83     die $binfn if $binfn!~m{^[.]/};
84     my $bin=readfile $binfn;
85     $binfn=~s{^[.]}{} or die;
86     my $rpath=($bin=~m{^.*\Q(R\E(?:UN)?\QPATH)\E\s*Library r(?:un)?path: \Q[\E(.*)\Q]\E$}m)[0];
87     if ($rpath) {
88       my $dirname=$File::Find::dir;
89       die if $dirname!~s{^[.]/}{/};
90       $rpath=~s{\$ORIGIN}{$dirname}g;
91     }
92     my $soname=($bin=~m{^.*\Q(SONAME)\E\s*Library soname: \Q[\E(.*)\Q]\E$}m)[0];
93     my $h={
94       "binfn"=>$binfn,
95       "needed"=>[$bin=~m{^\s*0x0000000000000001\s*\Q(NEEDED)\E\s*\QShared library: [\E(.*)\Q]\E$}gm],
96     };
97     $h->{"rpath"}=$rpath if $rpath;
98     $F{$binfn}=$h;
99 #warn "$binfn=".Dumper($h)."\n" if $binfn=~/libc.so.6/;
100 #    my $total=keys %F; warn "$total...\n" if 0==$total%1000;
101     if ($soname) {
102       my $sonamefn=$File::Find::dir."/".$soname;
103       $sonamefn=~s{^[.]/}{/} or die $sonamefn;
104       my $ref=\$SONAME{$sonamefn};
105 #      warn "soname=<$sonamefn> <$binfn> vs. <".$$ref->{"binfn"}.">\n" if $$ref;
106       $$ref=$h;
107     }
108     push @DEBUG,$binfn if $bin=~m{ \Q(DEBUG) \E };
109   },
110 },".";
111
112 #while (my($src,$target)=each %SYMLINK) {
113 #  die "$src->$target" if exists $SYMLINK{$target};
114 #}
115
116 my $dwzsizeall=0;
117 my $dwzsizeduplall=0;
118 my $dtsizeall=0;
119 my @ratioall;
120 my @ratioduplall;
121 my $computed=0;
122 BINFN: for my $binfn (@DEBUG) {
123 #  warn "$binfn...\n".Dumper([sort @{$F{$binfn}{"needed"}}]);
124   die $binfn if exists $SYMLINK{$binfn};
125   my @l=$binfn;
126   my %l=($binfn=>1);
127   while (@l) {
128     my $l=shift @l;
129     my $h=$F{$l};
130     for my $needed (@{$h->{"needed"}}) {
131       my $found;
132       if ($needed=~m{^/}) {
133         $needed=$SYMLINK{$needed} while exists $SYMLINK{$needed};
134         $found=$needed;
135       } else {
136 #       die "$binfn: $l: $needed" if $needed=~m{/};
137         my @rpath;
138         my $rpath=$h->{"rpath"};
139         push @rpath,split /:/,$rpath if $rpath;
140         push @rpath,qw(/lib64 /usr/lib64);
141         for my $rpath (@rpath) {
142           if ($rpath!~m{^/}) {
143             warn "$binfn: $l: $rpath";
144             next;
145           }
146           my $fn="$rpath/$needed";
147           $fn=$SYMLINK{$fn} while exists $SYMLINK{$fn};
148           next if !$SONAME{$fn};
149           $found=$fn;
150           last;
151         }
152         warn "$binfn: $l: $needed not found; rpath=".join(":",@rpath)."\n" if !$found;
153       }
154       push @l,$found if $found&&!$l{$found}++;
155     }
156   }
157 #warn Dumper $binfn,\%l;
158   my $dwzsizetot=0;
159   my $dwzsizedupltot=0;
160   my $dtsizetot=0;
161   my %dwzcommons;
162   for my $l (keys(%l)) {
163     my $ref=$D{$l};
164     if (!defined $ref) {
165       warn "$binfn: $l: missing\n";
166       next BINFN;
167     }
168     if (0==@$ref) {
169       warn "$binfn: $l: ambiguous\n";
170       next BINFN;
171     }
172     my $dtsize=$ref->[2];
173     die if !defined $dtsize;
174     $dtsizetot+=$dtsize;
175     my $dwzsize=$ref->[1];
176     die if !defined $dwzsize;
177     $dwzsizetot+=$dwzsize;
178     $dwzsizedupltot+=$dwzsize;
179     $computed++;
180     my $dwzcommon=$ref->[0];
181     next if $dwzcommon eq "nodwzcommon";
182     die if $dwzcommon eq "isdwzcommon";
183     my $duplicate=$dwzcommons{$dwzcommon}++;
184     my $dwzcommonref=$D{$dwzcommon};
185     die if !$dwzcommonref;
186     die if $dwzcommonref->[0] ne "isdwzcommon";
187     die if $dwzcommonref->[2] ne "NA";
188     my $dwzcommonsize=$dwzcommonref->[1];
189     $dwzsizetot+=$dwzcommonsize if !$duplicate;
190     $dwzsizedupltot+=$dwzcommonsize;
191   }
192   print "$binfn: dwzsizetot=$dwzsizetot dtsizetot=$dtsizetot\n";
193 warn "$binfn: ".Dumper(\%dwzcommons);
194   $dwzsizeall+=$dwzsizetot;
195   $dwzsizeduplall+=$dwzsizedupltot;
196   $dtsizeall+=$dtsizetot;
197   push @ratioall    ,$dwzsizetot    /$dtsizetot;
198   push @ratioduplall,$dwzsizedupltot/$dtsizetot;
199 #  warn "$binfn done\n".Dumper([sort keys(%l)]);
200 }
201 print "dwzsizeall    =$dwzsizeall"    ." dtsizeall=$dtsizeall =".$dwzsizeall    /$dtsizeall." avg=".List::Util::sum(@ratioall    )/@ratioall    ." stddev=".Statistics::Basic::stddev(\@ratioall    )."\n";
202 print "dwzsizeduplall=$dwzsizeduplall"." dtsizeall=$dtsizeall =".$dwzsizeduplall/$dtsizeall." avg=".List::Util::sum(@ratioduplall)/@ratioduplall." stddev=".Statistics::Basic::stddev(\@ratioduplall)."\n";
203 print "computed=$computed of DEBUG=".(0+@DEBUG)." =".$computed/@DEBUG."\n";
204 #print Dumper \@ratioall;