Revision 8a185bfafb95254fd0ffa59a10d2daf6d8f9f445 authored by Mishal Shah on 11 October 2017, 01:54:44 UTC, committed by Mishal Shah on 25 October 2017, 07:20:28 UTC
1 parent 1d8e0af
Raw File
optimizer_counters_to_sql.py
#!/usr/bin/env python
# optimizer_counters_to_sql.py - Store CSV counters into SQLite  -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors

import sqlite3 as lite
import sys


# A simple class to connect to a DB and store the statistics from a CSV
# (comma separated values) file with optimizer counters there.
#
# See OptimizerCountersAnalysis.md for more details about working with
# produced SQLite database and analyzing the collected optimizer counters.
class OptStatsDB(object):
    def __init__(self, dbname):
        try:
            # Establish a connection to a DB.
            con = lite.connect(dbname)
            self.con = con
            cur = con.cursor()
            self.cur = cur
            # FIXME: A more efficient representation could be used.
            # There could be separate tables for all possible Stage names,
            # Transform names, Kind names, Counter names, Symbol names.
            # They would get unique integer IDs in their respective tables.
            # The Counters table would then use those unique integer IDs
            # as foreign keys.
            # This way the storage required for Counters may get much
            # smaller as it would only store integers instead of long repeating
            # strings.
            # The drawback of such an approach is that the queries may become
            # much more complex to write, as they would need to span over
            # multiple tables.

            # Create the required tables, indices, etc.
            cur.execute("CREATE TABLE IF NOT EXISTS Counters"
                        "(Id INTEGER PRIMARY KEY AUTOINCREMENT, "
                        "Stage TEXT NOT NULL, "
                        "Transform TEXT NOT NULL, "
                        "Kind TEXT, "
                        "Counter TEXT NOT NULL, "
                        "PassNum INT NOT NULL, "
                        "Delta NUMBER,"
                        "Old INT, "
                        "New INT, "
                        "Duration INT, "
                        "Symbol TEXT NOT NULL DEFAULT '')")
            cur.execute('CREATE INDEX IF NOT EXISTS StageIndex '
                        'ON Counters(Stage)')
            cur.execute('CREATE INDEX IF NOT EXISTS TransformIndex '
                        'ON Counters(Transform)')
            cur.execute('CREATE INDEX IF NOT EXISTS KindIndex '
                        'ON Counters(Kind)')
            cur.execute('CREATE INDEX IF NOT EXISTS CounterIndex '
                        'ON Counters(Counter)')
            cur.execute('CREATE INDEX IF NOT EXISTS SymbolIndex '
                        'ON Counters(Symbol)')
        except lite.Error as e:
            print('Error {}' .format(e.args[0]))
            sys.exit(1)
        finally:
            pass

    def finish(self):
        try:
            self.con.commit()
            self.con.close()
        finally:
            pass

    # Store a single statistics record into a DB.
    def addRecord(self, stage, transform, kind,
                  counter, passnum, delta, old, new, duration, symbol):
        values = [(stage, transform, kind, counter, passnum,
                   delta, old, new, duration, symbol,), ]
        self.cur.executemany(
            'INSERT INTO Counters VALUES '
            '(NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
            values)


# Read input file line by line, parse the lines and store the stats into
# the DB.
def addStatsFromInput(inputFile, db):
    for line in inputFile:
        # Read next line
        # Split into segments
        segments = line.split(",")
        if len(segments) < 6 or not (segments[0] in [
                'module', 'function', 'function_history']):
            continue
        # Trim all values
        segments = map(str.strip, segments)
        if segments[0] == 'function_history':
            # Process history records
            delta = 0.0
            (kind, counter, stage, transform, passnum,
             old, duration, symbol) = segments
            new = old
        else:
            # Process stats records
            (kind, counter, stage, transform, passnum, delta,
             old, new, duration, symbol) = segments

        db.addRecord(
            stage,
            transform,
            kind,
            counter,
            passnum,
            delta,
            old,
            new,
            duration,
            symbol)


def processStatsFile(filename, dbname):
    print(
        "Copying stats from the file '{}' into database '{}'".format(
            filename,
            dbname))
    db = OptStatsDB(dbname)
    with open(filename, "rb") as inputFile:
        addStatsFromInput(inputFile, db)
    db.finish()


def main():
    filename = sys.argv[1]
    dbname = sys.argv[2]
    processStatsFile(filename, dbname)


if __name__ == '__main__':
    main()
back to top