1
2
3
4
5
6
7
8 import re
9 import os
10 import Ice
11 import sys
12 import path
13 import time
14 import uuid
15 import omero
16 import tables
17 import logging
18 import optparse
19 import fileinput
20 import exceptions
21
22 import omero.cli
23 import omero.util
24 import omero.util.temp_files
25 import omero_Constants_ice
26
27 command_pattern = "^\s*(\w+)(\((.*)\))?(:(.*))?$"
28 command_pattern_compiled = re.compile(command_pattern)
29 log = logging.getLogger("omero.perf")
30
31 FILE_FORMAT = """
32 File format:
33 <blank> Ignored
34 # comment Ignored
35 ServerTime(repeat=100) Retrieve the server time 100 times
36 Import:<file> Import given file
37 Import(Screen:<id>):<file> Import given file into screen
38 Import(Dataset:<id>):<file> Import given file into project/dataset
39 Import(Project:<id>,Dataset:<id>):<file> Import given file into project/dataset
40 Import(Dataset:some name):<file> Import given file into a new dataset
41 Import(Dataset):<file> Import given file into last created dataset (or create a new one)
42
43 #
44 # "Import" is the name of a command available in the current context
45 # Use the "--list" command to print them all. All lines must be of the
46 # form: %s
47
48 """ % command_pattern
49
50 parser = optparse.OptionParser(usage = """usage: %%prog [options] file1 file2
51
52 Use "-" as a file name to read from stdin.
53
54 %s""" % FILE_FORMAT)
55
56 parser.add_option('-l', '--list', action='store_true', help='list available commands')
57 parser.add_option('-d', '--debug', action='store_true', help='use DEBUG log level')
58 parser.add_option('-H', '--omero.host', action='store', help='host for connection')
59 parser.add_option('-P', '--omero.port', action='store', help='port for connection')
60 parser.add_option('-W', '--omero.pass', action='store', help='pass for connection')
61 parser.add_option('-C', '--Ice.Config', action='store', help='config file for connection')
62
63
64
65
66
67
68
74
75
77 """
78 Single line-item in the configuration file
79 """
80
82 self.line = line.strip()
83 if not self.comment():
84 match = command_pattern_compiled.match(self.line)
85 if not match:
86 raise BadLine("Unexpected line: %s" % line)
87 self.command = match.group(1)
88 self.arguments = match.group(3)
89 self.path = match.group(5)
90 self.props = dict()
91
92 if self.arguments:
93 args = self.arguments.split(",")
94 for arg in args:
95 parts = arg.split("=", 1)
96 value = (len(parts) == 2 and parts[1] or "")
97 self.props[parts[0]] = value
98
99 log.debug("Found line: %s, %s, %s, %s", self.command, self.arguments, self.path, self.props)
100
102 return int(self.props.get("repeat","1"))
103
109
111 if self.comment():
112 return
113 m = getattr(self, "_op_%s" % self.command, None)
114 if m is None:
115 raise BadCommand("Unknown command: %s" % self.command)
116
117 m(ctx)
118
120 id = None
121 id_path = ctx.dir / ("%s.id" % name)
122 prop = self.props.get(name)
123
124 if prop is None:
125 return None
126
127 try:
128 id = int(prop)
129 log.debug("Using specified %s:%s" % (name, id))
130 except:
131
132 if prop == "":
133 try:
134 id = int(id_path.lines()[0])
135 except exceptions.Exception, e:
136 log.debug("No %s.id: %s", name, e)
137 prop = str(uuid.uuid4())
138
139 if id is not None:
140 log.debug("Using reload %s:%s" % (name, id))
141 else:
142 kls = getattr(omero.model, "%sI" % name)
143 obj = kls()
144 obj.name = omero.rtypes.rstring(prop)
145 obj = ctx.update_service().saveAndReturnObject(obj)
146 id = obj.id.val
147 log.debug("Created obj %s:%s" % (name, id))
148 id_path.write_text(str(id))
149 return id
150
152 link = ctx.query_service().findByQuery(\
153 "select link from %s link where link.parent.id = %s and link.child.id = %s"\
154 % (kls_name, parent.id.val, child.id.val), None)
155 if link:
156 log.debug("Found link %s:%s" % (kls_name, link.id.val))
157 else:
158 kls = getattr(omero.model, "%sI" % kls_name)
159 obj = kls()
160 obj.parent = parent
161 obj.child = child
162 obj = ctx.update_service().saveAndReturnObject(obj)
163 log.debug("Created link %s:%s" % (kls_name, obj.id.val))
164
166 p = path.path(self.path)
167 if not p.exists():
168 raise BadPath("File does not exist: %s" % self.path)
169
170 f = str(p.abspath())
171 out = ctx.dir / ("import_%s.out" % ctx.count)
172 err = ctx.dir / ("import_%s.err" % ctx.count)
173
174 args = ["import", "---file=%s" % str(out), "---errs=%s" % str(err), "-s", ctx.host(), "-k", ctx.key(), f]
175 s_id = self.create_obj(ctx, "Screen")
176 if s_id:
177 args.extend(["-r", str(s_id)])
178 p_id = self.create_obj(ctx, "Project")
179 d_id = self.create_obj(ctx, "Dataset")
180 if p_id and d_id:
181 self.create_link(ctx, "ProjectDatasetLink", omero.model.ProjectI(p_id, False), omero.model.DatasetI(d_id, False))
182 if d_id:
183 args.extend(["-d", str(d_id)])
184
185 ctx.cli.invoke(args)
186 if ctx.cli.rv != 0:
187 raise BadImport("Failed import: rv=%s" % ctx.cli.rv)
188 num_pix = len(out.lines())
189 log.debug("Import count: %s", num_pix)
190
193
196
197 -class Context(object):
198 """
199 Login context which can be used by any handler
200 for connecting to a single session.
201 """
202
203 - def __init__(self, id, reporter = None):
204
205 self.reporters = []
206 self.count = 0
207 self.id = id
208 self.client = omero.client(id)
209 self.client.setAgent("OMERO.perf_test")
210 self.client.createSession()
211 self.services = {}
212 self.cli = omero.cli.CLI()
213 self.cli.loadplugins()
214 self.setup_dir()
215
216 - def add_reporter(self, reporter):
217 self.reporters.append(reporter)
218
219 - def setup_dir(self):
220 self.dir = path.path(".") / ("perfdir-%s" % os.getpid())
221 if self.dir.exists():
222 raise exceptions.Exception("%s exists!" % self.dir)
223 self.dir.makedirs()
224
225
226 handler = logging.handlers.RotatingFileHandler(str(self.dir / "perf.log"), maxBytes = 10000000, backupCount = 5)
227 handler.setLevel(logging.DEBUG)
228 formatter = logging.Formatter(omero.util.LOGFORMAT)
229 handler.setFormatter(formatter)
230 logging.getLogger().addHandler(handler)
231
232 log.debug("Started: %s", time.ctime())
233
236
238 return self.client.getProperty("omero.host")
239
241 return self.client.sf.ice_getIdentity().name
242
243 - def report(self, command, start, stop, loops, rv):
244 for reporter in self.reporters:
245 reporter.report(command, start, stop, loops, rv)
246
247 - def _stateless(self, name, prx):
248 svc = self.services.get(name)
249 if svc:
250 return svc
251 else:
252 svc = self.client.sf.getByName(name)
253 svc = prx.uncheckedCast(svc)
254 self.services[name] = svc
255 return svc
256
257 - def query_service(self):
258 return self._stateless(omero.constants.QUERYSERVICE, omero.api.IQueryPrx)
259
260 - def config_service(self):
261 return self._stateless(omero.constants.CONFIGSERVICE, omero.api.IConfigPrx)
262
263 - def update_service(self):
264 return self._stateless(omero.constants.UPDATESERVICE, omero.api.IUpdatePrx)
265
266
268
271
273
274 (self.ctx.dir/"line.log").write_text(line, append = True)
275
276 item = Item(line)
277 if item.comment():
278 return
279
280 values = {}
281 total = 0.0
282 self.ctx.incr()
283 start = time.time()
284 loops = item.repeat()
285 for i in range(loops):
286 try:
287 rv = item.execute(self.ctx)
288 except ItemException, ie:
289 log.exception("Error")
290 sys.exit(1)
291 except exceptions.Exception, e:
292 log.debug("Error during execution: %s" % item.line.strip(), exc_info = True)
293 rv = e
294 errs = values.get("errs",0)
295 errs += 1
296 values["errs"] = errs
297
298 if loops > 1:
299 values["avg"] = total / loops
300
301 stop = time.time()
302 total += (stop - start)
303 self.ctx.report(item.command, start, stop, loops, values)
304
305
306
307
308
309
310
312 """
313 Abstract base class of all reporters
314 """
315
316 - def report(self, command, start, stop, loops, rv):
317 raise exceptions.Exception("Not implemented")
318
319
321
323 if dir is None:
324 self.stream = sys.stdout
325 else:
326 self.file = str(dir / "report.csv")
327 self.stream = open(self.file, "w")
328 print >>self.stream, "Command,Start,Stop,Elapsed,Average,Values"
329
330 - def report(self, command, start, stop, loops, values):
331 print >>self.stream, "%s,%s,%s,%s,%s,%s" % (command, start, stop, (stop-start), (stop-start)/loops, values)
332 self.stream.flush()
333
334
336
338 self.file = str(dir / "report.hdf")
339 self.hdf = tables.openFile(self.file, "w")
340 self.tbl = self.hdf.createTable("/", "report", {
341 "Command":tables.StringCol(pos=0, itemsize = 64),
342 "Start":tables.Float64Col(pos=1),
343 "Stop":tables.Float64Col(pos=2),
344 "Elapsed":tables.Float64Col(pos=3),
345 "Average":tables.Float64Col(pos=4),
346 "Values":tables.StringCol(pos=5, itemsize = 1000)
347 })
348 self.row = self.tbl.row
349
350 - def report(self, command, start, stop, loops, values):
359
360
362
364 return
365 import matplotlib.pyplot as plt
366 self.fig = plt.figure()
367 self.ax = fig.add_subplot(111)
368
369 - def report(self, command, start, stop, loops, values):
370 return
371 ax.set_ylim(-2,25)
372 ax.set_xlim(0, (last-first))
373 plt.show()
374
375
376
377
378
379
380
381
383 return parser.format_help()
384
385
387 """
388 Primary method used by the command-line execution of
389 this module.
390 """
391
392 for line in fileinput.input(files):
393 handler(line)
394 log.debug("Handled %s lines" % handler.ctx.count)
395
396
397 -def main(args, prog = sys.argv[0]):
398
399 parser.prog = prog
400 opts, files = parser.parse_args(args)
401 if opts.list:
402 ops = [ x[4:] for x in dir(Item) if x.startswith("_op_") ]
403 ops.sort()
404 for op in ops:
405 print op
406 sys.exit(0)
407 elif not files:
408 print "No files"
409 print usage()
410 sys.exit(2)
411
412 level = opts.debug and logging.DEBUG or logging.INFO
413 logging.basicConfig(level=level)
414
415 props = [""]+["--%s=%s" % (x, getattr(opts, x, "")) for x in ["omero.host", "omero.port", "omero.pass"]]
416 config = getattr(opts, "Ice.Config", "")
417 if config:
418 props.append("--Ice.Config="+config)
419 id = Ice.InitializationData()
420 id.properties = Ice.createProperties(props)
421
422 ctx = Context(id)
423 print "Running performance tests in %s" % ctx.dir
424 ctx.add_reporter(CsvReporter(ctx.dir))
425 ctx.add_reporter(HdfReporter(ctx.dir))
426 ctx.add_reporter(PlotReporter())
427 handler = PerfHandler(ctx)
428
429 log.debug("Running perf on files: %s", files)
430 handle(handler, files)
431
432 if __name__ == "__main__":
433 args = sys.argv[1:]
434 main(args)
435