r25157 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r25156‎ | r25157 | r25158 >
Date:12:53, 26 August 2007
Author:midom
Status:old
Tags:
Comment:
The first, biggest change, is VERSION file added, which has a bumped up version from 0.0.1 to 0.0.2.
The second change is that there's configuration file, that even has a password in it.
Third change is that the password can be used for an admin interface, to clean profiling and take/drop snapshots.
The fourth change is that profiling can now view old snapshots.
The fifth change is that it is possible to compare snapshots.
And the sixth, overall change, is that UI is even more overloaded and much more difficult to understand.
Modified paths:
  • /trunk/udpprofile/web/VERSION (added) (history)
  • /trunk/udpprofile/web/admin.py (added) (history)
  • /trunk/udpprofile/web/config.py (added) (history)
  • /trunk/udpprofile/web/extractprofile.py (modified) (history)
  • /trunk/udpprofile/web/report.py (modified) (history)

Diff [purge]

Index: trunk/udpprofile/web/config.py
@@ -0,0 +1,7 @@
 2+#!/usr/bin/python
 3+
 4+password="thepassword"
 5+host="127.0.0.1"
 6+port=3811
 7+db="phase3"
 8+
Index: trunk/udpprofile/web/admin.py
@@ -0,0 +1,53 @@
 2+#!/usr/bin/python
 3+
 4+import shelve
 5+import cgi
 6+import cgitb; cgitb.enable()
 7+
 8+import datetime
 9+import sys
 10+import config
 11+
 12+password=config.password
 13+
 14+print "Content-type: text/html\n"
 15+
 16+form=cgi.SvFormContentDict()
 17+
 18+if 'password' in form:
 19+ if form['password'] != "" and form['password'] != password:
 20+ print "access denied!!!!!!!!!1111oneoneeleven"
 21+ sys.exit()
 22+ else:
 23+ authed=True
 24+else:
 25+ authed=False
 26+
 27+print """
 28+ <script>function deletesample(sample) {form=document.forms['actions'];form['sample'].value=sample;form.submit();}</script>
 29+ <form name='actions' method='POST' action='admin.py'>
 30+ <input type='submit' name='action' value='take'>
 31+ <input type='submit' name='action' value='clear'>
 32+ <input type='hidden' name='sample' value=''>
 33+ <input type='%s' name='password' value='%s'
 34+ </form>""" % ((authed and 'hidden' or 'password'),(authed and password or ''))
 35+
 36+store = shelve.open('baselines')
 37+
 38+if 'action' not in form:
 39+ if 'sample' in form:
 40+ del store[form['sample']]
 41+elif form['action'] == 'clear' and authed:
 42+ from socket import *
 43+ sock = socket(AF_INET,SOCK_DGRAM)
 44+ sock.sendto('-truncate',(config.host,config.port))
 45+elif form['action'] == 'take' and authed:
 46+ from extractprofile import SocketProfile
 47+ store[str(datetime.datetime.now()).replace(" ","-")] = SocketProfile(config.host,config.port).extract()
 48+elif 'sample' in form and authed:
 49+ del store[form['sample']]
 50+
 51+for entry in store.keys():
 52+ print """<div><a href='report.py?sample=%s'>%s</a> <a href='javascript:deletesample("%s")'>delete</a></div>""" % (entry,entry,entry)
 53+
 54+print "<div><a href='report.py'>current</a></div>"
\ No newline at end of file
Index: trunk/udpprofile/web/extractprofile.py
@@ -7,12 +7,14 @@
88
99 import sys
1010 import os
 11+import socket
1112
1213 import xml.sax
1314 from xml.sax import saxutils
1415 from xml.sax import make_parser
1516 from xml.sax.handler import feature_namespaces
1617
 18+# XML SAX parser class, puts stuff into some array!
1719 class ExtractProfile(xml.sax.handler.ContentHandler):
1820 def __init__(self):
1921 self.parser=make_parser()
@@ -60,6 +62,20 @@
6163 self.inContent=0
6264 self.parser.parse(file)
6365 return self.profile
 66+
 67+class SocketProfile:
 68+ def __init__(self,host='localhost',port=3811):
 69+ self.sock=SocketSource()
 70+ self.sock.connect((host,port))
 71+
 72+ def extract(self):
 73+ return ExtractProfile().extract(self.sock)
 74+
 75+class SocketSource (socket.socket):
 76+ """Stub class for extending socket object to support file source mechanics"""
 77+ def read(self,what):
 78+ """Alias recv to read, missing in socket.socket"""
 79+ return self.recv(what,0)
