Skip to content

Commit 7f63ad2

Browse files
committed
Add a script to read the counters in CSV format and store them into a SQLite database
1 parent f0a39e9 commit 7f63ad2

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

utils/optimizer_counters_to_sql.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
#!/usr/bin/env python
2+
# optimizer_counters_to_sql.py - Store CSV counters into SQLite -*- python -*-
3+
#
4+
# This source file is part of the Swift.org open source project
5+
#
6+
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
7+
# Licensed under Apache License v2.0 with Runtime Library Exception
8+
#
9+
# See https://swift.org/LICENSE.txt for license information
10+
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
11+
12+
import sqlite3 as lite
13+
import sys
14+
15+
16+
# A simple class to connect to a DB and store the statistics from a CSV
17+
# (comma separated values) file with optimizer counters there.
18+
#
19+
# See OptimizerCountersAnalysis.md for more details about working with
20+
# produced SQLite database and analyzing the collected optimizer counters.
21+
class OptStatsDB(object):
22+
def __init__(self, dbname):
23+
try:
24+
# Establish a connection to a DB.
25+
con = lite.connect(dbname)
26+
self.con = con
27+
cur = con.cursor()
28+
self.cur = cur
29+
# FIXME: A more efficient representation could be used.
30+
# There could be separate tables for all possible Stage names,
31+
# Transform names, Kind names, Counter names, Symbol names.
32+
# They would get unique integer IDs in their respective tables.
33+
# The Counters table would then use those unique integer IDs
34+
# as foreign keys.
35+
# This way the storage required for Counters may get much
36+
# smaller as it would only store integers instead of long repeating
37+
# strings.
38+
# The drawback of such an approach is that the queries may become
39+
# much more complex to write, as they would need to span over
40+
# multiple tables.
41+
42+
# Create the required tables, indices, etc.
43+
cur.execute("CREATE TABLE IF NOT EXISTS Counters"
44+
"(Id INTEGER PRIMARY KEY AUTOINCREMENT, "
45+
"Stage TEXT NOT NULL, "
46+
"Transform TEXT NOT NULL, "
47+
"Kind TEXT, "
48+
"Counter TEXT NOT NULL, "
49+
"PassNum INT NOT NULL, "
50+
"Delta NUMBER,"
51+
"Old INT, "
52+
"New INT, "
53+
"Duration INT, "
54+
"Symbol TEXT NOT NULL DEFAULT '')")
55+
cur.execute('CREATE INDEX IF NOT EXISTS StageIndex '
56+
'ON Counters(Stage)')
57+
cur.execute('CREATE INDEX IF NOT EXISTS TransformIndex '
58+
'ON Counters(Transform)')
59+
cur.execute('CREATE INDEX IF NOT EXISTS KindIndex '
60+
'ON Counters(Kind)')
61+
cur.execute('CREATE INDEX IF NOT EXISTS CounterIndex '
62+
'ON Counters(Counter)')
63+
cur.execute('CREATE INDEX IF NOT EXISTS SymbolIndex '
64+
'ON Counters(Symbol)')
65+
except lite.Error as e:
66+
print('Error {}' .format(e.args[0]))
67+
sys.exit(1)
68+
finally:
69+
pass
70+
71+
def finish(self):
72+
try:
73+
self.con.commit()
74+
self.con.close()
75+
finally:
76+
pass
77+
78+
# Store a single statistics record into a DB.
79+
def addRecord(self, stage, transform, kind,
80+
counter, passnum, delta, old, new, duration, symbol):
81+
values = [(stage, transform, kind, counter, passnum,
82+
delta, old, new, duration, symbol,), ]
83+
self.cur.executemany(
84+
'INSERT INTO Counters VALUES '
85+
'(NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
86+
values)
87+
88+
89+
# Read input file line by line, parse the lines and store the stats into
90+
# the DB.
91+
def addStatsFromInput(inputFile, db):
92+
for line in inputFile:
93+
# Read next line
94+
# Split into segments
95+
segments = line.split(",")
96+
if len(segments) < 6 or not (segments[0] in [
97+
'module', 'function', 'function_history']):
98+
continue
99+
# Trim all values
100+
segments = map(str.strip, segments)
101+
if segments[0] == 'function_history':
102+
# Process history records
103+
delta = 0.0
104+
(kind, counter, stage, transform, passnum,
105+
old, duration, symbol) = segments
106+
new = old
107+
else:
108+
# Process stats records
109+
(kind, counter, stage, transform, passnum, delta,
110+
old, new, duration, symbol) = segments
111+
112+
db.addRecord(
113+
stage,
114+
transform,
115+
kind,
116+
counter,
117+
passnum,
118+
delta,
119+
old,
120+
new,
121+
duration,
122+
symbol)
123+
124+
125+
def processStatsFile(filename, dbname):
126+
print(
127+
"Copying stats from the file '{}' into database '{}'".format(
128+
filename,
129+
dbname))
130+
db = OptStatsDB(dbname)
131+
with open(filename, "rb") as inputFile:
132+
addStatsFromInput(inputFile, db)
133+
db.finish()
134+
135+
136+
def main():
137+
filename = sys.argv[1]
138+
dbname = sys.argv[2]
139+
processStatsFile(filename, dbname)
140+
141+
142+
if __name__ == '__main__':
143+
main()

0 commit comments

Comments
 (0)