Commit | Line | Data |
---|---|---|
b87dc589 FD |
1 | # Copyright (C) 2017 - Francis Deslauriers <francis.deslauriers@efficios.com> |
2 | # | |
3 | # This program is free software: you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation, either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # This program is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
16 | ||
17 | import os, sys | |
18 | import numpy as np | |
19 | import pandas as pd | |
20 | ||
21 | #Set Matplotlib to use the PNG non interactive backend | |
22 | import matplotlib as mpl | |
23 | mpl.use('Agg') | |
24 | ||
25 | import matplotlib.pyplot as plt | |
26 | from matplotlib.ticker import MaxNLocator | |
27 | from cycler import cycler | |
58a2fcd3 | 28 | from collections import OrderedDict |
b87dc589 FD |
29 | |
30 | def rename_cols(df): | |
f758d98b FD |
31 | new_cols = {'baseline_1thr_peritermean': 'basel_1thr', |
32 | 'baseline_2thr_peritermean': 'basel_2thr', | |
33 | 'baseline_4thr_peritermean': 'basel_4thr', | |
34 | 'baseline_8thr_peritermean': 'basel_8thr', | |
35 | 'baseline_16thr_peritermean': 'basel_16thr', | |
36 | 'lttng_1thr_peritermean': 'lttng_1thr', | |
37 | 'lttng_2thr_peritermean': 'lttng_2thr', | |
38 | 'lttng_4thr_peritermean': 'lttng_4thr', | |
39 | 'lttng_8thr_peritermean': 'lttng_8thr', | |
094ca2d3 FD |
40 | 'lttng_16thr_peritermean': 'lttng_16thr', |
41 | 'baseline_1thr_periterstdev': 'basel_1thr_stdev', | |
42 | 'baseline_2thr_periterstdev': 'basel_2thr_stdev', | |
43 | 'baseline_4thr_periterstdev': 'basel_4thr_stdev', | |
44 | 'baseline_8thr_periterstdev': 'basel_8thr_stdev', | |
45 | 'baseline_16thr_periterstdev': 'basel_16thr_stdev', | |
46 | 'lttng_1thr_periterstdev': 'lttng_1thr_stdev', | |
47 | 'lttng_2thr_periterstdev': 'lttng_2thr_stdev', | |
48 | 'lttng_4thr_periterstdev': 'lttng_4thr_stdev', | |
49 | 'lttng_8thr_periterstdev': 'lttng_8thr_stdev', | |
50 | 'lttng_16thr_periterstdev': 'lttng_16thr_stdev' | |
b87dc589 FD |
51 | } |
52 | df.rename(columns=new_cols, inplace=True) | |
53 | return df | |
54 | ||
c5545ca0 FD |
55 | def convert_us_to_ns(df): |
56 | cols = [col for col in df.columns if 'periter' in col] | |
57 | df[cols] = df[cols].apply(lambda x: x*1000) | |
58 | return df | |
59 | ||
b87dc589 | 60 | def create_plot(df, graph_type): |
58a2fcd3 FD |
61 | # We map all test configurations and their |
62 | # respective color | |
63 | conf_to_color = OrderedDict([ | |
64 | ('basel_1thr','lightcoral'), | |
65 | ('lttng_1thr','red'), | |
66 | ('basel_2thr','gray'), | |
67 | ('lttng_2thr','black'), | |
68 | ('basel_4thr','chartreuse'), | |
69 | ('lttng_4thr','forestgreen'), | |
70 | ('basel_8thr','deepskyblue'), | |
71 | ('lttng_8thr','mediumblue'), | |
72 | ('basel_16thr','orange'), | |
73 | ('lttng_16thr','saddlebrown')]) | |
74 | ||
75 | # We create a list for each of the subplots | |
76 | baseline = [x for x in conf_to_color.keys() if 'basel' in x] | |
77 | lttng = [x for x in conf_to_color.keys() if 'lttng' in x] | |
78 | one_thr = [x for x in conf_to_color.keys() if '_1thr' in x] | |
79 | two_thr = [x for x in conf_to_color.keys() if '_2thr' in x] | |
80 | four_thr = [x for x in conf_to_color.keys() if '_4thr' in x] | |
81 | eight_thr = [x for x in conf_to_color.keys() if '_8thr' in x] | |
82 | sixteen_thr = [x for x in conf_to_color.keys() if '_16thr' in x] | |
83 | ||
84 | plots = [baseline, lttng, one_thr, two_thr, four_thr, eight_thr, sixteen_thr] | |
b87dc589 | 85 | |
42413939 | 86 | title='Meantime per event for {} testcase'.format(graph_type) |
b87dc589 | 87 | |
58a2fcd3 FD |
88 | # Create a axe object for each sub-plots |
89 | f, arrax = plt.subplots(len(plots), sharex=True, figsize=(16, 25)) | |
90 | f.suptitle(title, fontsize=20) | |
b87dc589 | 91 | |
58a2fcd3 | 92 | for (ax, data_cols) in zip(arrax, plots): |
094ca2d3 FD |
93 | curr_df = df[data_cols] |
94 | ||
58a2fcd3 FD |
95 | stdev_cols = ['{}_stdev'.format(x) for x in data_cols] |
96 | # Extract the color for each configuration | |
97 | colors = [conf_to_color[x] for x in data_cols] | |
98 | ||
094ca2d3 | 99 | # set the color cycler for this plot |
b87dc589 | 100 | ax.set_prop_cycle(cycler('color', colors)) |
094ca2d3 FD |
101 | |
102 | # Plot each line and its errorbars | |
103 | for (data, stdev) in zip(data_cols, stdev_cols): | |
bb43133f | 104 | ax.errorbar(x=df.index.values, y=df[data].values, yerr=df[stdev].values, marker='o') |
094ca2d3 | 105 | |
b87dc589 FD |
106 | ax.set_ylim(0) |
107 | ax.grid() | |
108 | ax.set_xlabel('Jenkins Build ID') | |
42413939 | 109 | ax.set_ylabel('Meantime per event [us]') |
58a2fcd3 | 110 | |
bb43133f | 111 | ax.xaxis.set_major_locator(MaxNLocator(integer=True, nbins=30)) |
b87dc589 | 112 | |
58a2fcd3 FD |
113 | ax.legend(prop={'family': 'monospace'}, |
114 | labels=curr_df.columns.values, bbox_to_anchor=(1.2,1)) | |
115 | ||
116 | plt.subplots_adjust(top=0.95) | |
b87dc589 FD |
117 | plt.savefig('{}.png'.format(graph_type), bbox_inches='tight') |
118 | ||
119 | # Writes a file that contains commit id of all configurations shown in the | |
120 | # plots | |
121 | def create_metadata_file(res_dir): | |
122 | list_ = [] | |
123 | for dirname, dirnames, res_files in os.walk('./'+res_dir): | |
124 | if len(dirnames) > 0: | |
125 | continue | |
f18335da FD |
126 | try: |
127 | metadata = pd.read_csv(os.path.join(dirname, 'metadata.csv')) | |
128 | except Exception: | |
129 | print('Omitting run {} because metadata.csv is missing'.format(dirname)) | |
130 | continue | |
b87dc589 FD |
131 | list_.append(metadata) |
132 | ||
e7e59cc4 | 133 | df = pd.concat(list_, sort=True) |
b87dc589 FD |
134 | df.index=df.build_id |
135 | df.sort_index(inplace=True) | |
136 | df.to_csv('metadata.csv', index=False) | |
137 | ||
138 | #Iterates over a result directory and creates the plots for the different | |
139 | #testcases | |
140 | def create_plots(res_dir): | |
141 | df = pd.DataFrame() | |
142 | metadata_df = pd.DataFrame() | |
143 | list_ = [] | |
144 | for dirname, dirnames, res_files in os.walk('./'+res_dir): | |
145 | if len(dirnames) > 0: | |
146 | continue | |
f18335da FD |
147 | try: |
148 | metadata = pd.read_csv(os.path.join(dirname, 'metadata.csv')) | |
149 | except Exception: | |
150 | print('Omitting run {} because metadata.csv is missing'.format(dirname)) | |
151 | continue | |
b87dc589 FD |
152 | |
153 | for res in res_files: | |
154 | if res in 'metadata.csv': | |
155 | continue | |
156 | tmp = pd.read_csv(os.path.join(dirname, res)) | |
157 | #Use the build id as the index for the dataframe for filtering | |
158 | tmp.index = metadata.build_id | |
159 | #Add the testcase name to the row for later filtering | |
160 | tmp['testcase'] = res.split('.')[0] | |
161 | list_.append(tmp) | |
162 | ||
e7e59cc4 | 163 | df = pd.concat(list_, sort=True) |
c5545ca0 | 164 | df = convert_us_to_ns(df) |
b87dc589 FD |
165 | df = rename_cols(df) |
166 | df.sort_index(inplace=True) | |
167 | ||
168 | #Go over the entire dataframe by testcase and create a plot for each type | |
169 | for testcase in df.testcase.unique(): | |
170 | df_testcase = df.loc[df['testcase'] == testcase] | |
171 | create_plot(df=df_testcase, graph_type=testcase) | |
172 | ||
173 | def main(): | |
174 | res_path = sys.argv[1] | |
175 | create_plots(os.path.join(res_path)) | |
176 | create_metadata_file(os.path.join(res_path)) | |
177 | ||
178 | if __name__ == '__main__': | |
179 | main() |