| #!/usr/bin/python |
| # |
| # Copyright 2010 Google Inc. All Rights Reserved. |
| |
| __author__ = "asharif@google.com (Ahmad Sharif)" |
| |
| import os |
| import random |
| import shutil |
| import tempfile |
| import unittest |
| |
| from utils import command_executer |
| from utils import misc |
| |
| |
| class DivideAndMergeProfilesTest(unittest.TestCase): |
| def tearDown(self): |
| shutil.rmtree(self._program_dir) |
| for profile_dir in self._profile_dirs: |
| shutil.rmtree(profile_dir) |
| |
| def setUp(self): |
| self._ce = command_executer.GetCommandExecuter() |
| self._program_dir = tempfile.mkdtemp() |
| self._writeProgram() |
| self._writeMakefile() |
| with misc.WorkingDirectory(self._program_dir): |
| self._ce.RunCommand("make") |
| num_profile_dirs = 2 |
| self._profile_dirs = [] |
| for i in range(num_profile_dirs): |
| profile_dir = tempfile.mkdtemp() |
| command = ("GCOV_PREFIX_STRIP=%s GCOV_PREFIX=$(/bin/pwd) " |
| " %s/program" % |
| (profile_dir.count("/"), |
| self._program_dir)) |
| with misc.WorkingDirectory(profile_dir): |
| self._ce.RunCommand(command) |
| self._profile_dirs.append(profile_dir) |
| self._merge_program = "/home/build/static/projects/crosstool/profile-merge/v14.5/profile_merge.par" |
| |
| def _writeMakefile(self): |
| makefile_contents = """ |
| CC = gcc |
| |
| CFLAGS = -fprofile-generate |
| |
| SRCS=$(wildcard *.c) |
| |
| OBJS=$(SRCS:.c=.o) |
| |
| all: program |
| |
| program: $(OBJS) |
| $(CC) -o $@ $^ $(CFLAGS) |
| |
| %.o: %.c |
| $(CC) -c -o $@ $^ $(CFLAGS)""" |
| makefile = os.path.join(self._program_dir, "Makefile") |
| with open(makefile, "w") as f: |
| print >> f, makefile_contents |
| |
| def _writeProgram(self, num_files=100): |
| for i in range(num_files): |
| current_file = os.path.join(self._program_dir, "%s.c" % i) |
| with open(current_file, "w") as f: |
| if i != num_files - 1: |
| print >> f, "extern void foo%s();" % (i + 1) |
| print >> f, "void foo%s(){foo%s();}" % (i, i + 1) |
| else: |
| print >> f, "void foo%s(){printf(\"\");}" % i |
| if i == 0: |
| print >> f, "int main(){foo%s(); return 0;}" % i |
| |
| def testMerge(self): |
| reference_output = self._getReferenceOutput() |
| my_output = self._getMyOutput() |
| |
| ret = self._diffOutputs(reference_output, my_output) |
| shutil.rmtree(my_output) |
| shutil.rmtree(reference_output) |
| self.assertTrue(ret == 0) |
| |
| def _diffOutputs(self, reference, mine): |
| command = "diff -uNr %s %s" % (reference, mine) |
| return self._ce.RunCommand(command) |
| |
| def _getMyOutput(self, args=""): |
| my_output = tempfile.mkdtemp() |
| my_merge_program = os.path.join(os.path.dirname(__file__), |
| "divide_and_merge_profiles.py") |
| command = ("python %s --inputs=%s --output=%s " |
| "--chunk_size=10 " |
| "--merge_program=%s " |
| "%s" % |
| (my_merge_program, |
| ",".join(self._profile_dirs), |
| my_output, |
| self._merge_program, |
| args)) |
| self._ce.RunCommand(command) |
| return my_output |
| |
| def _getReferenceOutput(self, args=""): |
| # First do a regular merge. |
| reference_output = tempfile.mkdtemp() |
| command = ("%s --inputs=%s --output=%s %s" % |
| (self._merge_program, |
| ",".join(self._profile_dirs), |
| reference_output, |
| args)) |
| self._ce.RunCommand(command) |
| return reference_output |
| |
| def testMergeWithMultipliers(self): |
| num_profiles = len(self._profile_dirs) |
| multipliers = [str(random.randint(0, num_profiles)) \ |
| for _ in range(num_profiles)] |
| args = "--multipliers=%s" % ",".join(multipliers) |
| |
| reference_output = self._getReferenceOutput(args) |
| my_output = self._getMyOutput(args) |
| |
| ret = self._diffOutputs(reference_output, my_output) |
| |
| shutil.rmtree(my_output) |
| shutil.rmtree(reference_output) |
| self.assertTrue(ret == 0) |
| |
| if __name__ == "__main__": |
| unittest.main() |