6480
6581 if __name__ == '__main__':
6682 print "\nNot a valid entry point"
Index: trunk/udpprofile/web/report.py
@@ -2,25 +2,27 @@
33
44 # Configuration and defaults
55
6 -profilehost = "localhost"
7 -profileport = 3811
 6+import config
87
9 -db="enwiki"
 8+db=config.db
 9+
1010 sort="real"
1111 limit=50
1212
1313
14 -from extractprofile import ExtractProfile
 14+from extractprofile import SocketProfile
1515
1616 import cgi
1717 import cgitb; cgitb.enable()
1818
1919 import socket
 20+import shelve
2021
2122 print "Content-type: text/html";
2223 print "\n"
2324
2425 form=cgi.SvFormContentDict()
 26+store = shelve.open('baselines')
2527
2628 if "db" in form:
2729 db=form["db"]
@@ -30,24 +32,31 @@
3133
3234 if "limit" in form: limit=int(form["limit"])
3335
34 -compare="none"
35 -if "compare" in form: compare=form["compare"]
 36+if "compare" in form:
 37+ compare=form["compare"]
 38+ compared=store[compare]
 39+else:
 40+ compare=""
 41+ compared=None
3642
37 -class SocketSource (socket.socket):
38 - def read(self,what):
39 - return self.recv(what,0)
40 -sock=SocketSource()
41 -sock.connect((profilehost,profileport))
 43+if 'sample' not in form:
 44+ fullprofile=SocketProfile(config.host,config.port).extract()
 45+ sample=""
 46+else:
 47+ fullprofile=store[form['sample']]
 48+ sample=form['sample']
4249
43 -cache={}
44 -fullprofile=ExtractProfile().extract(sock)
 50+
 51+
4552 events=fullprofile[db]["-"].items()
46 -cache[db]=events
47 -cache["_dbs"]=fullprofile.keys()
48 -dbs=cache["_dbs"]
49 -
 53+dbs=fullprofile.keys()
5054 total=fullprofile[db]["-"]["-total"]
5155
 56+# Limit the scope
 57+if compare:
 58+ compared=compared[db]["-"]
 59+ oldtotal=compared["-total"]
 60+
5261 #cache.close()
5362 if sort=="name":
5463 events.sort(lambda x,y: cmp(x[0],y[0]))
@@ -55,54 +64,145 @@
5665 events.sort(lambda y,x: cmp(x[1][sort],y[1][sort]))
5766
5867 def surl(stype,stext=None,limit=50):
 68+ """ Simple URL formatter for headers """
5969 if(stext==None): stext=stype
60 - if stype==sort: return """<td>%s</td>"""%stext
61 - return """<td><a href='report.py?db=%s&sort=%s&limit=%d'>%s</a></td>"""%(db,stype,limit,stext)
 70+ if stype==sort: return """<td><b>%s</b></td>"""%stext
 71+ return """<td><a href='report.py?db=%s&sort=%s&limit=%d&sample=%s&compare=%s'>%s</a></td>"""%(db,stype,limit,sample,compare,stext)
6272
6373 print """
6474 <style>
65 -table { width: 100%; }
 75+table { width: 100%; font-size: 9pt; }
6676 td { cell-padding: 1px;
6777 text-align: right;
6878 vertical-align: top;
6979 argin: 2px;
7080 border: 1px silver dotted;
 81+ white-space: nowrap;
7182 background-color: #eeeeee;
7283 }
73 -td.name { text-align: left; width: 100%;}
 84+td.name { text-align: left; width: 100%; white-space: normal;}
7485 tr.head td { text-align: center; }
7586 </style>"""
7687
 88+if sample:
 89+ print "<div>Using old sample: %s, <a href='report.py?db=%s'>reset to current</a></div>" % (sample,db)
 90+
 91+# Top list of databases
7792 for dbname in dbs:
7893 if db == dbname: print " [%s] "%dbname
7994 else: print " [<a href='report.py?db=%s'>%s</a>] "%(dbname,dbname)
8095
8196 if limit==50:
82 - print " [ showing %d events, <a href='report.py?db=%s&sort=%s&limit=5000'>show more</a> ] " % (limit,db,sort)
 97+ print " [ showing %d events, <a href='report.py?db=%s&sort=%s&sample=%s&compare=%s&limit=5000'>show more</a> ] " % (limit,db,sort,sample,compare)
8398 else:
84 - print " [ showing %d events, <a href='report.py?db=%s&sort=%s&limit=50'>show less</a> ] " % (limit,db,sort)
 99+ print " [ showing %d events, <a href='report.py?db=%s&sort=%s&sample=%s&compare=%s&limit=50'>show less</a> ] " % (limit,db,sort,sample,compare)
85100
 101+print " [ <a href='admin.py'>admin</a> ]</div>"
