#!/usr/bin/env python2 import os import sys import logging import time tmp_path = "%s/git/versuchung/src"% os.environ["HOME"] if os.path.exists(tmp_path): sys.path.append(tmp_path) from versuchung.experiment import Experiment from versuchung.types import String, Bool,Integer from versuchung.files import File, Directory from versuchung.archives import GitArchive from versuchung.execute import shell from versuchung.tex import DatarefDict from lib import ClangHashHelper class IncrementalCompilation(Experiment, ClangHashHelper): inputs = { "clang_hash": GitArchive("/home/stettberger/w/clang-hash/"), "project": GitArchive("/home/stettberger/w/clang-hash/hash-projects/musl", shallow=True), "touch-only": Bool(False), "mode": String("normal"), "jobs": Integer(4), } outputs = { "stats": File("summary.dict"), } def get_sources(self, path): ret = [] for root, dirnames, filenames in os.walk(path): for filename in filenames: if filename.endswith(('.h','.c')): ret.append(os.path.join(root, filename)) if self.project_name() == "musl": # We do not touch headers that are external, since they # are untouchable. ret = [x for x in ret if x.endswith(".c") or "internal" in x ] return sorted(ret) def touch(self, path): if self.touch_only.value: os.utime(path, None) else: with open(path) as fd: content = fd.read() content = "#line 1\n" + content with open(path, "w") as fd: fd.write(content) def run(self): # Determine the mode modes = ('normal', 'ccache', 'clang-hash') if not self.mode.value in modes: raise RuntimeError("Mode can only be one of: %s"%modes) logging.info("Build the Clang-Hash Plugin") with self.clang_hash as cl_path: shell("cd %s; mkdir build; cd build; cmake ..; make -j 4", cl_path) # Project name logging.info("Cloning project... %s", self.project_name()) self.build_info = {"project-name": self.project_name(), "commit-hash": self.metadata["project-hash"], 'builds': []} with self.project as src_path: # First, we redirect all calls to the compiler to our # clang hash wrapper self.setup_compiler_paths(cl_path) # Count the number of files sources = list(self.get_sources(src_path)) nr_files = len(sources) logging.info("#files: %d", nr_files) self.build_info['file-count'] = nr_files # Initial build of the given project self.call_configure(src_path) info = {"filename": "FRESH_BUILD"} self.rebuild(src_path, info) self.build_info["builds"].append(info) # Iterate over all files for fn in sources: self.touch(fn) info = {"filename": fn} self.rebuild(src_path, info) self.build_info["builds"].append(info) # Output the summary of this build into the statistics file. with open(self.stats.path, "w+") as fd: fd.write(repr(self.build_info)) def method_name(self): mod = "append" if self.metadata['touch-only']: mod = "touch" return "%s-%s" %(mod, self.metadata['mode']) def variant_name(self): return "%s-%s"%(self.project_name(), self.method_name()) def symlink_name(self): return "%s-%s"%(self.title, self.variant_name()) if __name__ == "__main__": experiment = IncrementalCompilation() dirname = experiment(sys.argv)