util: Add a unit test for the m5 utility's "readfile" command.
[gem5.git] / util / diff_config.pl
1 # Copyright (c) 2012 ARM Limited
2 # All rights reserved.
3 #
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
12 #
13 # Redistribution and use in source and binary forms, with or without
14 # modification, are permitted provided that the following conditions are
15 # met: redistributions of source code must retain the above copyright
16 # notice, this list of conditions and the following disclaimer;
17 # redistributions in binary form must reproduce the above copyright
18 # notice, this list of conditions and the following disclaimer in the
19 # documentation and/or other materials provided with the distribution;
20 # neither the name of the copyright holders nor the names of its
21 # contributors may be used to endorse or promote products derived from
22 # this software without specific prior written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #
36 # Author: Uri Wiener
37 #
38
39 # Script which takes two config.ini files and generates a semantic diff. The
40 # resulting diff shows which parts of the configurations differed, and in the
41 # case that there is a difference it displays it. This allows rapid comparision
42 # of two gem5 runs and therefore provides an easy method to ensure that
43 # configurations are similar, or not.
44
45 #!/usr/bin/perl
46 use strict;
47
48 die "Please check args... " unless ($#ARGV == 1);
49 my $config1FileName = $ARGV[0];
50 my $config2FileName = $ARGV[1];
51
52 # Get just the name of the file, rather than the full path
53 my $config1ShortName = getFilenameFromPath($config1FileName);
54 my $config2ShortName = getFilenameFromPath($config2FileName);
55
56 # If the file names are the same, use the full path
57 if ($config1ShortName == $config2ShortName) {
58 $config1ShortName = $config1FileName;
59 $config2ShortName = $config2FileName;
60 }
61
62 print "\nComparing the following files:\n",
63 "\t$config1FileName\n",
64 "\tvs.\n",
65 "\t$config2FileName\n\n";
66
67 # Read in the two config files
68 my %config1 = readConfig($config1FileName);
69 my %config2 = readConfig($config2FileName);
70
71 # Compare the two config files. For the first comparision we also compare the
72 # values (setting the first parameter to 1). There is little point doing this
73 # for the second comparison as it will yield the same information.
74 compareConfigs( 1, \%config1, $config1ShortName, \%config2, $config2ShortName );
75 compareConfigs( 0, \%config2, $config2ShortName, \%config1, $config1ShortName );
76
77
78 ########################################################
79 # Compare values and return unique values
80 ########################################################
81 sub compareValues {
82 my $values1 = shift;
83 my $values2 = shift;
84 my @splitValues1 = split(/ /, $values1);
85 my @splitValues2 = split(/ /, $values2);
86 my @uniqueValues;
87
88 foreach my $val1 (@splitValues1) {
89 my $foundMatch = 0;
90
91 # if both values equal set match flag, then break loop
92 foreach my $val2 (@splitValues2) {
93 if ($val1 eq $val2) {
94 $foundMatch = 1;
95 last;
96 }
97
98 # in case of ports, ignore port number and match port name only
99 if ($val1 =~ /\[/ and $val2 =~ /\[/) {
100 $val1 =~ m/^(.*)\[.*\]/;
101 my $val1Name = $1;
102 $val2 =~ m/^(.*)\[.*\]/;
103 my $val2Name = $1;
104
105 # if both values equal set match flag, then break loop
106 if ($val1Name eq $val2Name) {
107 $foundMatch = 1;
108 last;
109 }
110 }
111 }
112
113 # Otherwise, the value is unique.
114 if (not $foundMatch) {
115 push(@uniqueValues, $val1);
116 }
117 }
118
119 return join(", ", @uniqueValues);
120 }
121
122
123 ########################################################
124 # Compare two config files. Print differences.
125 ########################################################
126 sub compareConfigs {
127 my $compareFields = shift; # Specfy if the fields should be compared
128 my $config1Ref = shift; # Config 1
129 my $config1Name = shift; # Config 1 name
130 my $config2Ref = shift; # Config 2
131 my $config2Name = shift; # Config 2 name
132 my @uniqueSections;
133
134 foreach my $sectionName ( sort keys %$config1Ref ) {
135 # check if section exists in config2
136 if ( not exists $config2Ref->{$sectionName} ) {
137 push(@uniqueSections, $sectionName);
138 next;
139 }
140 my %section1 = %{ $config1Ref->{$sectionName} };
141 my %section2 = %{ $config2Ref->{$sectionName} };
142 my $firstDifInSection = 1;
143
144 if (not $compareFields) {
145 next;
146 }
147
148 # Compare the values of each field; print any differences
149 foreach my $field ( sort keys %section1 ) {
150 if ($section1{$field} ne $section2{$field}) {
151 my $diff1 = compareValues($section1{$field}, $section2{$field});
152 my $diff2 = compareValues($section2{$field}, $section1{$field});
153
154 # If same, skip to next iteration
155 if ($diff1 eq "" and $diff2 eq "") {
156 next;
157 }
158
159 # If it is the first difference in this section, print section
160 # name
161 if ($firstDifInSection) {
162 print "$sectionName\n";
163 $firstDifInSection = 0;
164 }
165
166 # Print the actual differences
167 print "\t$field\n";
168 if ($diff1 ne "") {
169 print "\t\t$config1Name: ", $diff1, "\n";
170 }
171 if ($diff2 ne "") {
172 print "\t\t$config2Name: ", $diff2, "\n";
173 }
174 } # end if
175 } # end foreach field
176 } # end foreach section
177
178 # If there are unique sections, print them
179 if ($#uniqueSections != -1) {
180 print "Sections which exist only in $config1Name: ",
181 join(", ", @uniqueSections), "\n";
182 }
183 }
184
185
186 ########################################################
187 # Split the path to get just the filename
188 ########################################################
189 sub getFilenameFromPath {
190 my $filename = shift; # the input filename including path
191 my @splitName = split(/\//, $filename);
192 return $splitName[$#splitName]; # return just the filename, without path
193 }
194
195
196 ########################################################
197 # Read in the config file section by section.
198 ########################################################
199 sub readConfig {
200 my $filename = shift;
201 my %config;
202 open CONFIG, "<$filename" or die $!;
203 while ( my $line = <CONFIG> ) {
204 if ( $line =~ /^\[.*\]$/ ) {
205 readSection( $line, \%config );
206 }
207 }
208 close CONFIG;
209 return %config;
210 }
211
212
213 ########################################################
214 # Read in each section of the config file.
215 ########################################################
216 sub readSection {
217 my $line = shift;
218 my $config_ref = shift;
219 $line =~ m/\[(.*)\]/;
220 my $sectionName = $1;
221 while ( my $line = <CONFIG> ) {
222 if ( $line =~ /^$/ ) {
223 last;
224 }
225 my @field = split( /=/, $line );
226 my $fieldName = $field[0];
227 my $value = $field[1];
228 chomp $value;
229 $config_ref->{$sectionName}{$fieldName} = $value;
230 }
231 }