~ubuntu-branches/ubuntu/raring/tsung/raring-proposed

« back to all changes in this revision

Viewing changes to src/tsung-plotter/tsplot.py.in

  • Committer: Package Import Robot
  • Author(s): Ignace Mouzannar
  • Date: 2011-09-20 05:21:15 UTC
  • Revision ID: package-import@ubuntu.com-20110920052115-nqhu0na28zgm78ei
Tags: upstream-1.4.1
ImportĀ upstreamĀ versionĀ 1.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/python
 
2
# -*- Mode: python -*-
 
3
# -*- coding: utf-8 -*-
 
4
 
 
5
#
 
6
#  Copyright: 2006 by Dalibo <dalibo.com>
 
7
#  Copyright: 2007 Dimitri Fontaine <dim@tapoueh.org>
 
8
#  Created: 2006 by Dimitri Fontaine <dim@tapoueh.org>
 
9
#
 
10
#  Modified: 2008 by Nicolas Niclausse
 
11
#
 
12
#  This program is free software; you can redistribute it and/or modify
 
13
#  it under the terms of the GNU General Public License as published by
 
14
#  the Free Software Foundation; either version 2 of the License, or
 
15
#  (at your option) any later version.
 
16
#
 
17
#  This program is distributed in the hope that it will be useful,
 
18
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
19
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
20
#  GNU General Public License for more details.
 
21
#
 
22
#  You should have received a copy of the GNU General Public License
 
23
#  along with this program; if not, write to the Free Software
 
24
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 
25
#
 
26
#  In addition, as a special exception, you have the permission to
 
27
#  link the code of this program with any library released under
 
28
#  the EPL license and distribute linked combinations including
 
29
#  the two.
 
30
 
 
31
# A plotter for tsung text generated data
 
32
 
 
33
import os, sys
 
34
 
 
35
LIBDIR         = "@EXPANDED_LIBDIR@/tsung"
 
36
SHAREDIR       = "@EXPANDED_SHAREDIR@"
 
37
USERDIR        = ".tsung"
 
38
CONF           = "http.plots.en.conf"
 
39
SYS_STATS_CONF = os.path.join(SHAREDIR, 'tsung_plotter', 'stats.conf')
 
40
 
 
41
sys.path.append(LIBDIR)
 
42
 
 
43
from tsung_plotter.tsung import TsungLog
 
44
from ConfigParser import ConfigParser
 
45
from pylab import *
 
46
 
 
47
 
 
48
class Plot:
 
49
    """ The ploting class, using matplotlib """
 
50
 
 
51
    def __init__(self,
 
52
                 name    = "",
 
53
                 xlabel  = "",
 
54
                 ylabel  = "",
 
55
                 title   = "",
 
56
                 legends = None,
 
57
                 position = 0,
 
58
                 styles  = ['b-', 'r-', 'g-', 'c-', 'y^', 'kv'],
 
59
                 colors  = ['b', 'r', 'g', 'c', 'y', 'k'],
 
60
                 dpi     = 150,
 
61
                 tn_dpi  = 50,
 
62
                 xfactor = 1,
 
63
                 yfactor = 1,
 
64
                 yscale  = 'linear',
 
65
                 plottype  = 'lineplot', # can be lineplot or bar
 
66
                 outdir  = '/tmp/tsung-plotter',
 
67
                 imgtype = 'png'):
 
68
 
 
69
        # Only used if no plot type given
 
70
        self.name      = name
 
71
        self.xlabel    = xlabel
 
72
        self.ylabel    = ylabel
 
73
        self.title     = title
 
74
        self.legends   = legends
 
75
        self.position  = position
 
76
        self.dpi       = dpi
 
77
        self.thumb_dpi = tn_dpi
 
78
        self.xfactor   = xfactor
 
79
        self.yfactor   = yfactor
 
80
        self.yscale    = yscale
 
81
        self.plottype  = plottype
 
82
        self.styles    = styles
 
83
        self.colors    = colors
 
84
        self.outdir    = outdir
 
85
        self.imgtype   = imgtype
 
86
 
 
87
    def plot(self, stats, dataset):
 
88
        """ draw a simple timeline or bar plots from two dataset """
 
89
 
 
90
        if self.plottype == "lineplot":
 
91
            # prepare matplotlib graph
 
92
            clf()
 
93
            ax = subplot(111)
 
94
            ax.set_yscale(self.yscale)
 
95
 
 
96
            count = 0
 
97
            for data in dataset:
 
98
                # get give type data for plotting
 
99
                nstats = 0
 
100
                for (name, stat) in stats:
 
101
                    pdata = data.stat(name, stat)
 
102
                    # we want timestamp sorted data to plot
 
