~kiithsacmp/miniini/trunk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/python3

# Copyright (C) 2010 Ferdinand Majerech
# This file is part of MiniINI
# For conditions of distribution and use, see copyright notice in LICENSE.txt

import sys
import getopt
import os

def help():
    print("Script to merge outputs (comparisons) of testutil-compare.py")
    print("Copyright (C) 2010 Ferdinand Majerech")
    print("Usage: testutil-compare-merge.py [OPTIONS] [ARGUMENTS]")
    print(" -h --help            display this help and exit")
    print(" -o --output      val file to output merged comparisons to")
    print("                      if not specified, output is printed to stdout")
    print("ARGUMENTS must be comparisons to merge.")

#Stores comparisons of same data type from all inputs
class Merged:
    def __init__(self, line):
        #each comparison is a list, first element of which is name of the
        #input to which the comparison belongs, other are values compared
        self.__comparisons = []
        #name of data compared in the comparisons
        #(e.g. cachegrind|Relative|data_refs)
        self.__data_name = line.partition(" ")[0]

    def add_comparison(self, name, line):
        self.__comparisons.append([name] + line.split()[1:])

    #format for nicer printing
    def __format(self):
        #widths of each column in the comparisons (first column are input names,
        #others are values compared)
        column_widths = []
        #get widths required for each column
        for comp in self.__comparisons:
            for column_index in range(0, len(comp)):
                column_width = len(comp[column_index])
                if column_index >= len(column_widths):
                    column_widths.append(column_width)
                else:
                    if column_width > column_widths[column_index]:
                        column_widths[column_index] = column_width
        #pad elements of each comparison with spaces to get straight columns
        for comp_index in range(0, len(self.__comparisons)):
            for column_index in range(0, len(comp)):
                column = self.__comparisons[comp_index][column_index]
                column = column + " " * (column_widths[column_index] - len(column))
                self.__comparisons[comp_index][column_index] = column

    #get a printable string representation of merged comparisons
    def get_string(self):
        self.__format()
        out = []
        #write data name
        out.append(self.__data_name + ":\n")
        #underline the data name for better readability
        out.append("-" * (len(out[-1]) - 1) + "\n")
        #write comparisons with their inputs' names and values
        for comp in self.__comparisons:
            out.append(" ".join(comp) + "\n")
        return "".join(out)

    #equality operator with a string so we can use the in operator and list search
    def __eq__(self, line):
        return self.__data_name == line.partition(" ")[0]

#handles merging of multiple comparison files output by testutil-compare.py
class Merge:
    def __init__(self, comparisons, output):
        #filenames of comparison files
        self.__comparisons = comparisons
        #merged data comparisons will be stored here (e.g. cachegrind data refs)
        self.__merged = []
        #process input files and merge them
        for comp in comparisons:
            self.__add_comparison(comp)
        #write out the result
        self.__write(output)

    #process an input file and merge it to already merged comparisons
    def __add_comparison(self, comp):
        #relative or absolute
        value_type = "unknown"
        #memcheck, callgrind, etc.
        section = "unknown"
        with open(comp, "r") as comp_file:
            for line in comp_file:
                #ignore comments
                if line[0] in (";", "#"):
                    continue
                #value type or section headers
                elif line[0] == "=":
                    if line[1] == "=":
                        section = line[2:-3]
                    else:
                        value_type = line[1:-2]
                #ignore empty lines, non-empty ones will be merged
                elif (len(line) > 0) and (not line.isspace()):
                    line = section + "|" + value_type + "|" + line
                    #if we don't have this data type yet, add it
                    if not line in self.__merged:
                        self.__merged.append(Merged(line))
                    #merge the comparison
                    merged_index = self.__merged.index(line)
                    self.__merged[merged_index].add_comparison(comp, line)

    def __write(self, output):
        #if no output file specified, write out to stdout
        if output == None:
            print(";merged test comparisons: " + " ".join(self.__comparisons))
            for merged in self.__merged:
                print (merged.get_string())
        #write to file
        else:
            with open(output, "w") as out_file:
                out_file.write(";merged test comparisons: " +
                               " ".join(self.__comparisons) + "\n")
                for merged in self.__merged:
                    out_file.write(merged.get_string() + "\n")

def main():
    output = None
    try:
        opts, args = getopt.getopt(sys.argv[1:], "ho:",
                     ["help", "output="])
    except getopt.GetoptError:
        help()
        sys.exit(1)

    for opt, arg in opts:
        if opt in ("-h", "--help"):
            help()
            sys.exit(0)
        if opt in ("-o", "--output"):
            output = arg

    if len(args) < 2:
        print ("Need at least 2 arguments: comparisons to merge.")
        sys.exit(2)
    Merge(args, output)

if __name__ == '__main__':
    main()