summaryrefslogtreecommitdiff
path: root/seivots-to-csv
blob: 80cf9b8b7d66e77371bb7b1cda4ac198d8d0ce80 (plain)
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
#!/usr/bin/python
# Copyright 2011  Lars Wirzenius
# 
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


import cliapp
import ConfigParser
import csv
import os


class SeivotToCsv(cliapp.Application):

    def add_settings(self):
        self.settings.add_string_setting(['output-dir'],
                                         'write output files into DIR '
                                            '(default: %default)',
                                         metavar='DIR',
                                         default='.')

    def process_args(self, args):
        seivots = []
        for filename in args:
            seivots.append(self.read_seivot(filename))
            
        sizes = self.find_initial_sizes(seivots)
        for size in sorted(sizes):
            group = self.find_seivots_in_size_group(seivots, size)
            group.sort(key=self.getkey)
            for op in ['backup', 'restore', 'list_files', 'forget']:
                filename = os.path.join(self.settings['output-dir'],
                                        '%s-%s.csv' % (op, size))
                f = open(filename, 'wb')
                writer = csv.writer(f, lineterminator='\n')
                writer.writerow(['obnam', 'larch', 'gen0 time (s)', 
                                 'gen0 speed (Mbit/s)',
                                 'gen0 RAM (MiB)', 'slowest inc (s)', 
                                 'slowest inc (Mbit/s)',
                                 'largest RAM inc (MiB)'])
                for seivot in group:
                    row = self.get_row_data(op, seivot)
                    writer.writerow(row)
                f.close()

    def read_seivot(self, filename):
        cp = ConfigParser.ConfigParser()
        cp.read([filename])
        return cp

    def getkey(self, seivot):
        return (seivot.get('meta', 'revision'), 
                 seivot.get('meta', 'larch-revision'))

    def get_size(self, seivot):
        return seivot.getint('0', 'backup.new-data')

    def find_initial_sizes(self, seivots):
        return list(set(self.get_size(s) for s in seivots))

    def find_seivots_in_size_group(self, seivots, size):
        return [s for s in seivots if self.get_size(s) == size]

    def get_row_data(self, op, seivot):
        bytes = seivot.getint('0', '%s.new-data' % op)
        secs = seivot.getfloat('0', '%s.real' % op)
        slowest_inc = self.find_slowest_incremental(op, seivot)
        inc_bytes = seivot.getint(slowest_inc, '%s.new-data' % op)
        inc_secs = seivot.getfloat(slowest_inc, '%s.real' % op)
        row = ['r%s' % seivot.get('meta', 'revision'),
               'r%s' % seivot.get('meta', 'larch-revision'),
               secs,
               self.bitspeed(bytes, secs),
               self.bytesize(seivot.getfloat('0', '%s.maxrss' % op)),
               inc_secs,
               self.bitspeed(inc_bytes, inc_secs),
               self.find_largest_incremental(op, seivot)]
        return row

    def values(self, op, suffix, seivot):
        for section in seivot.sections():
            if section not in ['meta', '0']:
                yield section, seivot.getfloat(section, '%s.%s' % (op,suffix))

    def find_slowest_incremental(self, op, seivot):
        v = list(self.values(op, 'real', seivot))
        if not v:
            return '0'
        return min(v, key=lambda pair: pair[1])[0]

    def find_largest_incremental(self, op, seivot):
        v = self.values(op, 'maxrss', seivot)
        return self.bytesize(min(list(x[1] for x in v) or [0.0]))

    def bytesize(self, kilobytes):
        return '%.1f' % (float(kilobytes) / 1024)

    def bitspeed(self, bytes, seconds):
        return '%.1f' % (8*bytes / seconds / (1000**2))


if __name__ == '__main__':
    SeivotToCsv().run()