6e1ccec9508062e6725e53c2a5f1cc61a1742ea8
1 # Copyright (c) 2003-2004 The Regents of The University of Michigan
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 import MySQLdb
, re
, string
33 last
= min(len(v1
), len(v2
)) - 1
34 for i
,j
in zip(v1
[0:last
], v2
[0:last
]):
38 # Special compare for last element.
39 if len(v1
) == len(v2
):
40 return cmp(v1
[last
], v2
[last
])
42 return cmp(len(v1
), len(v2
))
45 def __init__(self
, row
):
46 self
.run
= int(row
[0])
52 def __init__(self
, row
):
53 self
.stat
= int(row
[0])
60 def __init__(self
, row
):
63 self
.stat
= int(row
[0])
64 self
.run
= int(row
[1])
67 self
.data
= float(row
[4])
70 return '''Data(['%d', '%d', '%d', '%d', '%f'])''' % ( self
.stat
,
71 self
.run
, self
.x
, self
.y
, self
.data
)
73 class StatData(object):
74 def __init__(self
, row
):
75 self
.stat
= int(row
[0])
79 self
.prereq
= int(row
[5])
80 self
.precision
= int(row
[6])
84 if int(row
[4]): self
.flags |
= flags
.printable
85 if int(row
[7]): self
.flags |
= flags
.nozero
86 if int(row
[8]): self
.flags |
= flags
.nonan
87 if int(row
[9]): self
.flags |
= flags
.total
88 if int(row
[10]): self
.flags |
= flags
.pdf
89 if int(row
[11]): self
.flags |
= flags
.cdf
91 if self
.type == 'DIST' or self
.type == 'VECTORDIST':
92 self
.min = float(row
[12])
93 self
.max = float(row
[13])
94 self
.bktsize
= float(row
[14])
95 self
.size
= int(row
[15])
97 if self
.type == 'FORMULA':
98 self
.formula
= self
.db
.allFormulas
[self
.stat
]
101 def __init__(self
, name
):
106 class Database(object):
108 self
.host
= 'zizzer.pool'
116 self
.allStatNames
= {}
122 self
.allRunNames
= {}
126 self
.allBinNames
= {}
128 self
.allFormulas
= {}
138 self
.__dict
__['get'] = type(self
).sum
140 def query(self
, sql
):
141 self
.cursor
.execute(sql
)
143 def update_dict(self
, dict):
144 dict.update(self
.stattop
)
146 def append(self
, stat
):
147 statname
= re
.sub(':', '__', stat
.name
)
148 path
= string
.split(statname
, '.')
155 if not x
.__dict
__.has_key(name
):
156 x
.__dict
__[name
] = Node(fullname
+ name
)
158 fullname
= '%s%s.' % (fullname
, name
)
161 x
.__dict
__[name
] = stat
163 self
.stattop
[pathtop
] = self
.__dict
__[pathtop
]
164 self
.statdict
[statname
] = stat
165 self
.statlist
.append(statname
)
169 self
.thedb
= MySQLdb
.connect(db
=self
.db
,
175 self
.cursor
= self
.thedb
.cursor()
177 self
.query('''select rn_id,rn_name,rn_sample,rn_user,rn_project
179 for result
in self
.cursor
.fetchall():
180 run
= RunData(result
);
181 self
.allRuns
.append(run
)
182 self
.allRunIds
[run
.run
] = run
183 self
.allRunNames
[run
.name
] = run
185 self
.query('select * from bins')
186 for id,name
in self
.cursor
.fetchall():
187 self
.allBinIds
[int(id)] = name
188 self
.allBinNames
[name
] = int(id)
190 self
.query('select sd_stat,sd_x,sd_y,sd_name,sd_descr from subdata')
191 for result
in self
.cursor
.fetchall():
192 subdata
= SubData(result
)
193 if self
.allSubData
.has_key(subdata
.stat
):
194 self
.allSubData
[subdata
.stat
].append(subdata
)
196 self
.allSubData
[subdata
.stat
] = [ subdata
]
198 self
.query('select * from formulas')
199 for id,formula
in self
.cursor
.fetchall():
200 self
.allFormulas
[int(id)] = formula
.tostring()
203 self
.query('select * from stats')
205 for result
in self
.cursor
.fetchall():
206 stat
= info
.NewStat(StatData(result
))
208 self
.allStats
.append(stat
)
209 self
.allStatIds
[stat
.stat
] = stat
210 self
.allStatNames
[stat
.name
] = stat
213 # Desc: Prints all bins matching regex argument, if no argument
214 # is given all bins are returned
215 def listBins(self
, regex
='.*'):
216 print '%-50s %-10s' % ('bin name', 'id')
218 names
= self
.allBinNames
.keys()
221 id = self
.allBinNames
[name
]
222 print '%-50s %-10d' % (name
, id)
225 # Desc: Prints all runs matching a given user, if no argument
226 # is given all runs are returned
227 def listRuns(self
, user
=None):
228 print '%-40s %-10s %-5s' % ('run name', 'user', 'id')
230 for run
in self
.allRuns
:
231 if user
== None or user
== run
.user
:
232 print '%-40s %-10s %-10d' % (run
.name
, run
.user
, run
.run
)
235 # Desc: Prints all samples for a given run
236 def listTicks(self
, runs
=None):
238 print "----------------------------------------"
239 sql
= 'select distinct dt_tick from data where dt_stat=1180 and ('
248 sql
+= ' dt_run=%s' % run
.run
251 for r
in self
.cursor
.fetchall():
255 # Desc: Prints all samples for a given run
256 def retTicks(self
, runs
=None):
257 sql
= 'select distinct dt_tick from data where dt_stat=1180 and ('
265 sql
+= ' dt_run=%s' % run
.run
269 for r
in self
.cursor
.fetchall():
274 # Desc: Prints all statistics that appear in the database,
275 # the optional argument is a regular expression that can
276 # be used to prune the result set
277 def listStats(self
, regex
=None):
278 print '%-60s %-8s %-10s' % ('stat name', 'id', 'type')
283 rx
= re
.compile(regex
)
285 stats
= [ stat
.name
for stat
in self
.allStats
]
288 stat
= self
.allStatNames
[stat
]
289 if rx
== None or rx
.match(stat
.name
):
290 print '%-60s %-8s %-10s' % (stat
.name
, stat
.stat
, stat
.type)
293 # Desc: Prints all statistics that appear in the database,
294 # the optional argument is a regular expression that can
295 # be used to prune the result set
296 def listFormulas(self
, regex
=None):
297 print '%-60s %s' % ('formula name', 'formula')
302 rx
= re
.compile(regex
)
304 stats
= [ stat
.name
for stat
in self
.allStats
]
307 stat
= self
.allStatNames
[stat
]
308 if stat
.type == 'FORMULA' and (rx
== None or rx
.match(stat
.name
)):
309 print '%-60s %s' % (stat
.name
, self
.allFormulas
[stat
.stat
])
311 def getStat(self
, stats
):
312 if type(stats
) is not list:
317 if type(stat
) is int:
318 ret
.append(self
.allStatIds
[stat
])
320 if type(stat
) is str:
321 rx
= re
.compile(stat
)
322 for stat
in self
.allStats
:
323 if rx
.match(stat
.name
):
327 def getBin(self
, bins
):
328 if type(bins
) is not list:
335 elif type(bin
) is str:
336 ret
.append(self
.allBinNames
[bin
])
338 for name
,id in self
.allBinNames
.items():
344 def getNotBin(self
, bin
):
346 for bin
in getBin(bin
):
350 for bin
in self
.allBinIds
.keys():
351 if not map.has_key(bin
):
356 #########################################
359 def inner(self
, op
, stat
, bins
, ticks
, group
=False):
361 sql
+= 'dt_stat as stat, '
362 sql
+= 'dt_run as run, '
366 sql
+= 'dt_tick as tick, '
367 sql
+= '%s(dt_data) as data ' % op
371 if isinstance(stat
, list):
372 val
= ' or '.join([ 'dt_stat=%d' % s
.stat
for s
in stat
])
375 sql
+= ' dt_stat=%d' % stat
.stat
377 if self
.runs
!= None and len(self
.runs
):
378 val
= ' or '.join([ 'dt_run=%d' % r
for r
in self
.runs
])
379 sql
+= ' and (%s)' % val
381 if bins
!= None and len(bins
):
382 val
= ' or '.join([ 'dt_bin=%d' % b
for b
in bins
])
383 sql
+= ' and (%s)' % val
385 if ticks
!= None and len(ticks
):
386 val
= ' or '.join([ 'dt_tick=%d' % s
for s
in ticks
])
387 sql
+= ' and (%s)' % val
389 sql
+= ' group by dt_stat,dt_run,dt_x,dt_y'
394 def outer(self
, op_out
, op_in
, stat
, bins
, ticks
):
395 sql
= self
.inner(op_in
, stat
, bins
, ticks
, True)
396 sql
= 'select stat,run,x,y,%s(data) from (%s) as tb ' % (op_out
, sql
)
397 sql
+= 'group by stat,run,x,y'
401 # Desc: given a run, a stat and an array of samples and bins,
402 # sum all the bins and then get the standard deviation of the
403 # samples for non-binned runs. This will just return the average
404 # of samples, however a bin array still must be passed
405 def sum(self
, stat
, bins
, ticks
):
406 return self
.inner('sum', stat
, bins
, ticks
)
409 # Desc: given a run, a stat and an array of samples and bins,
410 # sum all the bins and then average the samples for non-binned
411 # runs this will just return the average of samples, however
412 # a bin array still must be passed
413 def avg(self
, stat
, bins
, ticks
):
414 return self
.outer('avg', 'sum', stat
, bins
, ticks
)
417 # Desc: given a run, a stat and an array of samples and bins,
418 # sum all the bins and then get the standard deviation of the
419 # samples for non-binned runs. This will just return the average
420 # of samples, however a bin array still must be passed
421 def stdev(self
, stat
, bins
, ticks
):
422 return self
.outer('stddev', 'sum', stat
, bins
, ticks
)
424 def __getattribute__(self
, attr
):
426 return super(Database
, self
).__getattribute
__(attr
)
428 if self
.__dict
__['get'] == type(self
).sum:
430 elif self
.__dict
__['get'] == type(self
).avg
:
432 elif self
.__dict
__['get'] == type(self
).stdev
:
437 def __setattr__(self
, attr
, value
):
439 super(Database
, self
).__setattr
__(attr
, value
)
443 self
.__dict
__['get'] = type(self
).sum
445 self
.__dict
__['get'] = type(self
).avg
446 elif value
== 'stdev':
447 self
.__dict
__['get'] = type(self
).stdev
449 raise AttributeError, "can only set get to: sum | avg | stdev"
451 def data(self
, stat
, bins
=None, ticks
=None):
456 sql
= self
.__dict
__['get'](self
, stat
, bins
, ticks
)
460 for x
in self
.cursor
.fetchall():
462 if not runs
.has_key(data
.run
):
464 if not runs
[data
.run
].has_key(data
.x
):
465 runs
[data
.run
][data
.x
] = {}
467 runs
[data
.run
][data
.x
][data
.y
] = data
.data