make_graph.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #!/usr/bin/python
  2. import string
  3. import sys
  4. import re
  5. from Numeric import *
  6. from pychart import *
  7. from xml.dom import minidom
  8. class exception:
  9. pass
  10. class res:
  11. """
  12. A 'structure' representing the results of a test.
  13. """
  14. def __init__(self, x_label, y_label, cntnr_list, cntnr_descs, res_sets):
  15. self.x_label = x_label
  16. self.y_label = y_label
  17. self.cntnr_list = cntnr_list
  18. self.cntnr_descs = cntnr_descs
  19. self.res_sets = res_sets
  20. class res_getter:
  21. """
  22. This class returns a res object for some test.
  23. """
  24. class __sorter:
  25. def __accum(self, results):
  26. total = 0
  27. for result in results:
  28. total = total + result[1]
  29. return total
  30. def sort(self, cntnr_list, res_sets):
  31. cntnrs_and_totals = []
  32. for cntnr in cntnr_list:
  33. results = res_sets[cntnr]
  34. total = self.__accum(results)
  35. cntnrs_and_totals.append((cntnr, total))
  36. by_total = lambda x,y: x[1] > y[1] and -1 or 1
  37. cntnrs_and_totals.sort(by_total)
  38. ret = []
  39. for cntnr_and_total in cntnrs_and_totals:
  40. cntnr = cntnr_and_total[0]
  41. ret.append(cntnr)
  42. return ret
  43. def __init__(self, test_infos_f_name):
  44. self.__test_to_container_res_sets = {}
  45. self.__test_to_f_names = {}
  46. tests_dat = minidom.parse(test_infos_f_name)
  47. for test in tests_dat.getElementsByTagName('test'):
  48. test_name = test.attributes['name'].value
  49. self.__test_to_f_names[test_name] = test.getElementsByTagName('file')[0].attributes['name'].value
  50. cntnr_list = []
  51. for cntnr in test.getElementsByTagName('cntnr'):
  52. cntnr_list.append(cntnr.attributes['name'].value)
  53. self.__test_to_container_res_sets[test_name] = cntnr_list
  54. def __get_label(self, tst_dat, label_name):
  55. label = tst_dat.getElementsByTagName(label_name)[0].firstChild.data
  56. label = string.strip(label, '\n')
  57. label = string.strip(label)
  58. return label
  59. def __parse_result_sets(self, f_name, cntnr_list):
  60. tst_dat = minidom.parse(f_name)
  61. x_label = self.__get_label(tst_dat, 'x_name')
  62. y_label = self.__get_label(tst_dat, 'y_name')
  63. parsed_container_list = tst_dat.getElementsByTagName('cntnr')
  64. res_sets = {}
  65. cntnr_descs = {}
  66. for cntnr in parsed_container_list:
  67. cntnr_name = cntnr.attributes["name"].value
  68. res_sets[cntnr_name] = []
  69. for cntnr in parsed_container_list:
  70. cntnr_name = cntnr.attributes["name"].value
  71. cntnr_desc = cntnr.getElementsByTagName('desc')
  72. if res_sets.has_key(cntnr_name):
  73. res_set = []
  74. result_list = cntnr.getElementsByTagName('result')
  75. for result in result_list:
  76. x = string.atol(result.attributes["x"].value)
  77. y = string.atof(result.attributes["y"].value)
  78. res_set.append((x, y))
  79. res_sets[cntnr_name] = res_set
  80. cntnr_descs[cntnr_name] = cntnr_desc[0]
  81. return (x_label, y_label, cntnr_descs, res_sets)
  82. def get(self, res_dir, test_name):
  83. cntnr_list = self.__test_to_container_res_sets[test_name]
  84. f_name = res_dir + '/' + self.__test_to_f_names[test_name]
  85. parsed = self.__parse_result_sets(f_name, cntnr_list)
  86. x_label = parsed[0]
  87. y_label = parsed[1]
  88. cntnr_descs = parsed[2]
  89. res_sets = parsed[3]
  90. cntnr_list = self.__sorter().sort(cntnr_list, res_sets)
  91. return res(x_label, y_label, cntnr_list, cntnr_descs, res_sets)
  92. class image_maker:
  93. """
  94. This class creates a svg file from a result set.
  95. """
  96. class __style_chooser:
  97. def __init__(self):
  98. self.native_re = re.compile(r'n_(?:.*?)')
  99. self.native_tick_mark_0 = tick_mark.blackdtri
  100. self.native_tick_mark_1 = tick_mark.blackdia
  101. self.native_line_style_0 = line_style.gray50_dash1
  102. self.native_line_style_1 = line_style.gray50_dash2
  103. self.mask_re = re.compile(r'mask(?:.*?)')
  104. self.mod_re = re.compile(r'mod(?:.*?)')
  105. self.rb_tree_mmap_rb_tree_set_re = re.compile(r'rb_tree_mmap_rb_tree_set(?:.*?)')
  106. self.rb_tree_mmap_lu_mtf_set_re = re.compile(r'rb_tree_mmap_lu_mtf_set(?:.*?)')
  107. self.splay_re = re.compile(r'splay(?:.*?)')
  108. self.rb_tree_re = re.compile(r'rb_tree(?:.*?)')
  109. self.ov_tree_re = re.compile(r'ov_tree(?:.*?)')
  110. self.splay_tree_re = re.compile(r'splay_tree(?:.*?)')
  111. self.pat_trie_re = re.compile(r'pat_trie(?:.*?)')
  112. self.lc_1div8_1div2_re = re.compile(r'lc_1div8_1div2(?:.*?)')
  113. self.lc_1div8_1div1_re = re.compile(r'lc_1div8_1div1(?:.*?)')
  114. self.mcolc_1div2_re = re.compile(r'mcolc_1div2(?:.*?)')
  115. def choose(self, cntnr):
  116. if self.native_re.search(cntnr):
  117. if cntnr == 'n_pq_vector':
  118. return (self.native_tick_mark_1, self.native_line_style_1)
  119. return (self.native_tick_mark_0, self.native_line_style_0)
  120. # tick_mark predefined
  121. # square, circle3, dia, tri, dtri, star, plus5, x5, gray70dia, blackdtri, blackdia
  122. if self.mask_re.search(cntnr):
  123. clr = color.navy
  124. elif self.mod_re.search(cntnr):
  125. clr = color.green4
  126. elif self.rb_tree_mmap_rb_tree_set_re.search(cntnr):
  127. clr = color.mediumblue
  128. tm = tick_mark.square
  129. elif self.rb_tree_mmap_lu_mtf_set_re.search(cntnr) or cntnr == 'rc_binomial_heap':
  130. clr = color.gray50
  131. tm = tick_mark.dia
  132. elif self.splay_tree_re.search(cntnr) or cntnr == 'binomial_heap':
  133. clr = color.gray58
  134. tm = tick_mark.tri
  135. elif self.rb_tree_re.search(cntnr) or cntnr == 'binary_heap':
  136. clr = color.red3
  137. tm = tick_mark.dtri
  138. elif self.ov_tree_re.search(cntnr) or cntnr == 'thin_heap':
  139. clr = color.orangered1
  140. tm = tick_mark.star
  141. elif self.pat_trie_re.search(cntnr) or cntnr == 'pairing_heap':
  142. clr = color.blueviolet
  143. tm = tick_mark.plus5
  144. else:
  145. sys.stderr.write(cntnr + '\n')
  146. raise exception
  147. # mask / mod
  148. if cntnr.find('lc_1div8_1div') <> -1:
  149. if cntnr.find('mask') <> -1:
  150. # mask
  151. if self.lc_1div8_1div2_re.search(cntnr):
  152. if cntnr.find('nsth') <> -1:
  153. tm = tick_mark.x5
  154. else:
  155. tm = tick_mark.gray70dia
  156. if self.lc_1div8_1div1_re.search(cntnr):
  157. if cntnr.find('nsth') <> -1:
  158. tm = tick_mark.dia
  159. else:
  160. tm = tick_mark.circle3
  161. else:
  162. # mod
  163. if self.lc_1div8_1div2_re.search(cntnr):
  164. if cntnr.find('nsth') <> -1:
  165. tm = tick_mark.tri
  166. else:
  167. tm = tick_mark.square
  168. if self.lc_1div8_1div1_re.search(cntnr):
  169. if cntnr.find('nsth') <> -1:
  170. tm = tick_mark.dtri
  171. else:
  172. tm = tick_mark.star
  173. if self.mcolc_1div2_re.search(cntnr):
  174. tm = tick_mark.circle3
  175. return (tm, line_style.T(color = clr, width = 2))
  176. def __init__(self):
  177. self.__sc = self.__style_chooser()
  178. self.__mmap_re = re.compile('mmap_')
  179. def __container_label_name(self, cntnr):
  180. return self.__mmap_re.sub('\nmmap_\n', cntnr)
  181. def make(self, res, of_name):
  182. print of_name
  183. # theme settings
  184. theme.debug_level = 3
  185. theme.output_format = 'svg'
  186. theme.scale_factor = 2
  187. theme.default_line_width = 0.5
  188. theme.default_font_size = 8
  189. theme.use_color = 1
  190. theme.reinitialize()
  191. # canvas settings
  192. f = file(of_name, "w")
  193. can = canvas.init(f, "svg")
  194. # axes
  195. y_tick_interval = self.__get_y_tics(res)
  196. xaxis = axis.X(format = "/6/i/a-90{}%d",
  197. tic_interval = 200,
  198. label = res.x_label, label_offset = (0, -20))
  199. yaxis = axis.Y(format = "/6/i/a0{}%.2e",
  200. tic_interval = y_tick_interval, tic_label_offset = (-25, 0),
  201. label = res.y_label, label_offset = (-15, 0))
  202. # legend
  203. legend_lines = len(res.cntnr_list)
  204. legend_vloc = 80 + (legend_lines * 10)
  205. legend_hloc = -0
  206. lg = legend.T(loc=(legend_hloc,-legend_vloc),
  207. frame_line_style = None, inter_row_sep = 2)
  208. # plot datasets
  209. ar = area.T(x_axis = xaxis, y_axis = yaxis, legend = lg, size = (240,110), x_range = (0, 2200))
  210. plot_list = []
  211. for cntnr in res.cntnr_list:
  212. style = self.__sc.choose(cntnr)
  213. pl = line_plot.T(label = self.__container_label_name(cntnr),
  214. data = res.res_sets[cntnr],
  215. tick_mark = style[0],
  216. line_style = style[1])
  217. plot_list.append(pl)
  218. for plot in plot_list:
  219. ar.add_plot(plot)
  220. # render image
  221. ar.draw(can)
  222. can.close()
  223. def __get_y_max_min(self, res):
  224. mx = 0
  225. nx = 0
  226. for cntnr in res.cntnr_list:
  227. m = max(d[1] for d in res.res_sets[cntnr])
  228. mx = max(m, mx)
  229. n = min(d[1] for d in res.res_sets[cntnr])
  230. nx = min(n, nx)
  231. return (mx, nx)
  232. def __get_x_max_min(self, res):
  233. mx = 0
  234. nx = 0
  235. for cntnr in res.cntnr_list:
  236. m = max(d[0] for d in res.res_sets[cntnr])
  237. mx = max(m, mx)
  238. n = min(d[0] for d in res.res_sets[cntnr])
  239. nx = min(n, nx)
  240. return (mx, nx)
  241. def __get_y_tics(self, res):
  242. mx = 0
  243. for cntnr in res.cntnr_list:
  244. m = max(d[1] for d in res.res_sets[cntnr])
  245. mx = max(m, mx)
  246. return mx / 5
  247. def main(test_infos_f_name, res_dir, doc_dir):
  248. xmls_dat = minidom.parse(test_infos_f_name)
  249. for test in xmls_dat.getElementsByTagName('test'):
  250. # parse results
  251. test_name = test.attributes['name'].value
  252. res_gtr = res_getter(test_infos_f_name)
  253. res = res_gtr.get(res_dir, test_name)
  254. # generate image
  255. image_mkr = image_maker()
  256. svg_of_name = doc_dir + '/pbds_' + test_name + '.svg'
  257. image_mkr.make(res, svg_of_name)
  258. if __name__ == "__main__":
  259. """
  260. This module takes 3 parameters from the command line:
  261. Tests info XML file name
  262. Test results directory
  263. Image output directory
  264. """
  265. usg = "make_graph.py <test_info_file> <res_dir> <image_dir>\n"
  266. if len(sys.argv) != 4:
  267. sys.stderr.write(usg)
  268. raise exception
  269. main(sys.argv[1], sys.argv[2], sys.argv[3])