86102
 103+print """<form>
 104+<input type='hidden' name='db' value='%s'>
 105+<input type='hidden' name='sort' value='%s'>
 106+<input type='hidden' name='limit' value='%d'>
 107+<input type='hidden' name='sample' value='%s'>
 108+<select name='compare'><option></option>""" %(db,sort,limit,sample)
 109+
 110+samples=store.keys()
 111+samples.sort()
 112+for baseline in samples:
 113+ print "<option%s>%s</option>" % ((compare==baseline and " SELECTED" or ""),baseline)
 114+print "</select><input type='submit' value='compare'></form>"
 115+
 116+
 117+# This is header!
87118 print """
88119 <table>
89120 <tr class="head">"""
90121 print surl("name")
91122 print surl("count")
 123+print "<td>count%</td>"
 124+print "<td>change</td>"
92125 print surl("cpu","cpu%")
 126+print "<td>change</td>"
93127 print surl("onecpu","cpu/c")
 128+print "<td>change</td>"
94129 print surl("real","real%")
 130+print "<td>change</td>"
95131 print surl("onereal","real/c")
 132+print "<td>change</td>"
96133 print "</tr>"
97134
98 -rowformat="""<tr class="data"><td class="name">%s</td><td>%d</td>
99 - <td>%.2f</td><td>%.1f</td><td>%.2f</td><td>%.1f</td></tr>"""
 135+rowformat="""
 136+<tr class="data"><td class="name">%s</td><td>%d</td>
 137+<td>%.2f</td><td>%.1f</td><td>%.2f</td><td>%.1f</td></tr>"""
100138
 139+
 140+# name
 141+# counts: total relative compared
 142+# cputime: total compared percall compared
 143+# realtime: total compared percall compared
 144+
 145+comparedformat="""
 146+<tr class="data"><td class="name">%s</td>
 147+<td>%d</td><td>%.2f</td><td>%.1f</td>
 148+<td>%.2f</td><td>%.1f</td><td>%.1f</td><td>%.1f</td>
 149+<td>%.2f</td><td>%.1f</td><td>%.1f</td><td>%.1f</td>
 150+</tr>
 151+"""
 152+
 153+# This is really really hacky way of reporting percentages
 154+
 155+# And this is output of results.
101156 for event in events:
102 - if event[0]=="close": continue
 157+ (name,event)=event
 158+ if name=="close": continue
 159+ if compared and name in compared: old=compared[name]
 160+ else: old=None
 161+
103162 limit-=1
104163 if limit<0: break
105 - print rowformat % \
106 - (event[0].replace(",",", "),event[1]["count"],event[1]["cpu"]/total["cpu"]*100,event[1]["onecpu"]*1000,\
107 - event[1]["real"]/total["real"]*100,event[1]["onereal"]*1000)
 164+
 165+ callcount=float(event["count"])/total["count"]
 166+ cpupct=event["cpu"]/total["cpu"]
 167+ onecpu=event["onecpu"]
 168+ realpct=event["real"]/total["real"]
 169+ onereal=event["onereal"]
 170+
 171+ if old:
 172+ oldcount=float(old["count"])/oldtotal["count"]
 173+ countdiff = (callcount-oldcount)/oldcount
 174+
 175+ oldcpupct = old["cpu"]/oldtotal["cpu"]
 176+ cpupctdiff = (cpupct-oldcpupct)/oldcpupct
 177+
 178+ onecpudiff = ( onecpu - old["onecpu"] ) / old["onecpu"]
 179+
 180+ oldrealpct = old["real"]/oldtotal["real"]
 181+ realpctdiff = (realpct-oldrealpct)/oldrealpct
 182+
 183+ o=old["onereal"]
 184+ onerealdiff = ( onereal - old["onereal"] ) / old["onereal"]
 185+
 186+ else:
 187+ countdiff=0
 188+ cpupctdiff=0
 189+ onecpudiff=0
 190+ realpctdiff=0
 191+ onerealdiff=0
 192+
 193+ dbg=0
 194+
 195+ if dbg and name=="wfMsgReal":
 196+ print old
 197+ print oldtotal
 198+ print event
 199+ print total
 200+ if not dbg: print comparedformat % (
 201+ name.replace(",",", "),
 202+ event["count"], callcount,countdiff*100,
 203+ cpupct*100,cpupctdiff*100,
 204+ onecpu*1000,onecpudiff*100,
 205+ realpct*100,realpctdiff*100,
 206+ onereal*1000,onerealdiff*100
 207+ )
108208
109209 print "</table>"
Index: trunk/udpprofile/web/VERSION
@@ -0,0 +1 @@
 2+0.0.2

Status & tagging log