| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | ## |
|---|
| 3 | ## |
|---|
| 4 | ## This file is part of CDS Indico. |
|---|
| 5 | ## Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 CERN. |
|---|
| 6 | ## |
|---|
| 7 | ## CDS Indico is free software; you can redistribute it and/or |
|---|
| 8 | ## modify it under the terms of the GNU General Public License as |
|---|
| 9 | ## published by the Free Software Foundation; either version 2 of the |
|---|
| 10 | ## License, or (at your option) any later version. |
|---|
| 11 | ## |
|---|
| 12 | ## CDS Indico is distributed in the hope that it will be useful, but |
|---|
| 13 | ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 15 | ## General Public License for more details. |
|---|
| 16 | ## |
|---|
| 17 | ## You should have received a copy of the GNU General Public License |
|---|
| 18 | ## along with CDS Indico; if not, write to the Free Software Foundation, Inc., |
|---|
| 19 | ## 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 20 | |
|---|
| 21 | import os |
|---|
| 22 | import sys |
|---|
| 23 | import struct |
|---|
| 24 | import time |
|---|
| 25 | import ZODB.FileStorage |
|---|
| 26 | import datetime |
|---|
| 27 | from ZODB.utils import U64, get_pickle_metadata |
|---|
| 28 | from persistent.TimeStamp import TimeStamp |
|---|
| 29 | from ZODB.tests.StorageTestBase import zodb_unpickle |
|---|
| 30 | from optparse import OptionParser |
|---|
| 31 | from time import gmtime, strftime |
|---|
| 32 | from datetime import timedelta |
|---|
| 33 | |
|---|
| 34 | StringType = str |
|---|
| 35 | |
|---|
| 36 | class Stat(object): |
|---|
| 37 | def __init__(self): |
|---|
| 38 | self.mean = [] |
|---|
| 39 | self.n = 0 |
|---|
| 40 | self.records = 0 |
|---|
| 41 | |
|---|
| 42 | def GetInHMS(seconds, showSec): |
|---|
| 43 | hours = int(seconds / 3600) |
|---|
| 44 | seconds -= 3600*hours |
|---|
| 45 | minutes = int(seconds / 60.0) |
|---|
| 46 | seconds -= 60*minutes |
|---|
| 47 | if hours == 0: |
|---|
| 48 | if(showSec): return "%02dmin %02dsecs" % (minutes, seconds) |
|---|
| 49 | else: return "%02dmin" % (minutes) |
|---|
| 50 | |
|---|
| 51 | if(showSec): return "%02dh %02dmin %02dsecs" % (hours, minutes, seconds) |
|---|
| 52 | else: return "%02dh %02dmin" % (hours, minutes) |
|---|
| 53 | |
|---|
| 54 | def pretty_size( size ): |
|---|
| 55 | if size < 1024: |
|---|
| 56 | return "%sB"%(size) |
|---|
| 57 | kb = size / 1024.0 |
|---|
| 58 | if kb < 1024.0: |
|---|
| 59 | return '%0.1fKb'%kb |
|---|
| 60 | else: |
|---|
| 61 | mb = kb/1024.0 |
|---|
| 62 | return '%0.1fMb'%mb |
|---|
| 63 | |
|---|
| 64 | def U64(s): |
|---|
| 65 | return struct.unpack(">Q", s)[0] |
|---|
| 66 | |
|---|
| 67 | def oid_repr(oid): |
|---|
| 68 | if isinstance(oid, StringType) and len(oid) == 8: |
|---|
| 69 | return '%16x' % U64(oid) |
|---|
| 70 | else: |
|---|
| 71 | return repr(oid) |
|---|
| 72 | |
|---|
| 73 | def main(): |
|---|
| 74 | usage = "usage: %prog [options] filename" |
|---|
| 75 | parser = OptionParser(usage=usage) |
|---|
| 76 | parser.add_option("-n", "--number", dest="num", |
|---|
| 77 | help="display only the 'n' busiest days", default=20, type="int") |
|---|
| 78 | parser.add_option("-f", "--file", dest="filename", action="store", type="string", |
|---|
| 79 | help="your FileStorage") |
|---|
| 80 | parser.add_option("-d", "--date", dest="date", action="store", type="string", |
|---|
| 81 | help="show the stats only for the date d (format dd-mm-yyyy)") |
|---|
| 82 | parser.add_option("-a", "--days", dest="days", action="store", default="0", type="string", |
|---|
| 83 | help="show the stats only for the last 'a' days") |
|---|
| 84 | |
|---|
| 85 | (options, args) = parser.parse_args() |
|---|
| 86 | objectsToDisplay = options.num |
|---|
| 87 | |
|---|
| 88 | if options.filename: |
|---|
| 89 | fname = options.filename |
|---|
| 90 | else: |
|---|
| 91 | print "You have to enter the filename, see --help for details" |
|---|
| 92 | return 2 |
|---|
| 93 | |
|---|
| 94 | stats = {} |
|---|
| 95 | start = time.time() |
|---|
| 96 | size = os.stat(fname).st_size |
|---|
| 97 | it = ZODB.FileStorage.FileIterator(fname) |
|---|
| 98 | |
|---|
| 99 | lastPercent = 0.0 |
|---|
| 100 | recordsCounter = 0 |
|---|
| 101 | interval = 0.005 |
|---|
| 102 | dataFound = False |
|---|
| 103 | now = datetime.date.today() |
|---|
| 104 | |
|---|
| 105 | try: |
|---|
| 106 | for t in it: |
|---|
| 107 | |
|---|
| 108 | #Format the date of the current transaction following dd-mm-yyyy |
|---|
| 109 | ts = TimeStamp(t.tid) |
|---|
| 110 | then = datetime.date(int(ts.year()), int(ts.month()), int(ts.day())) |
|---|
| 111 | delta = timedelta(days=int(options.days)) |
|---|
| 112 | |
|---|
| 113 | if((not int(options.days)) or (now - then < delta)): |
|---|
| 114 | dateT = strftime("%d-%m-%Y", [int(ts.year()), int(ts.month()), int(ts.day()),0,0,0,0,0,0] ) |
|---|
| 115 | percent = float(it._file.tell())/float(size) * 100 |
|---|
| 116 | #Check if we found the searched date |
|---|
| 117 | if options.date: |
|---|
| 118 | if str(dateT) == str(options.date): |
|---|
| 119 | dataFound = True |
|---|
| 120 | elif dataFound: |
|---|
| 121 | break |
|---|
| 122 | |
|---|
| 123 | #Show the percentage of the work completed and the remaining time |
|---|
| 124 | if(percent - lastPercent > interval): |
|---|
| 125 | spentTime = time.time() - start |
|---|
| 126 | remainingTime = spentTime / float(it._file.tell()) * (float(size)) - spentTime |
|---|
| 127 | sys.stderr.write("\r%f%% complete, time spent %s, remaining time: %s, recordsCounter %d" % (percent,GetInHMS(time.time() - start, True), GetInHMS(remainingTime, False), recordsCounter)) |
|---|
| 128 | |
|---|
| 129 | lastPercent = percent |
|---|
| 130 | |
|---|
| 131 | stat = stats.get(dateT) |
|---|
| 132 | if stat is None: |
|---|
| 133 | stat = stats[dateT] = Stat() |
|---|
| 134 | stat.n = 1 |
|---|
| 135 | else: |
|---|
| 136 | stat.n += 1 |
|---|
| 137 | |
|---|
| 138 | for r in t: |
|---|
| 139 | #need to reduce the time of the dictionary stats from time to time |
|---|
| 140 | if recordsCounter % (objectsToDisplay*100) == 0: |
|---|
| 141 | tmp = {} |
|---|
| 142 | for date, s in sorted( |
|---|
| 143 | stats.items(), key=lambda (k,v): v.n, reverse=True)[0: objectsToDisplay]: |
|---|
| 144 | tmp[date] = s |
|---|
| 145 | try: |
|---|
| 146 | tmp[dateT] = stats[dateT] |
|---|
| 147 | except KeyError: |
|---|
| 148 | pass |
|---|
| 149 | |
|---|
| 150 | stats = tmp |
|---|
| 151 | |
|---|
| 152 | if r.data: |
|---|
| 153 | mod, klass = get_pickle_metadata(r.data) |
|---|
| 154 | l = len(r.data) |
|---|
| 155 | stat = stats.get(dateT) |
|---|
| 156 | stat.records += 1 |
|---|
| 157 | recordsCounter += 1 |
|---|
| 158 | |
|---|
| 159 | stat = stats.get(dateT) |
|---|
| 160 | if stat is not None: |
|---|
| 161 | stat.mean.append(TimeStamp(t.tid).timeTime()) |
|---|
| 162 | |
|---|
| 163 | except KeyboardInterrupt: |
|---|
| 164 | pass |
|---|
| 165 | |
|---|
| 166 | print "\n" |
|---|
| 167 | print "%-15s %17s %17s %22s" % ("Date", "Transactions","Records Changed", "Average interval") |
|---|
| 168 | print "%s" % "_" * 74 |
|---|
| 169 | |
|---|
| 170 | if options.date: |
|---|
| 171 | for date, s in sorted( |
|---|
| 172 | stats.items(), key=lambda (k,v): v.n, reverse=True): |
|---|
| 173 | meanTime = 0 |
|---|
| 174 | for i in range(1,len(s.mean)): |
|---|
| 175 | meanTime += s.mean[i] - s.mean[i-1] |
|---|
| 176 | if str(date) == str(options.date): |
|---|
| 177 | print "%-15s | %15d | %15d | %15f secs" % (date, (s.n),s.records, meanTime/s.n) |
|---|
| 178 | else: |
|---|
| 179 | for date, s in sorted( |
|---|
| 180 | stats.items(), key=lambda (k,v): v.n, reverse=True)[0: objectsToDisplay]: |
|---|
| 181 | meanTime = 0 |
|---|
| 182 | for i in range(1,len(s.mean)): |
|---|
| 183 | meanTime += s.mean[i] - s.mean[i-1] |
|---|
| 184 | |
|---|
| 185 | print "%-15s | %15d | %15d | %15f secs" % (date, (s.n), s.records, meanTime/s.n) |
|---|
| 186 | |
|---|
| 187 | |
|---|
| 188 | if __name__ == '__main__': |
|---|
| 189 | main() |
|---|
| 190 | |
|---|