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
46use strict;
47
48die "Please check args... " unless ($#ARGV == 1);
49my $config1FileName = $ARGV[0];
50my $config2FileName = $ARGV[1];
51
52# Get just the name of the file, rather than the full path
53my $config1ShortName = getFilenameFromPath($config1FileName);
54my $config2ShortName = getFilenameFromPath($config2FileName);
55
56# If the file names are the same, use the full path
57if ($config1ShortName == $config2ShortName) {
58    $config1ShortName = $config1FileName;
59    $config2ShortName = $config2FileName;
60}
61
62print "\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
68my %config1 = readConfig($config1FileName);
69my %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.
74compareConfigs( 1, \%config1, $config1ShortName, \%config2, $config2ShortName );
75compareConfigs( 0, \%config2, $config2ShortName, \%config1, $config1ShortName );
76
77
78########################################################
79# Compare values and return unique values
80########################################################
81sub 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########################################################
126sub 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########################################################
189sub 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########################################################
199sub 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########################################################
216sub 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}
232