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