first public release
[dpdk.git] / app / test / graph_ring.py
1 #!/usr/bin/env python
2
3 #   BSD LICENSE
4
5 #   Copyright(c) 2010-2012 Intel Corporation. All rights reserved.
6 #   All rights reserved.
7
8 #   Redistribution and use in source and binary forms, with or without 
9 #   modification, are permitted provided that the following conditions 
10 #   are met:
11
12 #     * Redistributions of source code must retain the above copyright 
13 #       notice, this list of conditions and the following disclaimer.
14 #     * Redistributions in binary form must reproduce the above copyright 
15 #       notice, this list of conditions and the following disclaimer in 
16 #       the documentation and/or other materials provided with the 
17 #       distribution.
18 #     * Neither the name of Intel Corporation nor the names of its 
19 #       contributors may be used to endorse or promote products derived 
20 #       from this software without specific prior written permission.
21
22 #   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
23 #   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
24 #   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
25 #   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
26 #   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
27 #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
28 #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
29 #   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
30 #   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
31 #   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
32 #   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34 #  version: DPDK.L.1.2.3-3
35
36 import sys, re
37 import numpy as np
38 import matplotlib
39 matplotlib.use('Agg') # we don't want to use X11
40 import matplotlib.pyplot as plt
41 from matplotlib.ticker import FuncFormatter
42
43 INT = "([-+]?[0-9][0-9]*)"
44
45 class RingTest:
46     l = []
47
48     def __init__(self):
49         pass
50
51     # sort a test case list
52     def sort(self, x, y):
53         for t in [ "enq_core", "deq_core", "enq_bulk", "deq_bulk", "rate" ]:
54             if x[t] > y[t]:
55                 return 1
56             if x[t] < y[t]:
57                 return -1
58         return 0
59
60     # add a test case
61     def add(self, **args):
62         self.l.append(args)
63
64     # get an ordered list matching parameters
65     # ex: r.get(enq_core=1, deq_core=1)
66     def get(self, **args):
67         retlist = []
68         for t in self.l:
69             add_it = 1
70             for a in args:
71                 if args[a] != t[a]:
72                     add_it = 0
73                     break
74             if add_it:
75                 retlist.append(t)
76         retlist.sort(cmp=self.sort)
77         return retlist
78
79     # return an ordered list of all values for this param or param list
80     # ex: r.get_value_list("enq_core")
81     def get_value_list(self, param):
82         retlist = []
83         if type(param) is not list:
84             param = [param]
85         for t in self.l:
86             entry = []
87             for p in param:
88                 entry.append(t[p])
89             if len(entry) == 1:
90                 entry = entry[0]
91             else:
92                 entry = tuple(entry)
93             if not entry in retlist:
94                 retlist.append(entry)
95         retlist.sort()
96         return retlist
97
98 # read the file and return a RingTest object containing all data
99 def read_data_from_file(filename):
100
101     ring_test = RingTest()
102
103     # parse the file: it produces a list of dict containing the data for
104     # each test case (each dict in the list corresponds to a line)
105     f = open(filename)
106     while True:
107         l = f.readline()
108
109         if l == "":
110             break
111
112         regexp  = "ring_autotest "
113         regexp += "e/d_core=%s,%s e/d_bulk=%s,%s "%(INT, INT, INT, INT)
114         regexp += "sp=%s sc=%s "%(INT, INT)
115         regexp += "rate_persec=%s"%(INT)
116         m = re.match(regexp, l)
117         if m == None:
118             continue
119
120         ring_test.add(enq_core = int(m.groups()[0]),
121                       deq_core = int(m.groups()[1]),
122                       enq_bulk = int(m.groups()[2]),
123                       deq_bulk = int(m.groups()[3]),
124                       sp = int(m.groups()[4]),
125                       sc = int(m.groups()[5]),
126                       rate = int(m.groups()[6]))
127
128     f.close()
129     return ring_test
130
131 def millions(x, pos):
132     return '%1.1fM' % (x*1e-6)
133
134 # graph one, with specific parameters -> generate a .svg file
135 def graph_one(str, ring_test, enq_core, deq_core, sp, sc):
136     filename = "ring_%d_%d"%(enq_core, deq_core)
137     if sp:
138         sp_str = "sp"
139     else:
140         sp_str = "mp"
141     if sc:
142         sc_str = "sc"
143     else:
144         sc_str = "mc"
145     filename += "_%s_%s.svg"%(sp_str, sc_str)
146
147
148     enq_bulk_list = ring_test.get_value_list("enq_bulk")
149     N_enq_bulk = len(enq_bulk_list)
150     enq_names = map(lambda x:"enq=%d"%x, enq_bulk_list)
151
152     deq_bulk_list = ring_test.get_value_list("deq_bulk")
153     N_deq_bulk = len(deq_bulk_list)
154     deq_names = map(lambda x:"deq=%d"%x, deq_bulk_list)
155
156     N = N_enq_bulk * (N_deq_bulk + 1)
157     rates = []
158
159     colors = []
160     for enq_bulk in ring_test.get_value_list("enq_bulk"):
161         col = 0.
162         for deq_bulk in ring_test.get_value_list("deq_bulk"):
163             col += 0.9 / len(ring_test.get_value_list("deq_bulk"))
164             r = ring_test.get(enq_core=enq_core, deq_core=deq_core,
165                               enq_bulk=enq_bulk, deq_bulk=deq_bulk,
166                               sp=sp, sc=sc)
167             r = r[0]["rate"]
168             rates.append(r)
169             colors.append((1. - col, 0.2, col, 1.)) # rgba
170
171         rates.append(0)
172         colors.append((0.,0.,0.,0.))
173
174     ind = np.arange(N)  # the x locations for the groups
175     width = 1           # the width of the bars: can also be len(x) sequence
176
177
178     formatter = FuncFormatter(millions)
179     fig = plt.figure()
180     p = plt.bar(ind, tuple(rates), width, color=tuple(colors))
181     fig.axes[0].yaxis.set_major_formatter(formatter)
182
183     plt.ylabel('Obj/sec')
184     #plt.ylim(0, 400000000.)
185     plt.title("Ring autotest \"%s\"\nenq core(s)=%d, deq core(s)=%d, %s, %s"\
186                   %(str, enq_core, deq_core, sp_str, sc_str))
187     ind_names = np.arange(N_enq_bulk) * (N_deq_bulk+1) + (N_deq_bulk+1) / 2
188     plt.xticks(ind_names, tuple(enq_names))
189     plt.legend(tuple([p[i] for i in range(N_deq_bulk)]), tuple(deq_names),
190                loc="upper left")
191     plt.savefig(filename)
192
193 if len(sys.argv) != 3:
194     print "usage: graph_ring.py file title"
195     sys.exit(1)
196
197 ring_test = read_data_from_file(sys.argv[1])
198
199 for enq_core, deq_core, sp, sc in \
200         ring_test.get_value_list(["enq_core", "deq_core", "sp", "sc"]):
201     graph_one(sys.argv[2], ring_test, enq_core, deq_core, sp, sc)