103
                    ts = pdata.keys()
 
104
                    ts.sort()
 
105
                    values = [pdata[t] / self.yfactor[nstats%len(self.yfactor)] for t in ts]
 
106
 
 
107
                    if self.xfactor not in [1, "1"]:
 
108
                        ts = [x / self.xfactor for x in ts]
 
109
 
 
110
                    # Now use matplotlib to do the plotting
 
111
                    plot(ts, values, self.styles[count%len(self.styles)])
 
112
                    count += 1
 
113
                    nstats += 1
 
114
            # Now setup the legend
 
115
            title(self.title)
 
116
            xlabel(self.xlabel)
 
117
            ylabel(self.ylabel)
 
118
            legend(self.legends, loc=self.position)
 
119
 
 
120
            # we want to draw a grid
 
121
            grid(True)
 
122
 
 
123
            filename = os.path.join(self.outdir,
 
124
                                    "%s.%s" % (self.name, self.imgtype))
 
125
            thumbnail = os.path.join(self.outdir,
 
126
                                     "%s_tn.%s" % (self.name, self.imgtype))
 
127
 
 
128
            savefig(filename, dpi=self.dpi, orientation='portrait')
 
129
            savefig(thumbnail, dpi=self.thumb_dpi, orientation='portrait')
 
130
            return filename
 
131
        else:
 
132
            # box chart for gmean
 
133
            clf()
 
134
            width = 1.0/len(dataset)
 
135
            nbox=len(dataset)
 
136
            ind=arange(1)
 
137
            count = 0
 
138
            current = {}
 
139
            percent = []
 
140
            ticksp = []
 
141
            ax = subplot(111)
 
142
            ax.set_yscale(self.yscale)
 
143
            for data in dataset:
 
144
                nstats=0
 
145
                for (name, stat) in stats:
 
146
                    pdata = data.stat(name, stat)
 
147
                    size= len(pdata)
 
148
                    if size > 0 :
 
149
                        # the data we use is the latest value:
 
150
                        current[count] = pdata.values()[size-1] / self.yfactor[nstats]
 
151
                        ax.bar(ind+count*width, ( current[count] ), width,
 
152
                               color=self.colors[count] )
 
153
                        # get percent of increase/decrease:
 
154
                        if count > 0:
 
155
                            percent.append(str(round(-100 + current[count] / current[0] * 100)) + "% ")
 
156
                        else:
 
157
                            percent.append("reference")
 
158
                        currenttick=(0.5 + count)/nbox
 
159
                        ticksp.append(currenttick)
 
160
                        count += 1
 
161
                        nstats += 1
 
162
 
 
163
            boxchart = os.path.join(self.outdir,
 
164
                                    "%s.%s" % (self.name, self.imgtype))
 
165
            boxchart_thumb = os.path.join(self.outdir,
 
166
                                    "%s_tn.%s" % (self.name, self.imgtype))
 
167
            title(self.title)
 
168
            legend(self.legends, loc=self.position)
 
169
            ax.set_xticks(ticksp)
 
170
            ax.set_xticklabels(percent)
 
171
            ylabel(self.ylabel)
 
172
            savefig(boxchart, dpi=self.dpi, orientation='portrait')
 
173
            savefig(boxchart_thumb, dpi=self.thumb_dpi, orientation='portrait')
 
174
            return boxchart
 
175
 
 
176
 
 
177
def main(conffile, logs, legends, outdir, verbose):
 
178
    """ Produce plots from given """
 
179
 
 
180
    dataset = [d for f, d in logs]
 
181
 
 
182
    config = ConfigParser()
 
183
    config.read(conffile)
 
184
 
 
185
    for s in config.sections():
 
186
        p = Plot(name = s, outdir = outdir)
 
187
 
 
188
        # defaults
 
189
        for d, v in config.defaults().items():
 
190
            if d != 'encoding':
 
191
                p.__dict__[d] = v
 
192
            else:
 
193
                encoding = v
 
194
 
 
195
        # stats
 
196
        # conf:   200.count, 400.count
 
197
        # result: [["200", "count"], ["400", "count"]]
 
198
        try:
 
199
            stats = [x.strip().rsplit('.', 1)
 
200
                     for x in config.get(s, 'stats').split(' ')]
 
201
        except:
 
202
            print 'error: unable to read plot "%s" stats' % s
 
203
            continue
 
204
 
 
205
        if config.has_option(s, 'styles'):
 
206
            p.styles = [x.strip() for x in config.get(s, 'styles').split(' ')]
 
207
 
 
208
        if config.has_option(s, 'legend'):
 
209
            # this is the legend prefix$
 
210
            l = []
 
211
            count    = 0
 
212
            clegends = config.get(s, 'legend').decode(encoding).split(',')
 
