changeset 0:28b636105ed6

Working version of codeOptimizer. -Still needs to implement more finegrained control per file basis. -CXXFLAGS are hardcoded.
author Tom Fredrik Blenning Klaussen <bfg@blenning.no>
date Sat, 15 Sep 2012 20:34:39 +0200
parents
children a1224150b8f6
files Compilable.py DepGraph.py codeOptimizer.py
diffstat 3 files changed, 304 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Compilable.py	Sat Sep 15 20:34:39 2012 +0200
@@ -0,0 +1,133 @@
+import subprocess, re
+
+def tryCompileFile(file, compiler, flags):
+    cmd = compiler + " -x c++ -o /dev/null " + flags + " -c " + file
+    devnull = open('/dev/null', 'w')
+    p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+                         stdout=devnull, stderr=None, shell=True)
+    s = p.wait()
+    devnull.close()
+    return s == 0
+
+def tryCompileBuffer(buffer, compiler, flags):
+    cmd = compiler + " -x c++ -o /dev/null " + flags + " -c -"
+    devnull = open('/dev/null', 'w')
+    p = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+                         stdout=devnull, stderr=devnull, shell=True)
+    p.stdin.write(buffer)
+    p.stdin.close()
+    s = p.wait()
+    devnull.close()
+    return s == 0
+
+
+
+class Compilable:
+    def __init__(self, path):
+        self.path = path
+        self.flags = ''
+        self.lines = None
+
+    def setFlags(self, flags):
+        self.flags = flags
+
+    def worksWithoutModifications(self):
+        return tryCompileFile(self.path, 'g++', self.flags)
+
+    def activeBuffer(self):
+        self.loadFile()
+        str = ''
+        for i in range(len(self.lines)):
+            if not i in self.replace:
+                str += self.lines[i]
+            else:
+                str += self.replace[i]
+        return str
+
+    def works(self):
+        return tryCompileBuffer(self.activeBuffer(), 'g++', self.flags)
+
+    def deactivateLine(self, i):
+        self.replace[i] = "\n"
+
+    def activateLine(self, i):
+        del self.replace[i]
+
+    def loadFile(self):
+        if self.lines == None:
+            f = open(self.path, 'r')
+            self.lines = f.readlines()
+            f.close()
+            self.replace = {}
+
+    def includeLines(self):
+        self.loadFile()
+        pattern = '^\s*#include '
+        prog = re.compile(pattern)
+        res = []
+        for i in range(len(self.lines)):
+            if prog.match(self.lines[i].rstrip()):
+                res.append(i)
+        return res
+
+    def removeRemovableIncludes(self):
+        l = self.includeLines()
+        retVal = []
+        for n in l:
+            self.deactivateLine(n)
+            print 'Trying to compile ' + self.path + ' without ' + self.getPathname(self.lines[n])
+            if self.works():
+                retVal.append(n)
+            else:
+                self.activateLine(n)
+
+        return retVal
+            
+    @staticmethod
+    def getPathname(str):
+        pattern = '^\s*#include ["<]([^">]+)[">]'
+        prog = re.compile(pattern)
+        m = prog.search(str)
+        include = m.group(1)
+        return include
+        
+
+    @staticmethod
+    def getClassname(str):
+        include = Compilable.getPathname(str)
+
+        pattern = '[^/]+$'
+        prog = re.compile(pattern)
+        m = prog.search(include)
+        filename = m.group(0)
+
+        pattern = '^[^.]+'
+        prog = re.compile(pattern)
+        m = prog.search(filename)
+        basename = m.group(0)
+
+        return basename
+
+    def replaceIncludes(self):
+        l = self.includeLines()
+        retVal = []
+        for n in l:
+            if n not in self.replace:
+                rstring = 'class ' + self.getClassname(self.lines[n]) + ';\n'
+                self.replace[n] = rstring
+                if self.works():
+                    retVal.append(n)
+                else:
+                    self.activateLine(n)
+        return retVal
+
+    def dependencies(self):
+        lines = self.includeLines()
+        retVal = []
+        for line in lines:
+            retVal.append(self.getPathname(self.lines[line]))
+        return retVal
+
+
+    def __repr__(self):
+        return self.path
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DepGraph.py	Sat Sep 15 20:34:39 2012 +0200
@@ -0,0 +1,101 @@
+import numpy
+
+from types import *
+
+class DepGraph:
+    def __init__(self):
+        self.deps = []
+        self.values = []
+
+    def add(self, value):
+        if value in self.values:
+            raise ValueError
+        self.values.append(value)
+
+
+    def addDependency(self, src, dst):
+        if not type(dst) is ListType:
+            dst = [ dst ]
+
+        vl = len(self.values)
+        dl = len(self.deps)
+        si = self.values.index(src)
+        
+
+        if dl != vl:
+            full = []
+            for i in range(0, vl):
+                full.append(False)
+
+            exp = []
+            for i in range(dl, vl):
+                exp.append(False)
+                self.deps.append(full[:])
+
+            for i in range(0, dl):
+                self.deps[i].append(exp[:])
+                
+        for d in dst:
+            if d in self.values:
+                di = self.values.index(d)
+                self.deps[si][di] = True
+
+
+    @staticmethod
+    def directedGraphInternal(deps):
+        dl = len(deps)
+        myVals = []
+        for i in range(dl):
+            if not max(deps[i]):
+                myVals.append(i)
+
+        for i in myVals:
+            for j in range(dl):
+                deps[j][i] = False
+
+        retVal = myVals
+
+        if len(deps) != len(myVals):
+            subVals = self.directedGraphInternal(deps)
+            for val in myVals:
+                if val in subVals:
+                    ind = subVals.index(val)
+                    del subVals[ind]
+
+            if subVals:
+                retVal.extend(subVals)
+
+        return retVal
+
+    @staticmethod
+    def printableDepgraph(deps):
+        res=''
+        for i in range(len(deps)):
+            if res:
+                res += '\n'
+            s = ''
+            for j in range(len(deps[i])):
+                if deps[i][j]:
+                    s += '1'
+                else:
+                    s += '0'
+            res += s
+        return res
+
+    def directedGraph(self):
+        deps = self.deps[:][:]
+        vals = self.directedGraphInternal(deps)
+        retVal = []
+        for i in vals:
+            retVal.append(self.values[i])
+        return retVal
+
+
+    def toplevelDependencies(self):
+        dl = len(self.deps)
+        retVal = []
+        for i in range(dl):
+            if not max(self.deps[i]):
+                print max(self.deps[i])
+                retVal.append(self.values[i])
+        return retVal
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/codeOptimizer.py	Sat Sep 15 20:34:39 2012 +0200
@@ -0,0 +1,70 @@
+#!/usr/bin/env python -O
+
+import sys, string, os, subprocess
+
+from Compilable import Compilable
+from DepGraph import DepGraph
+
+
+
+def isHppfile(name):
+    if name.endswith(".hpp"):
+        return True
+    if name.endswith(".h"):
+        return True
+    return False
+
+def isCppfile(name):
+    if name.endswith(".cpp"):
+        return True
+    return False
+
+
+infiles = sys.argv[1:]
+
+cppfiles = {}
+unknown = []
+
+flags = '-DHAS_BOOST -DQT_NO_DEBUG -DQT_OPENGL_LIB -DQT_XML_LIB -DQT_SQL_LIB -O3 -Wall -I/opt/local/include -I/Users/bfg/QtSDK/Desktop/Qt/4.8.1/gcc/include -F/Users/bfg/QtSDK/Desktop/Qt/4.8.1/gcc/lib -I/Users/bfg/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtOpenGL -I/Users/bfg/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtXml -I/Users/bfg/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtSql -I/Users/bfg/projects/dedupe'
+
+for file in infiles:
+    if isHppfile(file) or isCppfile(file):
+        c = Compilable(file)
+        c.setFlags(flags)
+        cppfiles[file] = c
+    else:
+        unknown.append(file)
+
+if len(unknown) > 0:
+    str = ", "
+    raise SystemExit(str.join(unknown)  + " are of unknown filetype")
+
+files = cppfiles
+
+depgraph = DepGraph()
+
+for file in files:
+    depgraph.add(files[file])
+
+for file in files:
+    depgraph.addDependency(files[file], files[file].dependencies())
+
+files = depgraph.directedGraph()
+
+for file in files:
+    if not file.worksWithoutModifications():
+        print file.path
+        raise SystemExit(str.join(file.path)  + " does not compile at all")
+
+for file in files:
+    removable = file.removeRemovableIncludes()
+    if removable:
+        print 'Removable lines in ' + file.path
+        for r in removable:
+            print str(r) + ' : ' + file.lines[r].rstrip()
+            
+    replacable = file.replaceIncludes()
+    if replacable:
+        print 'Replacable lines in ' + file.path
+        for r in replacable:
+            print str(r) + ' : ' + file.lines[r].rstrip()