217cbc820bbfa473125e5464b7e87da056d4407f
[libfirm] / ir / be / test / statev_sql.py
1 #! /usr/bin/env python
2
3 import sys
4 import os
5 import re
6 import time
7 import stat
8 import profile
9 import sqlite3
10 import MySQLdb
11 import fileinput
12 import tempfile
13 import optparse
14
15 class DummyFilter:
16         def match(self, dummy):
17                 return True
18
19 class EmitBase:
20         def create_table(self, cols, name, type, unique):
21                 create = 'create table if not exists %s (id int %s' % (name, unique)
22
23                 sorted = [None] * len(cols)
24                 for x in cols.iterkeys():
25                         sorted[cols[x]] = x
26                 for x in sorted:
27                         create += (', %s %s' % (x, type))
28                 create += ');'
29                 return create
30
31 class EmitMysqlInfile(EmitBase):
32         tmpfile_mode = stat.S_IREAD | stat.S_IROTH | stat.S_IWUSR
33
34         def ex(self, args, tab, fname):
35                 res = os.fork()
36                 if res == 0:
37                         stmt = """load data infile '%s' into table %s fields terminated by ';'""" % (fname, tab)
38                         conn = MySQLdb.connect(**args)
39                         c = conn.cursor()
40                         c.execute(stmt)
41                         conn.commit()
42                         sys.exit(0)
43                 return res
44
45         def __init__(self, options, ctxcols, evcols):
46                 args = dict()
47                 if options.password:
48                         args['passwd'] = options.password
49                 if not options.host:
50                         options.host = 'localhost'
51                 args['user'] = options.user
52                 args['host'] = options.host
53                 args['db']   = options.database
54
55                 self.conn     = MySQLdb.connect(**args)
56                 self.ctxcols  = ctxcols
57                 self.evcols   = evcols
58                 self.options  = options
59
60                 params = (tempfile.gettempdir(), os.sep, os.getpid())
61                 self.evfifo  = '%s%sstatev_ev_%d' % params
62                 self.ctxfifo = '%s%sstatev_ctx_%d' % params
63
64                 os.mkfifo(self.evfifo)
65                 os.mkfifo(self.ctxfifo)
66
67                 os.chmod(self.evfifo,  self.tmpfile_mode)
68                 os.chmod(self.ctxfifo, self.tmpfile_mode)
69
70                 c = self.conn.cursor()
71                 c.execute('drop table if exists ev')
72                 c.execute('drop table if exists ctx')
73                 c.execute(self.create_table(self.ctxcols, 'ctx', 'char(80)', 'unique'))
74                 c.execute(self.create_table(self.evcols, 'ev', 'double default null', ''))
75                 self.conn.commit()
76
77                 if options.verbose:
78                         print 'go for gold'
79
80                 self.pidev  = self.ex(args, 'ev', self.evfifo)
81                 self.pidctx = self.ex(args, 'ctx', self.ctxfifo)
82
83                 if options.verbose:
84                         print "forked two mysql leechers: %d, %d" % (self.pidev, self.pidctx)
85
86                 self.evfile   = open(self.evfifo, 'w+t')
87                 self.ctxfile  = open(self.ctxfifo, 'w+t')
88
89                 if options.verbose:
90                         print 'fifo:  %s, %o' % (self.evfile.name, os.stat(self.evfile.name).st_mode)
91                         print 'fifo:  %s, %o' % (self.ctxfile.name, os.stat(self.ctxfile.name).st_mode)
92
93         def ev(self, curr_id, evitems):
94                 field = ['\N'] * len(self.evcols)
95                 for key, val in evitems.iteritems():
96                         index = self.evcols[key]
97                         field[index] = val
98                 print >> self.evfile, ('%d;' % curr_id) + ';'.join(field)
99
100         def ctx(self, curr_id, ctxitems):
101                 field = ['\N'] * len(self.ctxcols)
102                 for key, val in ctxitems.iteritems():
103                         index = self.ctxcols[key]
104                         field[index] = val
105                 print >> self.ctxfile, ('%d;' % curr_id) + ';'.join(field)
106
107         def commit(self):
108                 self.evfile.close()
109                 self.ctxfile.close()
110
111                 os.waitpid(self.pidev, 0)
112                 os.waitpid(self.pidctx, 0)
113
114                 os.unlink(self.evfile.name)
115                 os.unlink(self.ctxfile.name)
116
117
118 class EmitSqlite3(EmitBase):
119         def __init__(self, options, ctxcols, evcols):
120                 if os.path.isfile(options.database):
121                         os.unlink(options.database)
122
123                 self.conn = sqlite3.connect(options.database)
124                 self.conn.execute(self.create_table(ctxcols, 'ctx', 'text', 'unique'))
125                 self.conn.execute(self.create_table(evcols, 'ev', 'double', ''))
126
127                 n = max(len(ctxcols), len(evcols)) + 1
128                 q = ['?']
129                 self.quests = []
130                 for i in xrange(0, n):
131                         self.quests.append(','.join(q))
132                         q.append('?')
133
134         def ev(self, curr_id, evitems):
135                 keys = ','.join(evitems.keys())
136                 stmt = 'insert into ev (id, %s) values (%s)' % (keys, self.quests[len(evitems)])
137                 self.conn.execute(stmt, (curr_id,) + tuple(evitems.values()))
138
139         def ctx(self, curr_id, ctxitems):
140                 keys = ','.join(ctxitems.keys())
141                 stmt = 'insert into ctx (id, %s) values (%s)' % (keys, self.quests[len(ctxitems)])
142                 self.conn.execute(stmt, (curr_id,) + tuple(ctxitems.values()))
143
144         def commit(self):
145                 self.conn.commit()
146
147 class Conv:
148         engines = { 'sqlite3': EmitSqlite3, 'mysql': EmitMysqlInfile }
149         def find_heads(self):
150                 n_ev    = 0
151                 ctxind   = 0
152                 evind    = 0
153                 ctxcols  = dict()
154                 evcols   = dict()
155
156                 self.valid_keys = set()
157
158                 for line in self.input():
159                         heads = None
160                         if line[0] == 'P':
161                                 ind = line.index(';', 2)
162                                 key = line[2:ind]
163                                 if not key in ctxcols:
164                                         ctxcols[key] = ctxind
165                                         ctxind += 1
166
167                         elif line[0] == 'E':
168                                 ind = line.index(';', 2)
169                                 key = line[2:ind]
170                                 if self.filter.match(key):
171                                         self.n_events += 1
172                                         if not key in evcols:
173                                                 self.valid_keys.add(key)
174                                                 evcols[key] = evind
175                                                 evind += 1
176
177                 return (ctxcols, evcols)
178
179         def input(self):
180                 return fileinput.FileInput(files=self.files, openhook=fileinput.hook_compressed)
181
182         def fill_tables(self):
183                 lineno     = 0
184                 ids        = 0
185                 curr_id    = 0
186                 keystack   = []
187                 idstack    = []
188                 curr_event = 0
189                 last_prec  = -1
190                 evcols     = dict()
191                 ctxcols    = dict()
192
193                 for line in self.input():
194                         lineno += 1
195                         items = line.strip().split(';')
196                         op    = items[0]
197
198                         if op == 'P':
199                                 # flush the current events
200                                 if len(evcols):
201                                         self.emit.ev(curr_id, evcols)
202                                         evcols.clear()
203
204                                 # push the key
205                                 key   = items[1]
206                                 val   = items[2]
207                                 keystack.append(key)
208                                 curr_id = ids
209                                 ids += 1
210                                 idstack.append(curr_id)
211                                 ctxcols[key] = val
212
213                                 self.emit.ctx(curr_id, ctxcols)
214
215                         elif op == 'O':
216                                 popkey = items[1]
217                                 key = keystack.pop()
218
219                                 if popkey != key:
220                                         print "unmatched pop in line %d, push key %s, pop key: %s" % (lineno, key, popkey)
221
222                                 idstack.pop()
223                                 if len(idstack) > 0:
224                                         if len(evcols) > 0:
225                                                 self.emit.ev(curr_id, evcols)
226                                                 evcols.clear()
227                                         del ctxcols[key]
228                                         curr_id = idstack[-1]
229                                 else:
230                                         curr_id = -1
231
232                         elif op == 'E':
233                                 key = items[1]
234                                 if key in self.valid_keys:
235                                         curr_event += 1
236                                         evcols[key] = items[2]
237
238                                         if self.verbose:
239                                                 prec = curr_event * 10 / self.n_events
240                                                 if prec > last_prec:
241                                                         last_prec = prec
242                                                         print '%10d / %10d' % (curr_event, self.n_events)
243
244         def __init__(self):
245                 parser = optparse.OptionParser('usage: %prog [options]  <event file...>')
246                 parser.add_option("-c", "--clean",    dest="clean",    help="delete tables in advance", action="store_true", default=False)
247                 parser.add_option("-v", "--verbose",  dest="verbose",  help="verbose messages",         action="store_true", default=False)
248                 parser.add_option("-f", "--filter",   dest="filter",   help="regexp to filter event keys", metavar="REGEXP")
249                 parser.add_option("-u", "--user",     dest="user",     help="user",               metavar="USER")
250                 parser.add_option("-H", "--host",     dest="host",     help="host",               metavar="HOST")
251                 parser.add_option("-p", "--password", dest="password", help="password",           metavar="PASSWORD")
252                 parser.add_option("-d", "--db",       dest="database", help="database",           metavar="DB")
253                 parser.add_option("-e", "--engine",   dest="engine",   help="eingine",            metavar="ENG", default='sqlite3')
254                 (options, args) = parser.parse_args()
255
256                 self.n_events = 0
257                 self.stmts    = dict()
258                 self.verbose  = options.verbose
259
260                 if len(args) < 1:
261                         parser.print_help()
262                         sys.exit(1)
263
264                 self.files  = []
265                 files       = args
266
267                 for file in files:
268                         if not os.path.isfile(file):
269                                 print "cannot find input file %s" % (file, )
270                         else:
271                                 self.files.append(file)
272
273                 if len(self.files) < 1:
274                         print "no input file to process"
275                         sys.exit(3)
276
277                 if options.filter:
278                         self.filter = re.compile(options.filter)
279                 else:
280                         self.filter = DummyFilter()
281
282                 if options.engine in self.engines:
283                         engine = self.engines[options.engine]
284                 else:
285                         print 'engine %s not found' % options.engine
286                         print 'we offer: %s' % self.engines.keys()
287                         sys.exit(0)
288
289                 if options.verbose:
290                         print "determining schema..."
291
292                 (ctxcols, evcols) = self.find_heads()
293                 if options.verbose:
294                         print "context schema:"
295                         print ctxcols
296                         print "event schema:"
297                         print evcols
298
299                 self.emit = engine(options, ctxcols, evcols)
300
301                 if options.verbose:
302                         print "filling tables..."
303                 self.fill_tables()
304                 if options.verbose:
305                         print "comitting..."
306                 self.emit.commit()
307
308 if __name__ == "__main__":
309         Conv()