1#!/usr/bin/python 2 3import string 4import sys 5import re 6import os 7import platform 8import commands 9from Numeric import * 10from pychart import * 11from xml.dom import minidom 12 13class exception: 14 pass 15 16 17def comp_platform_info(compiler): 18 ret = '<ul>\n' 19 so = commands.getstatusoutput('cat /proc/cpuinfo | grep \'cpu MHz\'') 20 if so[0] == 0: 21 ret += '<li>CPU speed - %s</li>\n' % so[1] 22 so = commands.getstatusoutput('cat /proc/meminfo | grep \'MemTotal\'') 23 if so[0] == 0: 24 ret += '<li>Memory - %s</li>\n' % so[1] 25 ret += '<li>Platform - %s</li>\n' % platform.platform() 26 so = commands.getstatusoutput(compiler + ' --version') 27 if so[0] == 0: 28 ret += '<li>Compiler - %s</li>\n' % so[1] 29 ret += '</ul>\n' 30 return ret 31 32 33class res: 34 """ 35 A 'structure' representing the results of a test. 36 """ 37 def __init__(self, x_label, y_label, cntnr_list, cntnr_descs, res_sets): 38 self.x_label = x_label 39 self.y_label = y_label 40 self.cntnr_list = cntnr_list 41 self.cntnr_descs = cntnr_descs 42 self.res_sets = res_sets 43 44 45class res_getter: 46 """ 47 This class returns a res object for some test. 48 """ 49 class __sorter: 50 def __accum(self, results): 51 total = 0 52 for result in results: 53 total = total + result[1] 54 return total 55 56 def sort(self, cntnr_list, res_sets): 57 cntnrs_and_totals = [] 58 for cntnr in cntnr_list: 59 results = res_sets[cntnr] 60 total = self.__accum(results) 61 cntnrs_and_totals.append((cntnr, total)) 62 by_total = lambda x,y: x[1] > y[1] and -1 or 1 63 cntnrs_and_totals.sort(by_total) 64 ret = [] 65 for cntnr_and_total in cntnrs_and_totals: 66 cntnr = cntnr_and_total[0] 67 ret.append(cntnr) 68 return ret 69 70 def __init__(self, test_infos_f_name): 71 self.__test_to_container_res_sets = {} 72 self.__test_to_f_names = {} 73 tests_dat = minidom.parse(test_infos_f_name) 74 for test in tests_dat.getElementsByTagName('test'): 75 test_name = test.attributes['name'].value 76 self.__test_to_f_names[test_name] = test.getElementsByTagName('file')[0].attributes['name'].value 77 cntnr_list = [] 78 for cntnr in test.getElementsByTagName('cntnr'): 79 cntnr_list.append(cntnr.attributes['name'].value) 80 self.__test_to_container_res_sets[test_name] = cntnr_list 81 82 def __get_label(self, tst_dat, label_name): 83 label = tst_dat.getElementsByTagName(label_name)[0].firstChild.data 84 label = string.strip(label, '\n') 85 label = string.strip(label) 86 return label 87 88 def __parse_res_sets(self, f_name, cntnr_list): 89 tst_dat = minidom.parse(f_name) 90 x_label = self.__get_label(tst_dat, 'x_name') 91 y_label = self.__get_label(tst_dat, 'y_name') 92 parsed_container_list = tst_dat.getElementsByTagName('cntnr') 93 res_sets = {} 94 cntnr_descs = {} 95 for cntnr in parsed_container_list: 96 cntnr_name = cntnr.attributes["name"].value 97 res_sets[cntnr_name] = [] 98 for cntnr in parsed_container_list: 99 cntnr_name = cntnr.attributes["name"].value 100 cntnr_desc = cntnr.getElementsByTagName('desc') 101 if res_sets.has_key(cntnr_name): 102 res_set = [] 103 result_list = cntnr.getElementsByTagName('result') 104 for result in result_list: 105 x = string.atol(result.attributes["x"].value) 106 y = string.atof(result.attributes["y"].value) 107 res_set.append((x, y)) 108 res_sets[cntnr_name] = res_set 109 cntnr_descs[cntnr_name] = cntnr_desc[0] 110 return (x_label, y_label, cntnr_descs, res_sets) 111 112 def get(self, res_dir, test_name): 113 cntnr_list = self.__test_to_container_res_sets[test_name] 114 f_name = res_dir + '/' + self.__test_to_f_names[test_name] 115 parsed = self.__parse_res_sets(f_name, cntnr_list) 116 x_label = parsed[0] 117 y_label = parsed[1] 118 cntnr_descs = parsed[2] 119 res_sets = parsed[3] 120 cntnr_list = self.__sorter().sort(cntnr_list, res_sets) 121 return res(x_label, y_label, cntnr_list, cntnr_descs, res_sets) 122 123 124class png_maker: 125 """ 126 This class creates a png file from a result set. 127 """ 128 class __style_chooser: 129 def __init__(self): 130 self.native_re = re.compile(r'n_(?:.*?)') 131 132 self.native_tick_mark_0 = tick_mark.Circle(size = 4) 133 self.native_tick_mark_1 = tick_mark.Square(size = 4) 134 self.native_line_style_0 = line_style.T(color = color.black, width=2) 135 self.native_line_style_1 = line_style.T(color = color.black, width=2) 136 137 self.mask_re = re.compile(r'mask(?:.*?)') 138 self.mod_re = re.compile(r'mod(?:.*?)') 139 140 self.rb_tree_mmap_rb_tree_set_re = re.compile(r'rb_tree_mmap_rb_tree_set(?:.*?)') 141 self.rb_tree_mmap_lu_mtf_set_re = re.compile(r'rb_tree_mmap_lu_mtf_set(?:.*?)') 142 143 self.splay_re = re.compile(r'splay(?:.*?)') 144 self.rb_tree_re = re.compile(r'rb_tree(?:.*?)') 145 self.ov_tree_re = re.compile(r'ov_tree(?:.*?)') 146 self.splay_tree_re = re.compile(r'splay_tree(?:.*?)') 147 148 self.pat_trie_re = re.compile(r'pat_trie(?:.*?)') 149 150 self.lc_1div8_1div2_re = re.compile(r'lc_1div8_1div2(?:.*?)') 151 self.lc_1div8_1div1_re = re.compile(r'lc_1div8_1div1(?:.*?)') 152 self.mcolc_1div2_re = re.compile(r'mcolc_1div2(?:.*?)') 153 154 def choose(self, cntnr): 155 if self.native_re.search(cntnr): 156 if cntnr == 'n_pq_vector': 157 return (self.native_tick_mark_1, self.native_line_style_1) 158 159 return (self.native_tick_mark_0, self.native_line_style_0) 160 161 # tick_mark predefined 162 # square, circle3, dia, tri, dtri, star, plus5, x5, gray70dia, blackdtri, blackdia 163 if self.mask_re.search(cntnr): 164 clr = color.navy 165 elif self.mod_re.search(cntnr): 166 clr = color.green4 167 elif self.rb_tree_mmap_rb_tree_set_re.search(cntnr): 168 clr = color.mediumblue 169 tm = tick_mark.square 170 elif self.rb_tree_mmap_lu_mtf_set_re.search(cntnr) or cntnr == 'rc_binomial_heap': 171 clr = color.gray50 172 tm = tick_mark.dia 173 elif self.splay_tree_re.search(cntnr) or cntnr == 'binomial_heap': 174 clr = color.gray58 175 tm = tick_mark.tri 176 elif self.rb_tree_re.search(cntnr) or cntnr == 'binary_heap': 177 clr = color.red3 178 tm = tick_mark.dtri 179 elif self.ov_tree_re.search(cntnr) or cntnr == 'thin_heap': 180 clr = color.orangered1 181 tm = tick_mark.star 182 elif self.pat_trie_re.search(cntnr) or cntnr == 'pairing_heap': 183 clr = color.blueviolet 184 tm = tick_mark.plus5 185 else: 186 sys.stderr.write(cntnr + '\n') 187 raise exception 188 189 # mask / mod 190 if cntnr.find('lc_1div8_1div') <> -1: 191 if cntnr.find('mask') <> -1: 192 # mask 193 if self.lc_1div8_1div2_re.search(cntnr): 194 if cntnr.find('nsth') <> -1: 195 tm = tick_mark.x5 196 else: 197 tm = tick_mark.gray70dia 198 if self.lc_1div8_1div1_re.search(cntnr): 199 if cntnr.find('nsth') <> -1: 200 tm = tick_mark.dia 201 else: 202 tm = tick_mark.circle3 203 else: 204 # mod 205 if self.lc_1div8_1div2_re.search(cntnr): 206 if cntnr.find('nsth') <> -1: 207 tm = tick_mark.tri 208 else: 209 tm = tick_mark.square 210 if self.lc_1div8_1div1_re.search(cntnr): 211 if cntnr.find('nsth') <> -1: 212 tm = tick_mark.dtri 213 else: 214 tm = tick_mark.star 215 216 if self.mcolc_1div2_re.search(cntnr): 217 tm = tick_mark.circle3 218 219 return (tm, line_style.T(color = clr, width = 2)) 220 221 222 def __init__(self): 223 self.__sc = self.__style_chooser() 224 self.__mmap_re = re.compile('mmap_') 225 226 def __container_label_name(self, cntnr): 227 return self.__mmap_re.sub('\nmmap_\n', cntnr) 228 229 def make(self, res, of_name): 230 theme.output_format = 'png' 231 theme.output_file = of_name 232 theme.scale_factor = 2 233# theme.default_font_size = 5 234 theme.use_color = 1 235 theme.reinitialize() 236 y_tick_interval = self.__get_y_tics(res) 237 xaxis = axis.X(format = '/a90/hL%d', 238 tic_interval = 200, 239 label = res.x_label) 240 yaxis = axis.Y(format = '%.2e', 241 tic_interval = y_tick_interval, 242 label = res.y_label) 243 legend_lines = len(res.cntnr_list) 244 legend_vloc = 50 + (legend_lines * 10) 245 ar = area.T(x_axis = xaxis, y_axis = yaxis, 246 legend = legend.T(loc=(0,-legend_vloc), 247 frame_line_style=None, 248 inter_row_sep=2), 249 size=(240,110)) 250 plot_list = [] 251 for cntnr in res.cntnr_list: 252 style = self.__sc.choose(cntnr) 253 print cntnr 254 pl = line_plot.T(label = self.__container_label_name(cntnr), 255 data = res.res_sets[cntnr], 256 tick_mark = style[0], 257 line_style = style[1]) 258 plot_list.append(pl) 259 for plot in plot_list: 260 ar.add_plot(plot) 261 ar.draw() 262 263 264 def __get_y_tics(self, res): 265 mx = 0 266 for cntnr in res.cntnr_list: 267 m = max(d[1] for d in res.res_sets[cntnr]) 268 mx = max(m, mx) 269 return mx / 5 270 271 272 273def make_tt(s): 274 return '<tt>' + s + '</tt>' 275 276def make_b(s): 277 return '<b>' + s + '</b>' 278 279def make_ttb(s): 280 return '<tt><b>' + s + '</b></tt>' 281 282def make_i(s): 283 return '<i>' + s + '</i>' 284 285def make_pb_ds_class_href(c_name): 286 return '<a href = "' + c_name + '.html">' + make_tt(c_name) + '</a>\n' 287 288def build_value_to_pb_ds_class_href(s_desc): 289 value = s_desc.attributes['value'].value 290 ret = make_pb_ds_class_href(value) 291 return ret 292 293class hash_desc_to_html_builder: 294 def build_specific_comb_hash_fn(self, s_desc): 295 comb_hash_fn_desc = s_desc.getElementsByTagName('Comb_Hash_Fn')[0] 296 ret = make_tt('Comb_Hash_Fn') 297 ret = ret + ' = ' 298 ret = ret + build_value_to_pb_ds_class_href(comb_hash_fn_desc) 299 return ret 300 301 def __build_nom_denom(self, s_desc): 302 nom_denom = s_desc.attributes['nom'].value + '/' + s_desc.attributes['denom'].value 303 return make_i(nom_denom) 304 305 def __build_lc_trigger_desc(self, s_desc): 306 ret = build_value_to_pb_ds_class_href(s_desc) 307 ret = ret + ' with ' + make_i('α<sub>min</sub>') 308 ret = ret + ' = ' + self.__build_nom_denom(s_desc.getElementsByTagName('alpha_min')[0]) 309 ret = ret + ' and ' + make_i('α<sub>max</sub>') 310 ret = ret + ' = ' + self.__build_nom_denom(s_desc.getElementsByTagName('alpha_max')[0]) 311 return ret 312 313 def build_specific_resize_policy(self, s_desc): 314 ret = make_tt('Resize_Policy') 315 ret = ret + ' = ' 316 resize_policy_desc = s_desc.getElementsByTagName('Resize_Policy')[0] 317 ret = ret + build_value_to_pb_ds_class_href(resize_policy_desc) 318 ret = ret + ' with ' + make_tt('Size_Policy') 319 ret = ret + ' = ' 320 size_policy_desc = resize_policy_desc.getElementsByTagName('Size_Policy')[0] 321 ret = ret + build_value_to_pb_ds_class_href(size_policy_desc) 322 ret = ret + ', and ' + make_tt('Trigger_Policy') 323 ret = ret + ' = ' 324 trigger_policy_desc = resize_policy_desc.getElementsByTagName('Trigger_Policy')[0] 325 if trigger_policy_desc.attributes['value'].value == 'hash_load_check_resize_trigger': 326 ret = ret + self.__build_lc_trigger_desc(trigger_policy_desc) 327 else: 328 raise exception 329 return ret 330 331 332class cc_hash_desc_to_html_builder: 333 def __init__(self): 334 self.__hash_builder = hash_desc_to_html_builder() 335 336 def build(self, s_desc): 337 ret = build_value_to_pb_ds_class_href(s_desc) 338 ret = ret + 'with ' + self.__hash_builder.build_specific_comb_hash_fn(s_desc) 339 ret = ret + ', and ' + self.__hash_builder.build_specific_resize_policy(s_desc) 340 return ret 341 342 343class gp_hash_desc_to_html_builder: 344 def __init__(self): 345 self.__hash_builder = hash_desc_to_html_builder() 346 347 def build(self, s_desc): 348 ret = build_value_to_pb_ds_class_href(s_desc) 349 ret = ret + ' with ' + self.__hash_builder.build_specific_comb_hash_fn(s_desc) 350 ret = ret + ', ' + self.__hash_builder.build_specific_resize_policy(s_desc) 351 ret = ret + ', and ' + make_tt('Probe_Fn') 352 ret = ret + ' = ' 353 probe_fn = s_desc.getElementsByTagName('Probe_Fn')[0].attributes['value'].value 354 ret = ret + make_pb_ds_class_href(probe_fn) 355 return ret 356 357 358class basic_tree_like_desc_to_html_builder: 359 def build_tag(self, s_desc): 360 ret = make_tt('Tag') 361 ret = ret + ' = ' 362 tag_desc = s_desc.getElementsByTagName('Tag')[0] 363 ret = ret + build_value_to_pb_ds_class_href(tag_desc) 364 return ret 365 366 def build_node_update(self, s_desc): 367 ret = make_tt('Node_Update') 368 ret = ret + ' = ' 369 node_update_desc = s_desc.getElementsByTagName('Node_Update')[0] 370 ret = ret + build_value_to_pb_ds_class_href(node_update_desc) 371 return ret 372 373 374class basic_tree_desc_to_html_builder: 375 def __init__(self): 376 self.__tree_like_builder = basic_tree_like_desc_to_html_builder() 377 378 def build(self, s_desc): 379 ret = build_value_to_pb_ds_class_href(s_desc) 380 ret = ret + ' with ' + self.__tree_like_builder.build_tag(s_desc) 381 ret = ret + ', and ' + self.__tree_like_builder.build_node_update(s_desc) 382 return ret 383 384 385class basic_trie_desc_to_html_builder: 386 def __init__(self): 387 self.__tree_like_builder = basic_tree_like_desc_to_html_builder() 388 389 def build(self, s_desc): 390 ret = build_value_to_pb_ds_class_href(s_desc) 391 ret = ret + ' with ' + self.__tree_like_builder.build_tag(s_desc) 392 ret = ret + ', and ' + self.__tree_like_builder.build_node_update(s_desc) 393 return ret 394 395class lu_desc_to_html_builder: 396 def build(self, s_desc): 397 ret = build_value_to_pb_ds_class_href(s_desc) 398 ret = ret + ' with ' + make_tt('Update_Policy') 399 ret = ret + ' = ' 400 update_policy_desc = s_desc.getElementsByTagName('Update_Policy')[0] 401 ret = ret + build_value_to_pb_ds_class_href(update_policy_desc) 402 return ret 403 404 405class std_desc_to_html_builder: 406 def build(self, s_desc): 407 value = s_desc.attributes['value'].value 408 return make_tt(value.replace('std_', 'std::')) 409 410 411class std_tr1_desc_to_html_builder: 412 def build(self, s_desc): 413 value = s_desc.attributes['value'].value 414 ret = make_tt(value.replace('std_tr1_', 'std::tr1::')) 415 ret = ret + ' with ' + make_tt('cache_hash_code') 416 ret = ret + ' = ' 417 cache_hash_code = s_desc.getElementsByTagName('cache_hash_code')[0].attributes['value'].value 418 ret = ret + make_ttb(cache_hash_code) 419 return ret 420 421class gnucxx_desc_to_html_builder: 422 def build(self, s_desc): 423 value = s_desc.attributes['value'].value 424 return make_tt(value.replace('__gnucxx_', '__gnucxx::')) 425 426class stdext_desc_to_html_builder: 427 def build(self, s_desc): 428 value = s_desc.attributes['value'].value 429 return make_tt(value.replace('stdext_', 'stdext::')) 430 431class npq_desc_to_html_builder: 432 def build(self, vector): 433 if vector: 434 under = make_tt('std::vector') 435 else: 436 under = make_tt('std::deque') 437 438 return make_tt('std::priority_queue') + ' adapting ' + under 439 440class binary_heap_desc_to_html_builder: 441 def build(self, s_desc): 442 ret = make_pb_ds_class_href('priority_queue') 443 ret = ret + ' with ' + make_tt('Tag') 444 ret = ret + ' = ' + make_pb_ds_class_href('binary_heap_tag') 445 return ret 446 447class thin_heap_desc_to_html_builder: 448 def build(self, s_desc): 449 ret = make_pb_ds_class_href('priority_queue') 450 ret = ret + ' with ' + make_tt('Tag') 451 ret = ret + ' = ' + make_pb_ds_class_href('thin_heap_tag') 452 return ret 453 454class binomial_heap_desc_to_html_builder: 455 def build(self, s_desc): 456 ret = make_pb_ds_class_href('priority_queue') 457 ret = ret + ' with ' + make_tt('Tag') 458 ret = ret + ' = ' + make_pb_ds_class_href('binomial_heap_tag') 459 return ret 460 461class rc_binomial_heap_desc_to_html_builder: 462 def build(self, s_desc): 463 ret = make_pb_ds_class_href('priority_queue') 464 ret = ret + ' with ' + make_tt('Tag') 465 ret = ret + ' = ' + make_pb_ds_class_href('rc_binomial_heap_tag') 466 return ret 467 468class pairing_heap_desc_to_html_builder: 469 def build(self, s_desc): 470 ret = make_pb_ds_class_href('priority_queue') 471 ret = ret + ' with ' + make_tt('Tag') 472 ret = ret + ' = ' + make_pb_ds_class_href('pairing_heap_tag') 473 return ret 474 475class legend_desc_builder: 476 """ 477 Returns a string corresponding to a specific container type. 478 """ 479 def __init__(self): 480 self.__cc_hash_builder = cc_hash_desc_to_html_builder() 481 self.__gp_hash_builder = gp_hash_desc_to_html_builder() 482 self.__basic_tree_builder = basic_tree_desc_to_html_builder() 483 self.__basic_trie_builder = basic_trie_desc_to_html_builder() 484 self.__lu_builder = lu_desc_to_html_builder() 485 self.__std_builder = std_desc_to_html_builder() 486 self.__std_tr1_builder = std_tr1_desc_to_html_builder() 487 self.__gnucxx_builder = gnucxx_desc_to_html_builder() 488 self.__stdext_builder = stdext_desc_to_html_builder() 489 self.__npq_builder = npq_desc_to_html_builder() 490 self.__thin_heap_builder = thin_heap_desc_to_html_builder() 491 self.__thin_heap_builder = thin_heap_desc_to_html_builder() 492 self.__binary_heap_builder = binary_heap_desc_to_html_builder() 493 self.__binomial_heap_builder = binomial_heap_desc_to_html_builder() 494 self.__rc_binomial_heap_builder = rc_binomial_heap_desc_to_html_builder() 495 self.__pairing_heap_builder = pairing_heap_desc_to_html_builder() 496 497 def __build_specific(self, s_desc): 498 type = s_desc.attributes['value'].value 499 500 if type == 'thin_heap': 501 return self.__thin_heap_builder.build(s_desc) 502 if type == 'binary_heap': 503 return self.__binary_heap_builder.build(s_desc) 504 if type == 'binomial_heap': 505 return self.__binomial_heap_builder.build(s_desc) 506 if type == 'rc_binomial_heap': 507 return self.__rc_binomial_heap_builder.build(s_desc) 508 if type == 'pairing_heap': 509 return self.__pairing_heap_builder.build(s_desc) 510 if type == 'cc_hash_table': 511 ret = self.__cc_hash_builder.build(s_desc) 512 elif type == 'gp_hash_table': 513 ret = self.__gp_hash_builder.build(s_desc) 514 elif type == 'tree': 515 ret = self.__basic_tree_builder.build(s_desc) 516 elif type == 'trie': 517 ret = self.__basic_trie_builder.build(s_desc) 518 elif type == 'list_update': 519 ret = self.__lu_builder.build(s_desc) 520 elif type == 'std::priority_queue_vector': 521 return self.__npq_builder.build(True) 522 elif type == 'std::priority_queue_deque': 523 return self.__npq_builder.build(False) 524 elif type == 'std_set' or type == 'std_map' or type == 'std_multimap': 525 return self.__std_builder.build(s_desc) 526 elif type == 'std_tr1_unordered_set' or type == 'std_tr1_unordered_map': 527 return self.__std_tr1_builder.build(s_desc) 528 elif type == 'stdext_hash_set' or type == 'stdext_hash_map' or type == 'stdext_hash_multimap': 529 return self.__stdext_builder.build(s_desc) 530 elif type == '__gnucxx_hash_set' or type == '__gnucxx_hash_map' or type == '__gnucxx_hash_multimap': 531 return self.__gnucxx_builder.build(s_desc) 532 else: 533 sys.stderr.write('cannot recognize %s\n' % type) 534 raise exception 535 return ret 536 537 538 def build(self, desc): 539 s_descs = desc.getElementsByTagName('type') 540 if s_descs.length == 0: 541 print desc.toxml() 542 raise exception 543 ret = '' 544 count = 0 545 for s_desc in s_descs: 546 if count > 0: 547 ret = ret + ', mapping each key to ' 548 ret = ret + self.__build_specific(s_desc) 549 count = count + 1 550 return ret 551 552 553def main(doc_dir, res_dir, test_infos_f_name, test_name, build_name): 554 res_gtr = res_getter(test_infos_f_name) 555 res = res_gtr.get(res_dir, test_name) 556 png_mkr = png_maker() 557 png_of_name = doc_dir + '/' + test_name + '_' + build_name + '.png' 558 print png_of_name 559 png_mkr.make(res, png_of_name) 560 561 562if __name__ == "__main__": 563 """ 564 This module takes 6 parameters from the command line: 565 Docs directory 566 Results directory 567 Tests info XML file name 568 Test name 569 Build name 570 Compiler name 571 """ 572 usg = "make_graph.py <doc_dir> <res_dir> <test_info_file> <test_name> <build_name>\n" 573 if len(sys.argv) != 6: 574 sys.stderr.write(usg) 575 raise exception 576 main(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) 577