Util: Added script to semantically diff two config.ini files
This script (util/diff_config.pl) takes two config.ini files and compares them. It highlights value changes, as well as displaying which parts are unique to a specific config.ini file. This is useful when trying to replicate an earlier experiment and when trying to make small changes to an existing configuration.
This commit is contained in:
parent
6f603e0807
commit
29acf859eb
1 changed files with 231 additions and 0 deletions
231
util/diff_config.pl
Executable file
231
util/diff_config.pl
Executable file
|
@ -0,0 +1,231 @@
|
||||||
|
# Copyright (c) 2012 ARM Limited
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# The license below extends only to copyright in the software and shall
|
||||||
|
# not be construed as granting a license to any other intellectual
|
||||||
|
# property including but not limited to intellectual property relating
|
||||||
|
# to a hardware implementation of the functionality of the software
|
||||||
|
# licensed hereunder. You may use the software subject to the license
|
||||||
|
# terms below provided that you ensure that this notice is replicated
|
||||||
|
# unmodified and in its entirety in all distributions of the software,
|
||||||
|
# modified or unmodified, in source code or in binary form.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions are
|
||||||
|
# met: redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer;
|
||||||
|
# redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution;
|
||||||
|
# neither the name of the copyright holders nor the names of its
|
||||||
|
# contributors may be used to endorse or promote products derived from
|
||||||
|
# this software without specific prior written permission.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
#
|
||||||
|
# Author: Uri Wiener
|
||||||
|
#
|
||||||
|
|
||||||
|
# Script which takes two config.ini files and generates a semantic diff. The
|
||||||
|
# resulting diff shows which parts of the configurations differed, and in the
|
||||||
|
# case that there is a difference it displays it. This allows rapid comparision
|
||||||
|
# of two gem5 runs and therefore provides an easy method to ensure that
|
||||||
|
# configurations are similar, or not.
|
||||||
|
|
||||||
|
#!/usr/bin/perl
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
die "Please check args... " unless ($#ARGV == 1);
|
||||||
|
my $config1FileName = $ARGV[0];
|
||||||
|
my $config2FileName = $ARGV[1];
|
||||||
|
|
||||||
|
# Get just the name of the file, rather than the full path
|
||||||
|
my $config1ShortName = getFilenameFromPath($config1FileName);
|
||||||
|
my $config2ShortName = getFilenameFromPath($config2FileName);
|
||||||
|
|
||||||
|
# If the file names are the same, use the full path
|
||||||
|
if ($config1ShortName == $config2ShortName) {
|
||||||
|
$config1ShortName = $config1FileName;
|
||||||
|
$config2ShortName = $config2FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
print "\nComparing the following files:\n",
|
||||||
|
"\t$config1FileName\n",
|
||||||
|
"\tvs.\n",
|
||||||
|
"\t$config2FileName\n\n";
|
||||||
|
|
||||||
|
# Read in the two config files
|
||||||
|
my %config1 = readConfig($config1FileName);
|
||||||
|
my %config2 = readConfig($config2FileName);
|
||||||
|
|
||||||
|
# Compare the two config files. For the first comparision we also compare the
|
||||||
|
# values (setting the first parameter to 1). There is little point doing this
|
||||||
|
# for the second comparison as it will yield the same information.
|
||||||
|
compareConfigs( 1, \%config1, $config1ShortName, \%config2, $config2ShortName );
|
||||||
|
compareConfigs( 0, \%config2, $config2ShortName, \%config1, $config1ShortName );
|
||||||
|
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Compare values and return unique values
|
||||||
|
########################################################
|
||||||
|
sub compareValues {
|
||||||
|
my $values1 = shift;
|
||||||
|
my $values2 = shift;
|
||||||
|
my @splitValues1 = split(/ /, $values1);
|
||||||
|
my @splitValues2 = split(/ /, $values2);
|
||||||
|
my @uniqueValues;
|
||||||
|
|
||||||
|
foreach my $val1 (@splitValues1) {
|
||||||
|
my $foundMatch = 0;
|
||||||
|
|
||||||
|
# if both values equal set match flag, then break loop
|
||||||
|
foreach my $val2 (@splitValues2) {
|
||||||
|
if ($val1 eq $val2) {
|
||||||
|
$foundMatch = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# in case of ports, ignore port number and match port name only
|
||||||
|
if ($val1 =~ /\[/ and $val2 =~ /\[/) {
|
||||||
|
$val1 =~ m/^(.*)\[.*\]/;
|
||||||
|
my $val1Name = $1;
|
||||||
|
$val2 =~ m/^(.*)\[.*\]/;
|
||||||
|
my $val2Name = $1;
|
||||||
|
|
||||||
|
# if both values equal set match flag, then break loop
|
||||||
|
if ($val1Name eq $val2Name) {
|
||||||
|
$foundMatch = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Otherwise, the value is unique.
|
||||||
|
if (not $foundMatch) {
|
||||||
|
push(@uniqueValues, $val1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return join(", ", @uniqueValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Compare two config files. Print differences.
|
||||||
|
########################################################
|
||||||
|
sub compareConfigs {
|
||||||
|
my $compareFields = shift; # Specfy if the fields should be compared
|
||||||
|
my $config1Ref = shift; # Config 1
|
||||||
|
my $config1Name = shift; # Config 1 name
|
||||||
|
my $config2Ref = shift; # Config 2
|
||||||
|
my $config2Name = shift; # Config 2 name
|
||||||
|
my @uniqueSections;
|
||||||
|
|
||||||
|
foreach my $sectionName ( sort keys %$config1Ref ) {
|
||||||
|
# check if section exists in config2
|
||||||
|
if ( not exists $config2Ref->{$sectionName} ) {
|
||||||
|
push(@uniqueSections, $sectionName);
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my %section1 = %{ $config1Ref->{$sectionName} };
|
||||||
|
my %section2 = %{ $config2Ref->{$sectionName} };
|
||||||
|
my $firstDifInSection = 1;
|
||||||
|
|
||||||
|
if (not $compareFields) {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare the values of each field; print any differences
|
||||||
|
foreach my $field ( sort keys %section1 ) {
|
||||||
|
if ($section1{$field} ne $section2{$field}) {
|
||||||
|
my $diff1 = compareValues($section1{$field}, $section2{$field});
|
||||||
|
my $diff2 = compareValues($section2{$field}, $section1{$field});
|
||||||
|
|
||||||
|
# If same, skip to next iteration
|
||||||
|
if ($diff1 eq "" and $diff2 eq "") {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
|
||||||
|
# If it is the first difference in this section, print section
|
||||||
|
# name
|
||||||
|
if ($firstDifInSection) {
|
||||||
|
print "$sectionName\n";
|
||||||
|
$firstDifInSection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Print the actual differences
|
||||||
|
print "\t$field\n";
|
||||||
|
if ($diff1 ne "") {
|
||||||
|
print "\t\t$config1Name: ", $diff1, "\n";
|
||||||
|
}
|
||||||
|
if ($diff2 ne "") {
|
||||||
|
print "\t\t$config2Name: ", $diff2, "\n";
|
||||||
|
}
|
||||||
|
} # end if
|
||||||
|
} # end foreach field
|
||||||
|
} # end foreach section
|
||||||
|
|
||||||
|
# If there are unique sections, print them
|
||||||
|
if ($#uniqueSections != -1) {
|
||||||
|
print "Sections which exist only in $config1Name: ",
|
||||||
|
join(", ", @uniqueSections), "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Split the path to get just the filename
|
||||||
|
########################################################
|
||||||
|
sub getFilenameFromPath {
|
||||||
|
my $filename = shift; # the input filename including path
|
||||||
|
my @splitName = split(/\//, $filename);
|
||||||
|
return $splitName[$#splitName]; # return just the filename, without path
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Read in the config file section by section.
|
||||||
|
########################################################
|
||||||
|
sub readConfig {
|
||||||
|
my $filename = shift;
|
||||||
|
my %config;
|
||||||
|
open CONFIG, "<$filename" or die $!;
|
||||||
|
while ( my $line = <CONFIG> ) {
|
||||||
|
if ( $line =~ /^\[.*\]$/ ) {
|
||||||
|
readSection( $line, \%config );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close CONFIG;
|
||||||
|
return %config;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
########################################################
|
||||||
|
# Read in each section of the config file.
|
||||||
|
########################################################
|
||||||
|
sub readSection {
|
||||||
|
my $line = shift;
|
||||||
|
my $config_ref = shift;
|
||||||
|
$line =~ m/\[(.*)\]/;
|
||||||
|
my $sectionName = $1;
|
||||||
|
while ( my $line = <CONFIG> ) {
|
||||||
|
if ( $line =~ /^$/ ) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
my @field = split( /=/, $line );
|
||||||
|
my $fieldName = $field[0];
|
||||||
|
my $value = $field[1];
|
||||||
|
chomp $value;
|
||||||
|
$config_ref->{$sectionName}{$fieldName} = $value;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue