1 | /* |
2 | * performance_util.hpp |
3 | * |
4 | * Created on: Jul 21, 2019 |
5 | * Author: i-bird |
6 | */ |
7 | |
8 | #ifndef PERFORMANCE_UTIL_HPP_ |
9 | #define PERFORMANCE_UTIL_HPP_ |
10 | |
11 | #include <boost/lexical_cast.hpp> |
12 | #include <boost/filesystem.hpp> |
13 | #include <boost/property_tree/ptree.hpp> |
14 | #include <boost/property_tree/xml_parser.hpp> |
15 | |
16 | static void addUpdtateTime(GoogleChart & cg, int np) |
17 | { |
18 | time_t t = time(0); // get time now |
19 | struct tm * now = localtime( & t ); |
20 | |
21 | std::stringstream str; |
22 | |
23 | std::string commit; |
24 | commit = exec("git rev-parse HEAD" ); |
25 | |
26 | str << "<h3>Updated: " << now->tm_mday << "/" << now->tm_mon + 1 << "/" << now->tm_year+1900 << " " << now->tm_hour << ":" << now->tm_min << ":" |
27 | << now->tm_sec << " commit: " << commit << " run with: " << np << " processes" << std::endl; |
28 | |
29 | cg.addHTML(str.str()); |
30 | } |
31 | |
32 | static inline void warning_set(int & warning_level, double mean, double mean_ref, double sigma) |
33 | { |
34 | int warning_level_candidate; |
35 | |
36 | if (mean - mean_ref < -2.0*sigma ) |
37 | warning_level_candidate = -1; |
38 | else if (mean - mean_ref < 2.0*sigma) |
39 | warning_level_candidate = 0; |
40 | else if (mean - mean_ref < 3.0*sigma) |
41 | warning_level_candidate = 1; |
42 | else |
43 | warning_level_candidate = 2; |
44 | |
45 | if (warning_level_candidate > warning_level) |
46 | warning_level = warning_level_candidate; |
47 | } |
48 | |
49 | static inline void addchartarea(std::string & chart_area, int lvl) |
50 | { |
51 | std::string color; |
52 | |
53 | if (lvl == -1) |
54 | { |
55 | chart_area = std::string(",chartArea: {\ |
56 | backgroundColor: {\ |
57 | stroke: '#00FF00',\ |
58 | strokeWidth: 6\ |
59 | }\ |
60 | }" ); |
61 | } |
62 | else if (lvl == 0) |
63 | { |
64 | // NOTHING TO DO |
65 | } |
66 | else if (lvl == 1) |
67 | { |
68 | chart_area = std::string(",chartArea: {\ |
69 | backgroundColor: {\ |
70 | stroke: '#FFFF00',\ |
71 | strokeWidth: 6\ |
72 | }\ |
73 | }" ); |
74 | } |
75 | else if (lvl == 2) |
76 | { |
77 | chart_area = std::string(",chartArea: {\ |
78 | backgroundColor: {\ |
79 | stroke: '#FF0000',\ |
80 | strokeWidth: 6\ |
81 | }\ |
82 | }" ); |
83 | } |
84 | |
85 | } |
86 | |
87 | /*! \brief Check of a string is a float |
88 | * |
89 | * \param something strign to check if it is a number |
90 | * |
91 | */ |
92 | static bool isFloat(const std::string &someString) |
93 | { |
94 | using boost::lexical_cast; |
95 | using boost::bad_lexical_cast; |
96 | |
97 | try |
98 | {boost::lexical_cast<float>(someString);} |
99 | catch (bad_lexical_cast &) |
100 | {return false;} |
101 | |
102 | return true; |
103 | } |
104 | |
105 | static void StandardXMLPerformanceGraph(std::string file_xml, |
106 | std::string file_xml_ref, |
107 | GoogleChart & cg, |
108 | const double deviationMultiplier = 3.0) |
109 | { |
110 | // Create empty property tree object |
111 | boost::property_tree::ptree tree_measure; |
112 | |
113 | // Parse the XML into the property tree. |
114 | boost::property_tree::read_xml(file_xml, tree_measure); |
115 | |
116 | // Create empty property tree object |
117 | boost::property_tree::ptree tree_reference; |
118 | |
119 | // We check if exist the reference file. If does not exist copy the file_xml into the report folder |
120 | if (boost::filesystem::exists(file_xml_ref) == false ) |
121 | { |
122 | boost::filesystem::copy_file(file_xml,file_xml_ref); |
123 | } |
124 | |
125 | // Parse the JSON into the property tree. |
126 | boost::property_tree::read_xml(file_xml_ref, tree_reference); |
127 | |
128 | // First we check for graphs |
129 | |
130 | // try |
131 | { |
132 | boost::property_tree::ptree childs = tree_measure.get_child("graphs" ); |
133 | |
134 | for (auto & c: childs) |
135 | { |
136 | std::string type = c.second.template get<std::string>("type" ,"" ); |
137 | // discorver the number of points |
138 | int number = 0; |
139 | openfpm::vector<std::string> yn; |
140 | |
141 | while (1) |
142 | { |
143 | if (c.second.template get<std::string>("y.data(" + std::to_string(number) + ").title" ,"" ) == "" ) |
144 | {break;} |
145 | yn.add(c.second.template get<std::string>("y.data(" + std::to_string(number) + ").title" , |
146 | "line" + std::to_string(number))); |
147 | yn.add("interval" ); |
148 | yn.add("interval" ); |
149 | number++; |
150 | } |
151 | |
152 | bool is_log_x = c.second.template get<bool>("options.log_x" ,false); |
153 | bool is_log_y = c.second.template get<bool>("options.log_y" ,false); |
154 | |
155 | // We process the graph |
156 | std::string title = c.second.template get<std::string>("title" ,"" ); |
157 | std::string x_title = c.second.template get<std::string>("x.title" ,"" ); |
158 | std::string y_title = c.second.template get<std::string>("y.title" ,"" ); |
159 | |
160 | // This is optional |
161 | |
162 | std::string preHTML = c.second.template get<std::string>("preHTML" ,"" ); |
163 | std::string postHTML = c.second.template get<std::string>("postHTML" ,"" ); |
164 | |
165 | openfpm::vector<openfpm::vector<double>> x; |
166 | openfpm::vector<openfpm::vector<std::string>> xs; |
167 | openfpm::vector<openfpm::vector<double>> y; |
168 | |
169 | openfpm::vector<openfpm::vector<double>> x_ref; |
170 | openfpm::vector<openfpm::vector<double>> y_ref_up; |
171 | openfpm::vector<openfpm::vector<double>> y_ref_dw; |
172 | |
173 | int warning_level = -1; |
174 | bool is_literal_x = false; |
175 | |
176 | for (size_t i = 0 ; i < number ; i++) |
177 | { |
178 | x.add(); |
179 | xs.add(); |
180 | y.add(); |
181 | |
182 | x_ref.add(); |
183 | y_ref_up.add(); |
184 | y_ref_dw.add(); |
185 | |
186 | std::string xv = c.second.template get<std::string>("x.data(" + std::to_string(i) + ").source" ,"" ); |
187 | std::string yv = c.second.template get<std::string>("y.data(" + std::to_string(i) + ").source" ,"" ); |
188 | |
189 | // Get the numbers |
190 | |
191 | int j = 0; |
192 | while (1) |
193 | { |
194 | std::string xv_ = xv; |
195 | std::string yv_ = yv; |
196 | |
197 | int xpos = xv_.find("#" ); |
198 | int ypos = yv_.find("#" ); |
199 | |
200 | xv_.replace(xpos,1,std::to_string(j)); |
201 | yv_.replace(ypos,1,std::to_string(j)); |
202 | |
203 | if (tree_measure.template get<std::string>(xv_,"" ) == "" ) |
204 | { |
205 | if (j == 0) |
206 | { |
207 | std::cout << "WARNING: Not found " << xv_ << " in file: " << file_xml << std::endl; |
208 | } |
209 | break; |
210 | } |
211 | |
212 | std::string tmp = tree_measure.template get<std::string>(xv_,"" ); |
213 | |
214 | double x_val; |
215 | std::string x_val_str; |
216 | if (isFloat(tmp) == true) |
217 | {x_val = tree_measure.template get<double>(xv_,0.0);} |
218 | else |
219 | { |
220 | is_literal_x = true; |
221 | xs.last().add(tmp); |
222 | } |
223 | |
224 | double y_val = tree_measure.template get<double>(yv_,0.0); |
225 | |
226 | double x_val_ref = tree_reference.template get<double>(xv_,0.0); |
227 | double y_val_ref = tree_reference.template get<double>(yv_,0.0); |
228 | |
229 | if (y_val_ref == 0.0) |
230 | { |
231 | std::cout << "WARNING: " << yv_ << " does not exist on the reference file: " << file_xml_ref << std::endl; |
232 | } |
233 | |
234 | ypos = yv_.find(".mean" ); |
235 | std::string yv_dev = yv_.replace(ypos,5,".dev" ); |
236 | double y_val_dev_ref = tree_reference.template get<double>(yv_,0.0); |
237 | |
238 | if (y_val_dev_ref == 0.0) |
239 | { |
240 | std::cout << "WARNING: " << yv_ << " does not exist on the reference file: " << file_xml_ref << std::endl; |
241 | } |
242 | |
243 | x.last().add(x_val); |
244 | y.last().add(y_val); |
245 | |
246 | x_ref.last().add(x_val_ref); |
247 | y_ref_dw.last().add(y_val_ref - deviationMultiplier * y_val_dev_ref); |
248 | y_ref_up.last().add(y_val_ref + deviationMultiplier * y_val_dev_ref); |
249 | |
250 | warning_set(warning_level,y_val,y_val_ref,y_val_dev_ref); |
251 | |
252 | j++; |
253 | } |
254 | } |
255 | |
256 | if (type == "line" ) |
257 | { |
258 | GCoptions opt; |
259 | |
260 | std::string chart_area; |
261 | addchartarea(chart_area,warning_level); |
262 | opt.curveType = c.second.template get<std::string>("interpolation" ,"function" ); |
263 | // opt.curveType = c.second.template get<std::string>("interpolation","none"); |
264 | |
265 | if (is_log_x == true) |
266 | { |
267 | opt.more = GC_X_LOG + "," + GC_ZOOM + chart_area; |
268 | } |
269 | else |
270 | { |
271 | opt.more = GC_ZOOM + chart_area; |
272 | } |
273 | |
274 | if (is_log_y == true) |
275 | { |
276 | opt.more = GC_Y_LOG + "," + GC_ZOOM + chart_area; |
277 | } |
278 | else |
279 | { |
280 | opt.more = GC_ZOOM + chart_area; |
281 | } |
282 | |
283 | opt.title = title; |
284 | opt.xAxis = x_title; |
285 | opt.yAxis = y_title; |
286 | |
287 | if (is_literal_x == false) |
288 | { |
289 | if (x.size() == 1) |
290 | { |
291 | cg.AddLines(yn,opt,x.get(0),y.get(0), |
292 | x_ref.get(0),y_ref_dw.get(0), |
293 | x_ref.get(0),y_ref_up.get(0)); |
294 | } |
295 | if (x.size() == 2) |
296 | { |
297 | cg.AddLines(yn,opt,x.get(0),y.get(0), |
298 | x_ref.get(0),y_ref_dw.get(0),x_ref.get(0),y_ref_up.get(0), |
299 | x.get(1),y.get(1), |
300 | x_ref.get(1),y_ref_dw.get(1),x_ref.get(1),y_ref_up.get(1)); |
301 | } |
302 | if (x.size() == 3) |
303 | { |
304 | cg.AddLines(yn,opt,x.get(0),y.get(0), |
305 | x_ref.get(0),y_ref_dw.get(0),x_ref.get(0),y_ref_up.get(0), |
306 | x.get(1),y.get(1), |
307 | x_ref.get(1),y_ref_dw.get(1),x_ref.get(1),y_ref_up.get(1), |
308 | x.get(2),y.get(2), |
309 | x_ref.get(2),y_ref_dw.get(2),x_ref.get(2),y_ref_up.get(2)); |
310 | } |
311 | if (x.size() == 4) |
312 | { |
313 | cg.AddLines(yn,opt,x.get(0),y.get(0), |
314 | x_ref.get(0),y_ref_dw.get(0),x_ref.get(0),y_ref_up.get(0), |
315 | x.get(1),y.get(1), |
316 | x_ref.get(1),y_ref_dw.get(1),x_ref.get(1),y_ref_up.get(1), |
317 | x.get(2),y.get(2), |
318 | x_ref.get(2),y_ref_dw.get(2),x_ref.get(2),y_ref_up.get(2), |
319 | x.get(3),y.get(3), |
320 | x_ref.get(3),y_ref_dw.get(3),x_ref.get(3),y_ref_up.get(3)); |
321 | } |
322 | if (x.size() == 5) |
323 | { |
324 | cg.AddLines(yn,opt,x.get(0),y.get(0), |
325 | x_ref.get(0),y_ref_dw.get(0),x_ref.get(0),y_ref_up.get(0), |
326 | x.get(1),y.get(1), |
327 | x_ref.get(1),y_ref_dw.get(1),x_ref.get(1),y_ref_up.get(1), |
328 | x.get(2),y.get(2), |
329 | x_ref.get(2),y_ref_dw.get(2),x_ref.get(2),y_ref_up.get(2), |
330 | x.get(3),y.get(3), |
331 | x_ref.get(3),y_ref_dw.get(3),x_ref.get(3),y_ref_up.get(3), |
332 | x.get(4),y.get(4), |
333 | x_ref.get(4),y_ref_dw.get(4),x_ref.get(4),y_ref_up.get(4)); |
334 | } |
335 | if (x.size() == 6) |
336 | { |
337 | cg.AddLines(yn,opt,x.get(0),y.get(0), |
338 | x_ref.get(0),y_ref_dw.get(0),x_ref.get(0),y_ref_up.get(0), |
339 | x.get(1),y.get(1), |
340 | x_ref.get(1),y_ref_dw.get(1),x_ref.get(1),y_ref_up.get(1), |
341 | x.get(2),y.get(2), |
342 | x_ref.get(2),y_ref_dw.get(2),x_ref.get(2),y_ref_up.get(2), |
343 | x.get(3),y.get(3), |
344 | x_ref.get(3),y_ref_dw.get(3),x_ref.get(3),y_ref_up.get(3), |
345 | x.get(4),y.get(4), |
346 | x_ref.get(4),y_ref_dw.get(4),x_ref.get(4),y_ref_up.get(4), |
347 | x.get(5),y.get(5), |
348 | x_ref.get(5),y_ref_dw.get(5),x_ref.get(5),y_ref_up.get(5)); |
349 | } |
350 | } |
351 | else |
352 | { |
353 | openfpm::vector<openfpm::vector<double>> y_tmp; |
354 | |
355 | y_tmp.resize(x.get(0).size()); |
356 | |
357 | for (size_t i = 0 ; i < x.size() ; i++) |
358 | { |
359 | for (size_t j = 0 ; j < x.get(i).size() ; j++) |
360 | { |
361 | y_tmp.get(j).add(y.get(i).get(j)); |
362 | y_tmp.get(j).add(y_ref_dw.get(i).get(j)); |
363 | y_tmp.get(j).add(y_ref_up.get(i).get(j)); |
364 | } |
365 | } |
366 | |
367 | cg.AddLinesGraph(xs.get(0),y_tmp,yn,opt); |
368 | } |
369 | } |
370 | } |
371 | } |
372 | // catch (std::exception e) |
373 | // { |
374 | // std::cout << __FILE__ << ":" << __LINE__ << " Error: invalid xml for performance test " << e.what() << std::endl; |
375 | // } |
376 | |
377 | } |
378 | |
379 | |
380 | #endif /* PERFORMANCE_UTIL_HPP_ */ |
381 | |