extractDb.py 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184
  1. import argparse
  2. import sqlite3
  3. import re
  4. import pandas as pd
  5. import numpy as np
  6. from TestScripts.doc.Structure import *
  7. from TestScripts.doc.Format import *
  8. import os.path
  9. import yaml
  10. refCoreName=""
  11. # Command to get last runid
  12. lastID="""SELECT runid FROM RUN ORDER BY runid DESC LIMIT 1
  13. """
  14. # Command to get last runid and date
  15. lastIDAndDate="""SELECT date FROM RUN WHERE runid=?
  16. """
  17. # Command to get last runid
  18. runIDDetails="""SELECT distinct core FROM %s
  19. INNER JOIN CORE USING(coreid)
  20. WHERE %s
  21. """
  22. def joinit(iterable, delimiter):
  23. # Intersperse a delimiter between element of a list
  24. it = iter(iterable)
  25. yield next(it)
  26. for x in it:
  27. yield delimiter
  28. yield x
  29. def getLastRunID():
  30. r=c.execute(lastID)
  31. return(int(r.fetchone()[0]))
  32. def getrunIDDate(forID):
  33. r=c.execute(lastIDAndDate,(forID,))
  34. return(r.fetchone()[0])
  35. parser = argparse.ArgumentParser(description='Generate summary benchmarks')
  36. parser.add_argument('-b', nargs='?',type = str, default="bench.db", help="Database")
  37. parser.add_argument('-o', nargs='?',type = str, default="full.md", help="Full summary")
  38. parser.add_argument('-r', action='store_true', help="Regression database")
  39. parser.add_argument('-t', nargs='?',type = str, default="md", help="type md or html")
  40. parser.add_argument('-byc', action='store_true', help="Result oganized by Compiler")
  41. parser.add_argument('-g', action='store_true', help="Include graphs in regression report")
  42. parser.add_argument('-details', action='store_true', help="Details about runids")
  43. parser.add_argument('-lastid', action='store_true', help="Get last ID")
  44. parser.add_argument('-comments', nargs='?',type = str, default="comments", help="Comment folder")
  45. parser.add_argument('-byd', action='store_true', help="Result oganized by datatype")
  46. parser.add_argument('-ratio', action='store_true', help="Compute ratios for regression by core instead of cycles")
  47. parser.add_argument('-ref', nargs='?',type = str, default="M55", help="Reference COREDEF for ratio in db")
  48. parser.add_argument('-clampval', nargs='?',type = float, default=8.0, help="Clamp for ratio")
  49. parser.add_argument('-clamp', action='store_true', help="Clamp enabled for ratio")
  50. parser.add_argument('-cores', nargs='?',type = str, help="Cores to keep")
  51. parser.add_argument('-toc', nargs='?',type = str, help="Yaml for the table of contents")
  52. # For runid or runid range
  53. parser.add_argument('others', nargs=argparse.REMAINDER,help="Run ID")
  54. args = parser.parse_args()
  55. c = sqlite3.connect(args.b)
  56. coreidSQL="select distinct coreid from CORE where coredef==?"
  57. def getCoreID(corename):
  58. r=c.execute(coreidSQL,(corename,))
  59. t=r.fetchone()
  60. if t is None:
  61. print("Unrecognized reference core \"%s\"" % corename)
  62. quit()
  63. return(t[0])
  64. def parseSelector(o,field="runid"):
  65. vals=[]
  66. runidCMD=[]
  67. # parameters are not allowed in VIEWs
  68. runidVIEWcmd=[]
  69. for t in o:
  70. if re.search(r'-',t):
  71. bounds=[int(x) for x in t.split("-")]
  72. vals += bounds
  73. runidCMD += ["(%s >= ? AND %s <= ?)" % (field,field)]
  74. x=(field,bounds[0],field,bounds[1])
  75. runidVIEWcmd += ["(%s >= %d AND %s <= %d)" % x]
  76. else:
  77. theid=int(t)
  78. runidCMD += ["%s == ?" % field]
  79. runidVIEWcmd += ["%s == %d" % (field,theid)]
  80. vals.append(theid)
  81. runidval = tuple(vals)
  82. runidCMD = "(" + "".join(joinit(runidCMD," OR ")) + ")"
  83. runidVIEWcmd = "(" + "".join(joinit(runidVIEWcmd," OR ")) + ")"
  84. return(runidval,runidCMD,runidVIEWcmd)
  85. if args.others:
  86. runidval,runidCMD,runidVIEWcmd = parseSelector(args.others)
  87. else:
  88. theid=getLastRunID()
  89. print("Last run ID = %d\n" % theid)
  90. runidval=(theid,)
  91. runidCMD = "runid = ?"
  92. runidVIEWcmd="(runid = %d)" % theid
  93. # None means all
  94. coreidval = []
  95. coreidCMD = []
  96. keepCoreIds=None
  97. if args.cores:
  98. cores=args.cores.split(",")
  99. coreids = [str(getCoreID(x.strip())) for x in cores]
  100. keepCoreIds = coreids.copy()
  101. if args.ref:
  102. coreids.append(str(getCoreID(args.ref.strip())))
  103. #print(coreids)
  104. coreidval,coreidCMD, coreidVIEWcmd = parseSelector(coreids,field="coreid")
  105. runidval += coreidval
  106. runidCMD += " AND %s" % coreidCMD
  107. runidVIEWcmd += " AND %s" % coreidVIEWcmd
  108. # We extract data only from data tables
  109. # Those tables below are used for descriptions
  110. REMOVETABLES=['TESTNAME','TESTDATE','RUN','CORE', 'PLATFORM', 'COMPILERKIND', 'COMPILER', 'TYPE', 'CATEGORY', 'CONFIG']
  111. # This is assuming the database is generated by the regression script
  112. # So platform is the same for all benchmarks.
  113. # Category and type is coming from the test name in the yaml
  114. # So no need to add this information here
  115. # Name is removed here because it is added at the beginning
  116. REMOVECOLUMNS=['runid','name','type','platform','category','coredef','OPTIMIZED','HARDFP','FASTMATH','NEON','HELIUM','UNROLL','ROUNDING','DATE','compilerkindid','date','categoryid', 'ID', 'platformid', 'coreid', 'compilerid', 'typeid']
  117. REMOVECOLUMNSFORHISTORY=['Regression','MAXREGCOEF','name','type','platform','category','coredef','OPTIMIZED','HARDFP','FASTMATH','NEON','HELIUM','UNROLL','ROUNDING','DATE','compilerkindid','date','categoryid', 'ID', 'platformid', 'coreid', 'compilerid', 'typeid']
  118. # Get existing benchmark tables
  119. def getBenchTables():
  120. r=c.execute("SELECT name FROM sqlite_master WHERE type='table'")
  121. benchtables=[]
  122. for table in r:
  123. if not table[0] in REMOVETABLES:
  124. benchtables.append(table[0])
  125. return(benchtables)
  126. # get existing types in a table
  127. def getExistingTypes(benchTable):
  128. r=c.execute("select distinct typeid from %s WHERE %s order by typeid desc " % (benchTable,runidCMD),runidval).fetchall()
  129. result=[x[0] for x in r]
  130. return(result)
  131. # Get existing cores in a table
  132. def getAllExistingCores(benchTable):
  133. r=c.execute("select distinct coreid from %s WHERE %s order by coreid desc " % (benchTable,runidCMD),runidval).fetchall()
  134. result=[x[0] for x in r]
  135. return(result)
  136. def getrunIDDetails():
  137. tables=getBenchTables()
  138. r=[]
  139. for table in tables:
  140. r += [x[0] for x in c.execute(runIDDetails % (table,runidCMD),runidval).fetchall()]
  141. r=list(set(r))
  142. print(r)
  143. if args.lastid:
  144. quit()
  145. if args.details:
  146. getrunIDDetails()
  147. quit()
  148. # Get compilers from specific type and table
  149. allCompilers="""select distinct compilerid from %s WHERE typeid=?"""
  150. # Get compilers from specific type and table
  151. allCompilerForCore="""select distinct compilerid from %s WHERE coreid=?"""
  152. # Get compilers from specific type and table
  153. allCores="""select distinct coreid from %s WHERE typeid=? AND (%s)"""
  154. compilerDesc="""select compiler,version from COMPILER
  155. INNER JOIN COMPILERKIND USING(compilerkindid) WHERE compilerid=?"""
  156. coreDesc="""select core from CORE WHERE coreid=?"""
  157. # Get existing compiler in a table for a specific type
  158. # (In case report is structured by types)
  159. def getExistingCompiler(benchTable,typeid):
  160. r=c.execute(allCompilers % benchTable,(typeid,)).fetchall()
  161. return([x[0] for x in r])
  162. # Get existing compiler in a table for a specific core
  163. # (In case report is structured by core)
  164. def getExistingCompilerForCore(benchTable,coreid):
  165. r=c.execute(allCompilerForCore % benchTable,(coreid,)).fetchall()
  166. return([x[0] for x in r])
  167. def getExistingCores(benchTable,typeid):
  168. vals = (typeid,) + runidval
  169. r=c.execute(allCores % (benchTable,runidCMD),vals).fetchall()
  170. return([x[0] for x in r])
  171. def getCoreDesc(coreid):
  172. r=c.execute(coreDesc,(coreid,)).fetchone()
  173. return(r)
  174. def getCompilerDesc(compilerid):
  175. r=c.execute(compilerDesc,(compilerid,)).fetchone()
  176. return(r)
  177. # Get type name from type id
  178. def getTypeName(typeid):
  179. r=c.execute("select type from TYPE where typeid=?",(typeid,)).fetchone()
  180. return(r[0])
  181. # Diff of 2 lists
  182. def diff(first, second):
  183. second = set(second)
  184. return [item for item in first if item not in second]
  185. # Command to get data for specific compiler
  186. # and type
  187. benchCmdForCoreCompiler="""select %s from %s
  188. INNER JOIN CATEGORY USING(categoryid)
  189. INNER JOIN PLATFORM USING(platformid)
  190. INNER JOIN CORE USING(coreid)
  191. INNER JOIN COMPILER USING(compilerid)
  192. INNER JOIN COMPILERKIND USING(compilerkindid)
  193. INNER JOIN TYPE USING(typeid)
  194. INNER JOIN TESTNAME USING(testnameid)
  195. WHERE coreid=? AND compilerid = ? AND (%s)
  196. """
  197. # Command to get data for specific core
  198. # and type
  199. historyCmd="""select %s from %s
  200. INNER JOIN CATEGORY USING(categoryid)
  201. INNER JOIN PLATFORM USING(platformid)
  202. INNER JOIN CORE USING(coreid)
  203. INNER JOIN COMPILER USING(compilerid)
  204. INNER JOIN COMPILERKIND USING(compilerkindid)
  205. INNER JOIN TYPE USING(typeid)
  206. INNER JOIN TESTNAME USING(testnameid)
  207. WHERE compilerid=? AND coreid=? AND typeid = ? AND ID = ? AND runid > (? - 10)
  208. """
  209. compilersForHistory="""select distinct compilerid,compiler,version from %s
  210. INNER JOIN COMPILER USING(compilerid)
  211. INNER JOIN COMPILERKIND USING(compilerkindid)
  212. WHERE coreid=? AND typeid = ? AND ID = ? AND runid > (? - 10)
  213. """
  214. # Command to get data for specific core
  215. # and type
  216. benchCmdForCore="""select %s from %s
  217. INNER JOIN CATEGORY USING(categoryid)
  218. INNER JOIN PLATFORM USING(platformid)
  219. INNER JOIN CORE USING(coreid)
  220. INNER JOIN COMPILER USING(compilerid)
  221. INNER JOIN COMPILERKIND USING(compilerkindid)
  222. INNER JOIN TYPE USING(typeid)
  223. INNER JOIN TESTNAME USING(testnameid)
  224. WHERE coreid=? AND typeid = ? AND (%s)
  225. """
  226. coresForHistory="""select distinct coreid,core from %s
  227. INNER JOIN CORE USING(coreid)
  228. WHERE compilerid=? AND typeid = ? AND ID = ? AND runid > (? - 10)
  229. """
  230. # Command to get data for specific compiler
  231. # and type
  232. benchCmdForCompiler="""select %s from %s
  233. INNER JOIN CATEGORY USING(categoryid)
  234. INNER JOIN PLATFORM USING(platformid)
  235. INNER JOIN CORE USING(coreid)
  236. INNER JOIN COMPILER USING(compilerid)
  237. INNER JOIN COMPILERKIND USING(compilerkindid)
  238. INNER JOIN TYPE USING(typeid)
  239. INNER JOIN TESTNAME USING(testnameid)
  240. WHERE compilerid=? AND typeid = ? AND (%s)
  241. """
  242. # Command to get test names for specific compiler
  243. # and type
  244. benchNamesForCore="""select distinct name from %s
  245. INNER JOIN COMPILER USING(compilerid)
  246. INNER JOIN COMPILERKIND USING(compilerkindid)
  247. INNER JOIN TYPE USING(typeid)
  248. INNER JOIN TESTNAME USING(testnameid)
  249. WHERE coreid=? AND typeid = ? AND (%s)
  250. """
  251. # Command to get test names for specific core
  252. # and compiler
  253. benchNamesForCoreCompiler="""select distinct name from %s
  254. INNER JOIN COMPILER USING(compilerid)
  255. INNER JOIN COMPILERKIND USING(compilerkindid)
  256. INNER JOIN TYPE USING(typeid)
  257. INNER JOIN TESTNAME USING(testnameid)
  258. WHERE coreid=? AND compilerid = ? AND (%s)
  259. """
  260. # Command to get test names for specific compiler
  261. # and type
  262. benchNamesForCompiler="""select distinct name from %s
  263. INNER JOIN COMPILER USING(compilerid)
  264. INNER JOIN COMPILERKIND USING(compilerkindid)
  265. INNER JOIN TYPE USING(typeid)
  266. INNER JOIN TESTNAME USING(testnameid)
  267. WHERE compilerid=? AND typeid = ? AND (%s)
  268. """
  269. # Command to get columns for specific table
  270. benchCmdColumns="""select * from %s
  271. INNER JOIN CATEGORY USING(categoryid)
  272. INNER JOIN PLATFORM USING(platformid)
  273. INNER JOIN CORE USING(coreid)
  274. INNER JOIN COMPILER USING(compilerid)
  275. INNER JOIN COMPILERKIND USING(compilerkindid)
  276. INNER JOIN TESTNAME USING(testnameid)
  277. INNER JOIN TYPE USING(typeid)
  278. """
  279. def joinit(iterable, delimiter):
  280. it = iter(iterable)
  281. yield next(it)
  282. for x in it:
  283. yield delimiter
  284. yield x
  285. # Is not a column name finishing by id
  286. # (often primary key for thetable)
  287. def isNotIDColumn(col):
  288. if re.match(r'^.*id$',col):
  289. return(False)
  290. else:
  291. return(True)
  292. # Get test names
  293. # for specific core and compiler (for the data)
  294. def getTestNamesForCoreCompiler(benchTable,compilerid,core):
  295. vals=(core,compilerid) + runidval
  296. result=c.execute(benchNamesForCoreCompiler % (benchTable,runidCMD),vals).fetchall()
  297. names=[x[0] for x in list(result)]
  298. return(names)
  299. # Get test names
  300. # for specific typeid and core (for the data)
  301. def getTestNamesForCore(benchTable,core,typeid):
  302. vals=(core,typeid) + runidval
  303. result=c.execute(benchNamesForCore % (benchTable,runidCMD),vals).fetchall()
  304. names=[x[0] for x in list(result)]
  305. return(names)
  306. # Get test names
  307. # for specific typeid and compiler (for the data)
  308. def getTestNamesForCompiler(benchTable,comp,typeid):
  309. vals=(comp,typeid) + runidval
  310. result=c.execute(benchNamesForCompiler % (benchTable,runidCMD),vals).fetchall()
  311. names=[x[0] for x in list(result)]
  312. return(names)
  313. # Command to get data for specific core
  314. # and type
  315. nbElemsInBenchAndTypeAndCoreCmd="""select count(*) from %s
  316. WHERE coreid=? AND typeid = ? AND (%s)
  317. """
  318. # Command to get data for specific compiler
  319. # and type
  320. nbElemsInBenchAndTypeAndCompilerCmd="""select count(*) from %s
  321. WHERE compilerid=? AND typeid = ? AND (%s)
  322. """
  323. # Command to get data for specific compiler
  324. # and type
  325. nbElemsInBenchAndCoreAndCompilerCmd="""select count(*) from %s
  326. WHERE compilerid=? AND coreid = ? AND (%s)
  327. """
  328. nbElemsInBenchAndTypeCmd="""select count(*) from %s
  329. WHERE typeid = ? AND (%s)
  330. """
  331. nbElemsInBenchAndCoreCmd="""select count(*) from %s
  332. WHERE coreid = ? AND (%s)
  333. """
  334. nbElemsInBenchCmd="""select count(*) from %s
  335. WHERE %s
  336. """
  337. categoryName="""select distinct category from %s
  338. INNER JOIN CATEGORY USING(categoryid)
  339. WHERE %s
  340. """
  341. def getCategoryName(benchTable):
  342. result=c.execute(categoryName % (benchTable,runidCMD),runidval).fetchone()
  343. return(result[0])
  344. # Get nb elems in a table
  345. def getNbElemsInBenchAndTypeAndCoreCmd(benchTable,coreid,typeid):
  346. vals=(coreid,typeid) + runidval
  347. result=c.execute(nbElemsInBenchAndTypeAndCoreCmd % (benchTable,runidCMD),vals).fetchone()
  348. return(result[0])
  349. # Get nb elems in a table
  350. def getNbElemsInBenchAndTypeAndCompilerCmd(benchTable,comp,typeid):
  351. vals=(comp,typeid) + runidval
  352. result=c.execute(nbElemsInBenchAndTypeAndCompilerCmd % (benchTable,runidCMD),vals).fetchone()
  353. return(result[0])
  354. # Get nb elems in a table
  355. def getNbElemsInBenchAndCoreAndCompilerCmd(benchTable,comp,coreid):
  356. vals=(comp,coreid) + runidval
  357. result=c.execute(nbElemsInBenchAndCoreAndCompilerCmd % (benchTable,runidCMD),vals).fetchone()
  358. return(result[0])
  359. def getNbElemsInBenchAndTypeCmd(benchTable,typeid):
  360. vals=(typeid,) + runidval
  361. result=c.execute(nbElemsInBenchAndTypeCmd % (benchTable,runidCMD),vals).fetchone()
  362. return(result[0])
  363. def getNbElemsInBenchAndCoreCmd(benchTable,coreid):
  364. vals=(coreid,) + runidval
  365. result=c.execute(nbElemsInBenchAndCoreCmd % (benchTable,runidCMD),vals).fetchone()
  366. return(result[0])
  367. def getNbElemsInBenchCmd(benchTable):
  368. result=c.execute(nbElemsInBenchCmd % (benchTable,runidCMD),runidval).fetchone()
  369. return(result[0])
  370. # Get names of columns and data for a table
  371. # for specific typeid and coreid (for the data)
  372. def getColNamesAndHistory(benchTable,compiler,core,typeid,testid):
  373. cursor=c.cursor()
  374. result=cursor.execute(benchCmdColumns % (benchTable))
  375. cols= [member[0] for member in cursor.description]
  376. keepCols = ['name'] + [c for c in diff(cols , REMOVECOLUMNSFORHISTORY) if isNotIDColumn(c)]
  377. keepColsStr = "".join(joinit(keepCols,","))
  378. vals=(compiler,core,typeid,testid,runid)
  379. result=cursor.execute(historyCmd % (keepColsStr,benchTable),vals)
  380. vals =np.array([list(x) for x in list(result)])
  381. return(keepCols,vals)
  382. # Get names of columns and data for a table
  383. # for specific typeid and coreid (for the data)
  384. def getColNamesAndDataForCore(benchTable,core,typeid):
  385. cursor=c.cursor()
  386. result=cursor.execute(benchCmdColumns % (benchTable))
  387. cols= [member[0] for member in cursor.description]
  388. keepCols = ['name'] + [c for c in diff(cols , REMOVECOLUMNS) if isNotIDColumn(c)]
  389. keepColsStr = "".join(joinit(keepCols,","))
  390. vals=(core,typeid) + runidval
  391. result=cursor.execute(benchCmdForCore % (keepColsStr,benchTable,runidCMD),vals)
  392. vals =np.array([list(x) for x in list(result)])
  393. return(keepCols,vals)
  394. # Get names of columns and data for a table
  395. # for specific coreid and compilerid (for the data)
  396. def getColNamesAndDataForCoreCompiler(benchTable,compilerid,core):
  397. cursor=c.cursor()
  398. result=cursor.execute(benchCmdColumns % (benchTable))
  399. cols= [member[0] for member in cursor.description]
  400. keepCols = ['name','type'] + [c for c in diff(cols , REMOVECOLUMNS) if isNotIDColumn(c)]
  401. keepColsStr = "".join(joinit(keepCols,","))
  402. vals=(core,compilerid) + runidval
  403. result=cursor.execute(benchCmdForCoreCompiler % (keepColsStr,benchTable,runidCMD),vals)
  404. vals =np.array([list(x) for x in list(result)])
  405. return(keepCols,vals)
  406. # Get names of columns and data for a table
  407. # for specific typeid and compiler (for the data)
  408. def getColNamesAndDataForCompiler(benchTable,comp,typeid):
  409. cursor=c.cursor()
  410. result=cursor.execute(benchCmdColumns % (benchTable))
  411. cols= [member[0] for member in cursor.description]
  412. keepCols = ['name'] + [c for c in diff(cols , REMOVECOLUMNS) if isNotIDColumn(c)]
  413. keepColsStr = "".join(joinit(keepCols,","))
  414. vals=(comp,typeid) + runidval
  415. result=cursor.execute(benchCmdForCompiler % (keepColsStr,benchTable,runidCMD),vals)
  416. vals =np.array([list(x) for x in list(result)])
  417. return(keepCols,vals)
  418. def formatFloat(s):
  419. result=[]
  420. for t in s:
  421. if type(t) is float:
  422. result.append(("%.3f" % t))
  423. else:
  424. result.append(t)
  425. return(result)
  426. PARAMS=["NB","NumTaps", "NBA", "NBB", "Factor", "NumStages","VECDIM","NBR","NBC","NBI","IFFT", "BITREV"]
  427. def regressionTableFor(byname,name,section,ref,toSort,indexCols,field):
  428. data=ref.pivot_table(index=indexCols, columns=byname,
  429. values=[field], aggfunc='first',fill_value="NA")
  430. data=data.sort_values(toSort)
  431. if args.byc:
  432. cores = [(c[1] + ":" + c[2]) for c in list(data.columns)]
  433. else:
  434. cores = [c[1] for c in list(data.columns)]
  435. columns = diff(indexCols,['name'])
  436. dataTable=Table(columns,cores)
  437. section.addContent(dataTable)
  438. dataForFunc=data.loc[name]
  439. if type(dataForFunc) is pd.DataFrame:
  440. bars={'cols':columns,'cores':cores,'data':[]}
  441. for row in dataForFunc.itertuples():
  442. row=list(row)
  443. if type(row[0]) is int:
  444. row=[row[0]] + row[1:]
  445. else:
  446. row=list(row[0]) + row[1:]
  447. if field=="MAXREGCOEF":
  448. newrow = row
  449. newrow[len(columns):] = formatFloat(row[len(columns):])
  450. row=newrow
  451. dataTable.addRow(row)
  452. bars['data'].append(row)
  453. return(bars)
  454. else:
  455. if field=="MAXREGCOEF":
  456. dataForFunc=formatFloat(dataForFunc)
  457. dataTable.addRow(dataForFunc)
  458. return(list(zip(cores,dataForFunc)))
  459. def formatColumnName(c):
  460. return("".join(joinit(c,":")))
  461. def getCoresForHistory(benchTable,compilerid,typeid,testid,runid):
  462. vals=(compilerid,typeid,testid,runid)
  463. result=c.execute(coresForHistory % benchTable,vals).fetchall()
  464. ids=[(x[0],x[1]) for x in list(result)]
  465. return(ids)
  466. def getCompilerForHistory(benchTable,coreid,typeid,testid,runid):
  467. vals=(coreid,typeid,testid,runid)
  468. result=c.execute(compilersForHistory % benchTable,vals).fetchall()
  469. ids=[(x[0],x[1],x[2]) for x in list(result)]
  470. return(ids)
  471. def getHistory(desc,testid,indexCols):
  472. benchName,sectionID,typeid,runid = desc
  473. #print(benchName)
  474. #print(sectionID)
  475. #print(typeid)
  476. #print(testid)
  477. columns = diff(indexCols,['name'])
  478. #print(columns)
  479. if args.byc:
  480. coreid=sectionID
  481. compilerids=getCompilerForHistory(benchName,coreid,typeid,testid,runid)
  482. series={}
  483. for compilerid,compilername,version in compilerids:
  484. result=getColNamesAndHistory(benchName,compilerid,coreid,typeid,testid)
  485. #print("%s:%s" % (compilername,version))
  486. maxpos = result[0].index('MAX')
  487. lrunid = result[0].index('runid')
  488. r=[[int(x[lrunid]),int(x[maxpos])] for x in result[1:][0]]
  489. series[corename]=r
  490. hist=History(series,runid)
  491. return(hist)
  492. else:
  493. compilerid=sectionID
  494. coreids = getCoresForHistory(benchName,compilerid,typeid,testid,runid)
  495. series={}
  496. for coreid,corename in coreids:
  497. result=getColNamesAndHistory(benchName,compilerid,coreid,typeid,testid)
  498. #print(corename)
  499. maxpos = result[0].index('MAX')
  500. corepos = result[0].index('core')
  501. lrunid = result[0].index('runid')
  502. r=[[int(x[lrunid]),int(x[maxpos])] for x in result[1:][0]]
  503. series[corename]=r
  504. hist=History(series,runid)
  505. return(hist)
  506. def convertRowToInt(r):
  507. result=[]
  508. for e in r:
  509. if type(e) is float:
  510. result.append(int(e))
  511. else:
  512. result.append(e)
  513. return(result)
  514. def addSectionComment(section):
  515. if os.path.exists(args.comments):
  516. fileName=re.sub(r'[() :]','',section.name)
  517. path=os.path.join(args.comments,fileName+".html")
  518. para=""
  519. if os.path.exists(path):
  520. commentSection = Section("Comments")
  521. section.addSection(commentSection)
  522. with open(path,"r") as r:
  523. for l in r:
  524. if l.strip():
  525. para += l
  526. else:
  527. commentSection.addContent(Text(para))
  528. para=""
  529. if para:
  530. commentSection.addContent(Text(para))
  531. def formatTableBy(desc,byname,section,typeSection,testNames,cols,vals):
  532. if vals.size != 0:
  533. ref=pd.DataFrame(vals,columns=cols)
  534. toSort=["name"]
  535. for param in PARAMS:
  536. if param in ref.columns:
  537. ref[param]=pd.to_numeric(ref[param])
  538. toSort.append(param)
  539. if args.r:
  540. # Regression table
  541. ref['MAX']=pd.to_numeric(ref['MAX'])
  542. ref['MAXREGCOEF']=pd.to_numeric(ref['MAXREGCOEF'])
  543. indexCols=diff(cols,byname + ['Regression','MAXREGCOEF','MAX'] + section)
  544. valList = ['Regression']
  545. else:
  546. ref['CYCLES']=pd.to_numeric(ref['CYCLES']).round(decimals=0)
  547. indexCols=diff(cols,byname + ['CYCLES'] + section)
  548. valList = ['CYCLES']
  549. for name in testNames:
  550. if args.r:
  551. testSection = Section(name)
  552. testSection.setTest()
  553. typeSection.addSection(testSection)
  554. addSectionComment(testSection)
  555. maxCyclesSection = Section("Max cycles")
  556. testSection.addSection(maxCyclesSection)
  557. theCycles=regressionTableFor(byname,name,maxCyclesSection,ref,toSort,indexCols,'MAX')
  558. if args.g:
  559. if type(theCycles) is dict:
  560. nbParams=len(theCycles['cols'])
  561. for bar in theCycles['data']:
  562. params=bar[0:nbParams]
  563. values=bar[nbParams:]
  564. title=[("%s=%s" % x) for x in list(zip(theCycles['cols'],params))]
  565. title="".join(joinit(title," "))
  566. sec=Section(title)
  567. maxCyclesSection.addSection(sec)
  568. values=list(zip(theCycles['cores'],values))
  569. barChart=BarChart(values)
  570. sec.addContent(barChart)
  571. else:
  572. #print(theCycles)
  573. sec=Section("Graph")
  574. maxCyclesSection.addSection(sec)
  575. barChart=BarChart(theCycles)
  576. sec.addContent(barChart)
  577. #history=getHistory(desc,testid,indexCols)
  578. #testSection.addContent(history)
  579. regressionSection = Section("Regression")
  580. testSection.addSection(regressionSection)
  581. regressionTableFor(byname,name,regressionSection,ref,toSort,indexCols,'Regression')
  582. maxRegCoefSection = Section("Max Reg Coef")
  583. testSection.addSection(maxRegCoefSection)
  584. regressionTableFor(byname,name,maxRegCoefSection,ref,toSort,indexCols,'MAXREGCOEF')
  585. else:
  586. data=ref.pivot_table(index=indexCols, columns=byname,
  587. values=valList, aggfunc='first',fill_value="NA")
  588. data=data.sort_values(toSort)
  589. #print(list(data.columns))
  590. testSection = Section(name)
  591. testSection.setTest()
  592. typeSection.addSection(testSection)
  593. addSectionComment(testSection)
  594. dataForFunc=data.loc[name]
  595. dataForFunc = dataForFunc.dropna(axis=1)
  596. columnsID = [formatColumnName(c[1:]) for c in list(dataForFunc.columns)]
  597. columns = diff(indexCols,['name'])
  598. dataTable=Table(columns,columnsID)
  599. testSection.addContent(dataTable)
  600. if type(dataForFunc) is pd.DataFrame:
  601. for row in dataForFunc.itertuples():
  602. if type(row[0]) is int:
  603. row=list([row[0]] + list(row[1:]))
  604. else:
  605. row=list(row[0]) + list(row[1:])
  606. dataTable.addRow(convertRowToInt(row))
  607. else:
  608. dataTable.addRow(convertRowToInt(dataForFunc))
  609. referenceCoreID = None
  610. refCore="""CREATE TEMP VIEW if not exists refCore AS
  611. select * from %s where (coreid = %s) and (typeid = %s)
  612. and %s
  613. and compilerid = %s"""
  614. otherCore="""CREATE TEMP VIEW if not exists otherCore AS
  615. select * from %s where (typeid = %s)
  616. and %s
  617. and compilerid = %s"""
  618. refCoreAllTypes="""CREATE TEMP VIEW if not exists refCore AS
  619. select * from %s where (coreid = %s)
  620. and %s
  621. and compilerid = %s"""
  622. otherCoreAllTypes="""CREATE TEMP VIEW if not exists otherCore AS
  623. select * from %s where (coreid = %s)
  624. and %s
  625. and compilerid = %s"""
  626. ratioSQL="""select name,otherCore.compilerid as compilerid,CORE.core as core,%s(CAST(otherCore.MAX as FLOAT) / CAST(refCore.MAX AS FLOAT)) AS RATIO
  627. from otherCore
  628. INNER JOIN refCore ON (refCore.categoryid = otherCore.categoryid
  629. AND refCore.testnameid = otherCore.testnameid
  630. AND refCore.typeid = otherCore.typeid
  631. AND refCore.runid = otherCore.runid
  632. AND refCore.compilerid = otherCore.compilerid
  633. )
  634. INNER JOIN TESTNAME ON TESTNAME.testnameid = refCore.testnameid
  635. INNER JOIN CORE USING(coreid)
  636. %s"""
  637. ratioSQLAllTypes="""select name,otherCore.compilerid as compilerid,TYPE.type as type,%s(CAST(otherCore.MAX as FLOAT) / CAST(refCore.MAX AS FLOAT)) AS RATIO
  638. from otherCore
  639. INNER JOIN refCore ON (refCore.categoryid = otherCore.categoryid
  640. AND refCore.testnameid = otherCore.testnameid
  641. AND refCore.typeid = otherCore.typeid
  642. AND refCore.runid = otherCore.runid
  643. AND refCore.compilerid = otherCore.compilerid
  644. )
  645. INNER JOIN TESTNAME ON TESTNAME.testnameid = refCore.testnameid
  646. INNER JOIN TYPE USING(typeid)
  647. %s"""
  648. ratioTestNamesSQL="""select distinct TESTNAME.name
  649. from otherCore
  650. INNER JOIN refCore ON (refCore.categoryid = otherCore.categoryid
  651. AND refCore.testnameid = otherCore.testnameid
  652. AND refCore.typeid = otherCore.typeid
  653. AND refCore.runid = otherCore.runid
  654. AND refCore.compilerid = otherCore.compilerid
  655. )
  656. INNER JOIN TESTNAME ON TESTNAME.testnameid = refCore.testnameid
  657. INNER JOIN CORE USING(coreid)
  658. %s"""
  659. dropViewsRef="""drop view refCore"""
  660. dropViewsOther="""drop view otherCore"""
  661. def getTableParams(benchTable):
  662. cursor=c.cursor()
  663. result=cursor.execute("select * from %s limit 1" % (benchTable))
  664. cols= [member[0] for member in cursor.description]
  665. params=[]
  666. for x in cols:
  667. if x in PARAMS:
  668. params.append(x)
  669. return(params)
  670. def computeRatio(benchName,viewParams,refMkViewCmd,otherMkViewCmd,byd):
  671. params = getTableParams(benchName)
  672. cols=["ratio"]
  673. paramscmd=""
  674. paramscols=""
  675. paramsnames = ["refCore.%s as %s" % (x,x) for x in params]
  676. paramseq = ["refCore.%s = otherCore.%s" % (x,x) for x in params]
  677. if len(params) > 0:
  678. cols = ["%s" % x for x in params]
  679. cols.append("ratio")
  680. paramscols= ("".join(joinit(paramsnames," , ")) + ",")
  681. paramscmd = "WHERE " + "".join(joinit(paramseq," AND "))
  682. if byd:
  683. ratioCmd = ratioSQLAllTypes % (paramscols,paramscmd)
  684. else:
  685. ratioCmd = ratioSQL % (paramscols,paramscmd)
  686. ratioTestNames = ratioTestNamesSQL % (paramscmd)
  687. #print(refMkViewCmd)
  688. #print(otherMkViewCmd)
  689. #
  690. #print(ratioCmd)
  691. #
  692. #print(dropViewsRef)
  693. #print(dropViewsOther)
  694. #quit()
  695. c.execute(refMkViewCmd)
  696. c.execute(otherMkViewCmd)
  697. ratio=c.execute(ratioCmd).fetchall()
  698. testNames=c.execute(ratioTestNames).fetchall()
  699. testNames=[x[0] for x in testNames]
  700. c.execute(dropViewsRef)
  701. c.execute(dropViewsOther)
  702. #print(ratio)
  703. #quit()
  704. if byd:
  705. return(['name','compilerid','type'] + cols,params,ratio,testNames)
  706. else:
  707. return(['name','compilerid','core'] + cols,params,ratio,testNames)
  708. # Compute for all core for a given type
  709. def computeRatioTable(benchName,referenceCore,typeID,compiler):
  710. viewParams = (benchName,referenceCore,typeID,runidVIEWcmd,compiler)
  711. refMkViewCmd = refCore % viewParams
  712. otherParams = (benchName,typeID,runidVIEWcmd,compiler)
  713. otherMkViewCmd = otherCore % otherParams
  714. #print(refMkViewCmd)
  715. #print(otherMkViewCmd)
  716. return(computeRatio(benchName,viewParams,refMkViewCmd,otherMkViewCmd,False))
  717. def computeRatioTableForCore(benchName,referenceCore,otherCoreID,compiler):
  718. viewParams = (benchName,referenceCore,runidVIEWcmd,compiler)
  719. refMkViewCmd = refCoreAllTypes % viewParams
  720. otherParams = (benchName,otherCoreID,runidVIEWcmd,compiler)
  721. otherMkViewCmd = otherCoreAllTypes % otherParams
  722. #print(refMkViewCmd)
  723. #print(otherMkViewCmd)
  724. return(computeRatio(benchName,viewParams,refMkViewCmd,otherMkViewCmd,True))
  725. def formatPerfRatio(s):
  726. result=[]
  727. for t in s:
  728. if type(t) is float:
  729. if args.clamp:
  730. if t > args.clampval:
  731. t = args.clampval
  732. if t < 0.0:
  733. result.append("NA")
  734. else:
  735. result.append(("%.3f" % t))
  736. else:
  737. result.append(s)
  738. return(result)
  739. def addRatioTable(cols,params,data,section,testNames,byd):
  740. ref=pd.DataFrame(data,columns=cols)
  741. toSort=["name"] + params
  742. for param in PARAMS:
  743. if param in ref.columns:
  744. ref[param]=pd.to_numeric(ref[param])
  745. #print(testNames)
  746. for name in testNames:
  747. testSection = Section(name)
  748. testSection.setTest()
  749. section.addSection(testSection)
  750. addSectionComment(testSection)
  751. ratioSection = Section("Ratios")
  752. testSection.addSection(ratioSection)
  753. #print(toSort)
  754. #print(ref)
  755. if byd:
  756. data=ref.pivot_table(index=toSort, columns=['type'],
  757. values=["ratio"], aggfunc='first',fill_value=-1.0)
  758. else:
  759. data=ref.pivot_table(index=toSort, columns=['core'],
  760. values=["ratio"], aggfunc='first')
  761. data=data.sort_values(toSort)
  762. #print(data)
  763. dataForFunc=data.loc[name]
  764. cores = [c[1] for c in list(data.columns)]
  765. dataTable=Table(params,cores)
  766. if args.g:
  767. if type(dataForFunc) is not pd.DataFrame:
  768. sec=Section("Graph")
  769. testSection.addSection(sec)
  770. barChart=BarChart(zip(cores,dataForFunc))
  771. sec.addContent(barChart)
  772. ratioSection.addContent(Text("A bigger ratio means the reference core \"%s\" is better" % refCoreName))
  773. ratioSection.addContent(dataTable)
  774. if type(dataForFunc) is pd.DataFrame:
  775. for row in dataForFunc.itertuples():
  776. row=list(row)
  777. if type(row[0]) is int:
  778. row=[row[0]] + formatPerfRatio(row[1:])
  779. else:
  780. row=list(row[0]) + formatPerfRatio(row[1:])
  781. dataTable.addRow(row)
  782. else:
  783. row=list(dataForFunc)
  784. dataTable.addRow(formatPerfRatio(row))
  785. # Add a report for each table
  786. def addReportFor(document,benchName):
  787. nbElems = getNbElemsInBenchCmd(benchName)
  788. if nbElems > 0:
  789. categoryName = getCategoryName(benchName)
  790. benchSection = Section(categoryName)
  791. document.addSection(benchSection)
  792. print("Process %s\n" % benchName)
  793. if args.byd:
  794. allCores=getAllExistingCores(benchName)
  795. if args.ratio:
  796. if keepCoreIds:
  797. allCores=keepCoreIds
  798. if ("%d" % referenceCoreID) in allCores:
  799. allCores.remove("%d" % referenceCoreID)
  800. for aCoreID in allCores:
  801. nbElems = getNbElemsInBenchAndCoreCmd(benchName,aCoreID)
  802. if nbElems > 0:
  803. coreName=getCoreDesc(aCoreID)
  804. coreSection = Section("%s" % coreName)
  805. benchSection.addSection(coreSection)
  806. allCompilers = getExistingCompilerForCore(benchName,aCoreID)
  807. for compiler in allCompilers:
  808. #print(compiler)
  809. if args.ratio:
  810. cols,params,ratios,testNames=computeRatioTableForCore(benchName,referenceCoreID,aCoreID,compiler)
  811. #print(cols)
  812. #print(ratios)
  813. #print(" ")
  814. if len(ratios)>0:
  815. compilerName,version=getCompilerDesc(compiler)
  816. compilerSection = Section("%s (%s)" % (compilerName,version))
  817. coreSection.addSection(compilerSection)
  818. addRatioTable(cols,params,ratios,compilerSection,testNames,True)
  819. else:
  820. nbElems = getNbElemsInBenchAndCoreAndCompilerCmd(benchName,compiler,aCoreID)
  821. # Print test results for table, type, compiler
  822. if nbElems > 0:
  823. compilerName,version=getCompilerDesc(compiler)
  824. compilerSection = Section("%s (%s)" % (compilerName,version))
  825. coreSection.addSection(compilerSection)
  826. cols,vals=getColNamesAndDataForCoreCompiler(benchName,compiler,aCoreID)
  827. desc=(benchName,compiler,aCoreID)
  828. names=getTestNamesForCoreCompiler(benchName,compiler,aCoreID)
  829. formatTableBy(desc,['type'],['core','version','compiler'],compilerSection,names,cols,vals)
  830. else:
  831. allTypes = getExistingTypes(benchName)
  832. # Add report for each type
  833. for aTypeID in allTypes:
  834. nbElems = getNbElemsInBenchAndTypeCmd(benchName,aTypeID)
  835. if nbElems > 0:
  836. typeName = getTypeName(aTypeID)
  837. typeSection = Section(typeName)
  838. benchSection.addSection(typeSection)
  839. if args.byc:
  840. ## Add report for each core
  841. allCores = getExistingCores(benchName,aTypeID)
  842. for core in allCores:
  843. #print(core)
  844. nbElems = getNbElemsInBenchAndTypeAndCoreCmd(benchName,core,aTypeID)
  845. # Print test results for table, type, compiler
  846. if nbElems > 0:
  847. coreName=getCoreDesc(core)
  848. coreSection = Section("%s" % coreName)
  849. typeSection.addSection(coreSection)
  850. cols,vals=getColNamesAndDataForCore(benchName,core,aTypeID)
  851. desc=(benchName,core,aTypeID)
  852. names=getTestNamesForCore(benchName,core,aTypeID)
  853. formatTableBy(desc,['compiler','version'],['core'],coreSection,names,cols,vals)
  854. elif args.ratio:
  855. allCompilers = getExistingCompiler(benchName,aTypeID)
  856. for compiler in allCompilers:
  857. cols,params,ratios,testNames=computeRatioTable(benchName,referenceCoreID,aTypeID,compiler)
  858. #print(cols)
  859. #print(ratios)
  860. #print(" ")
  861. if len(ratios)>0:
  862. compilerName,version=getCompilerDesc(compiler)
  863. compilerSection = Section("%s (%s)" % (compilerName,version))
  864. typeSection.addSection(compilerSection)
  865. addRatioTable(cols,params,ratios,compilerSection,testNames,False)
  866. else:
  867. ## Add report for each compiler
  868. allCompilers = getExistingCompiler(benchName,aTypeID)
  869. for compiler in allCompilers:
  870. #print(compiler)
  871. nbElems = getNbElemsInBenchAndTypeAndCompilerCmd(benchName,compiler,aTypeID)
  872. # Print test results for table, type, compiler
  873. if nbElems > 0:
  874. compilerName,version=getCompilerDesc(compiler)
  875. compilerSection = Section("%s (%s)" % (compilerName,version))
  876. typeSection.addSection(compilerSection)
  877. cols,vals=getColNamesAndDataForCompiler(benchName,compiler,aTypeID)
  878. desc=(benchName,compiler,aTypeID)
  879. names=getTestNamesForCompiler(benchName,compiler,aTypeID)
  880. formatTableBy(desc,['core'],['version','compiler'],compilerSection,names,cols,vals)
  881. toc=[Hierarchy("BasicMathsBenchmarks"),
  882. Hierarchy("ComplexMathsBenchmarks"),
  883. Hierarchy("FastMath"),
  884. Hierarchy("Filters",
  885. [Hierarchy("FIR"),
  886. Hierarchy("BIQUAD"),
  887. Hierarchy("DECIM"),
  888. Hierarchy("MISC")]),
  889. Hierarchy("Support Functions",
  890. [Hierarchy("Support"),
  891. Hierarchy("SupportBar")]),
  892. Hierarchy("Matrix Operations" ,
  893. [Hierarchy("Binary"),
  894. Hierarchy("Unary")]),
  895. Hierarchy("Transform"),
  896. Hierarchy("Stats"),
  897. Hierarchy("Classical ML",[
  898. Hierarchy("Bayes"),
  899. Hierarchy("SVM"),
  900. Hierarchy("Distance"),
  901. Hierarchy("KalmanBenchmarks")
  902. ]),
  903. ]
  904. processed=[]
  905. def addComments(document):
  906. if os.path.exists(args.comments):
  907. section=Section("Measurement Context")
  908. path=os.path.join(args.comments,"comments.txt")
  909. document.addSection(section)
  910. para=""
  911. with open(path,"r") as r:
  912. for l in r:
  913. if l.strip():
  914. para += l
  915. else:
  916. section.addContent(Text(para))
  917. para=""
  918. if para:
  919. section.addContent(Text(para))
  920. if args.ratio:
  921. section.addContent(Text("Reference core for the ratio is %s" % refCoreName))
  922. section.addContent(Text("A bigger ratio means the reference code is better"))
  923. def processToc(d):
  924. result=[]
  925. for k in d:
  926. if d[k] is not None:
  927. result.append(Hierarchy(k,processToc(d[k])))
  928. else:
  929. result.append(Hierarchy(k))
  930. return(result)
  931. def createDoc(document,sections,benchtables):
  932. global processed,referenceCoreID
  933. for s in sections:
  934. if s.name in benchtables:
  935. addReportFor(document,s.name)
  936. processed.append(s.name)
  937. else:
  938. section=Section(s.name)
  939. document.addSection(section)
  940. createDoc(section,s.sections,benchtables)
  941. try:
  942. benchtables=getBenchTables()
  943. document = Document(None)
  944. if args.ratio:
  945. referenceCoreID= getCoreID(args.ref)
  946. refCoreName=getCoreDesc(referenceCoreID)
  947. addComments(document)
  948. if args.toc:
  949. with open(args.toc,"r") as f:
  950. config=yaml.safe_load(f)
  951. toc = processToc(config['root'])
  952. #print(toc)
  953. #quit()
  954. createDoc(document,toc,benchtables)
  955. misc=Section("Miscellaneous")
  956. document.addSection(misc)
  957. remaining=diff(benchtables,processed)
  958. for bench in remaining:
  959. addReportFor(misc,bench)
  960. #for bench in benchtables:
  961. # addReportFor(document,bench)
  962. with open(args.o,"w") as output:
  963. if args.t=="md":
  964. document.accept(Markdown(output))
  965. if args.t=="html":
  966. reorder=NORMALFORMAT
  967. if args.byc:
  968. reorder=BYCFORMAT
  969. if args.byd:
  970. reorder=BYDFORMAT
  971. document.accept(HTML(output,args.r,args.ratio,reorder))
  972. finally:
  973. c.close()