213
 
 
214
            for f in logs:
 
215
                l     += ['%s %s' % (x.strip(), legends[count]) \
 
216
                          for x in clegends]
 
217
                count += 1
 
218
        p.legends = l
 
219
        
 
220
        if config.has_option(s, 'position'):
 
221
            # legend position according to matplotlib standard values (1-10)
 
222
            val = config.get(s, 'position').decode(encoding)
 
223
            if val.isdigit():
 
224
                p.position = int(val)
 
225
            else:
 
226
                p.position = val
 
227
            
 
228
 
 
229
        if config.has_option(s, 'yfactor'):
 
230
            try:
 
231
                p.__dict__['yfactor'] = map(float,config.get(s, 'yfactor').decode(encoding).split(','))
 
232
            except ValueError:
 
233
                print 'warning: %s yfactor not a number: %s' \
 
234
                    % (p.name, config.get(s, yfactor))
 
235
        # Text parameters - to decode into specified encoding
 
236
        for attr in ['title', 'xlabel', 'ylabel', 'plottype', 'yscale']:
 
237
            if config.has_option(s, attr):
 
238
                cstring = config.get(s, attr).decode(encoding)
 
239
                p.__dict__[attr] = cstring
 
240
 
 
241
        # Numerical parameters
 
242
        for attr in ['xfactor', 'dpi', 'tn_dpi']:
 
243
            if config.has_option(s, attr):
 
244
                try:
 
245
                    p.__dict__[attr] = config.getfloat(s, attr)
 
246
                except ValueError:
 
247
                    print 'warning: %s %s not a number: %s' \
 
248
                          % (p.name, attr, config.get(s, attr))
 
249
 
 
250
        outfile = p.plot(stats, dataset)
 
251
 
 
252
        if verbose:
 
253
            print 'Generated plot %s' % outfile
 
254
 
 
255
if __name__ == "__main__":
 
256
    from optparse import OptionParser
 
257
 
 
258
    parser = OptionParser()
 
259
    parser.add_option("-c", "--config", dest="config", default=None,
 
260
                      help="configuration file")
 
261
    parser.add_option("-d", "--outdir", dest="outdir", default="/tmp/tsung",
 
262
                      help="output dir where to save plots (/tmp/tsung)")
 
263
    parser.add_option("-v", action="store_true", dest="verbose", default=False,
 
264
                      help="be verbose")
 
265
 
 
266
    (options, args) = parser.parse_args()
 
267
 
 
268
    if options.config is None:
 
269
        userconf = os.path.join(os.environ['HOME'], USERDIR, CONF)
 
270
        if os.access(userconf, os.R_OK):
 
271
            config = userconf
 
272
        else:
 
273
            config = os.path.join(SHAREDIR, 'tsung_plotter', CONF)
 
274
    else:
 
275
        config = options.config
 
276
 
 
277
    if options.verbose:
 
278
        print 'Using %s configuration file' % config
 
279
 
 
280
    if not os.access(config, os.R_OK):
 
281
        print "can't read configuration file: %s" % config
 
282
        sys.exit(1)
 
283
 
 
284
    # FIXME: error control
 
285
    # OSError: [Errno 17] Le fichier existe.: '/tmp/tsung'
 
286
    try:
 
287
        os.makedirs(options.outdir)
 
288
    except:
 
289
        pass
 
290
 
 
291
    # args are legend then file, any times wanted by user
 
292
    if len(args) % 2 != 0:
 
293
        print "error: please provide legend and tsung log filename"
 
294
        sys.exit(3)
 
295
 
 
296
    count   = 0
 
297
    legends = []
 
298
    files   = []
 
299
 
 
300
    for a in args:
 
301
        if count % 2 == 0:
 
302
            legends.append(a)
 
303
        else:
 
304
            files.append(a)
 
305
 
 
306
        count += 1
 
307
 
 
308
    if options.verbose:
 
309
        print 'Using %s stats configuration file' % SYS_STATS_CONF
 
310
 
 
311
    logs = []
 
312
    for logfile in files:
 
313
        if not os.access(logfile, os.R_OK):
 
314
            print "error: unable to read file %s" % logfile
 
315
 
 
316
        else:
 
317
            if options.verbose:
 
318
                print 'Parsing Tsung log file', logfile
 
319
            logs.append((logfile, TsungLog(SYS_STATS_CONF, logfile)))
 
320
 
 
321
    if len(logs) != len(args) / 2:
 
322
        print 'error while parsing files (%d != %d)' % (len(logs),
 
323
                                                        len(args)/2)
 
324
        sys.exit(2)
 
325
 
 
326
    main(config, logs, legends, options.outdir, options.verbose)