340
342
template_context['multiple_profiles'] = prof_stats.count > 1
341
343
# Try to free some more memory.
346
if 'sqltrace' in actions:
347
trace = da.stop_sql_traceback_logging()
348
# The trace is a list of dicts, each with the keys "sql" and
349
# "stack". "sql" is a tuple of start time, stop time, database
350
# name (with a "SQL-" prefix), and sql statement. "stack" is a
351
# tuple of filename, line number, function name, text, module
352
# name, optional supplement dict, and optional info string. The
353
# supplement dict has keys 'source_url', 'line', 'column',
354
# 'expression', 'warnings' (an iterable), and 'extra', any of
359
ix = 1 # We display these, so start at 1, not 0.
361
_heappushpop = heapq.heappushpop # This is an optimization.
363
# Set up an identifier for each trace step.
365
step['sql'] = dict(zip(
366
('start', 'stop', 'name', 'statement'), step['sql']))
367
# Divide up the stack into the more unique (app) and less
369
app_stack = step['app_stack'] = []
370
db_stack = step['db_stack'] = []
372
for f in step['stack']:
374
('filename', 'lineno', 'name', 'line', 'module',
375
'supplement', 'info'), f))
376
storm_found = storm_found or (
378
f_data['module'].startswith('storm.'))
380
db_stack.append(f_data)
382
app_stack.append(f_data)
383
# Begin to gather what app code is triggering the most SQL
386
(f['filename'], f['lineno']) for f in app_stack)
387
if trigger_key not in triggers:
388
triggers[trigger_key] = []
389
triggers[trigger_key].append(ix)
390
# Get the nbest (n=10) sql and python times
391
step['python_time'] = step['sql']['start'] - last_stop_time
392
step['sql_time'] = step['sql']['stop'] - step['sql']['start']
393
python_data = (step['python_time'], ix, step)
394
sql_data = (step['sql_time'], ix, step)
396
top_sql.append(sql_data)
397
top_python.append(python_data)
400
heapq.heapify(top_sql)
401
heapq.heapify(top_python)
402
_heappushpop(top_sql, sql_data)
403
_heappushpop(top_python, python_data)
404
# Reset for next loop.
405
last_stop_time = step['sql']['stop']
407
# Finish setting up top sql and python times.
408
top_sql.sort(reverse=True)
409
top_python.sort(reverse=True)
411
for rank, (key, ix, step) in enumerate(top_sql):
412
step['sql_rank'] = rank + 1
413
step['sql_class'] = (
414
'sql_danger' if key > 500 else
415
'sql_warning' if key > 100 else None)
416
top_sql_ids.append(dict(
419
rank=step['sql_rank'],
420
cls=step['sql_class']))
422
for rank, (key, ix, step) in enumerate(top_python):
423
step['python_rank'] = rank + 1
424
step['python_class'] = (
425
'python_danger' if key > 500 else
426
'python_warning' if key > 100 else None)
427
top_python_ids.append(dict(
430
rank=step['python_rank'],
431
cls=step['python_class']))
432
# Identify the repeated Python calls that generated SQL.
433
triggers = triggers.items()
434
triggers.sort(key=lambda x: len(x[1]))
437
for (key, ixs) in triggers:
440
info = trace[ixs[0] - 1]['app_stack'][-1].copy()
441
info['indexes'] = ixs
442
info['count'] = len(ixs)
443
top_triggers.append(info)
444
template_context.update(dict(
447
top_python=top_python_ids,
448
top_triggers=top_triggers,
449
sql_count=len(trace)))
343
450
template_context['dump_path'] = os.path.abspath(dump_path)
344
451
if actions and is_html:
345
452
# Hack the new HTML in at the end of the page.