From 326e11a2e73118d157bb6fa0b1ac3de32d235ebe Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Thu, 19 Jul 2018 15:58:02 -0600 Subject: [PATCH 001/196] simple changes. testing now --- scripts/flitcli/flit_bisect.py | 19 ++++++++++++++++--- scripts/flitcli/flitutil.py | 4 ++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 6febf387..0b3fe26b 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -413,7 +413,7 @@ def extract_symbols(file_or_filelist, objdir): return symbol_tuples -def bisect_search(is_bad, elements): +def bisect_search(is_bad, elements, found_callback=None): ''' Performs the bisect search, attempting to minimize the bad list. We could go through the list one at a time, but that would cause us to call is_bad() @@ -504,6 +504,10 @@ def bisect_search(is_bad, elements): # add to the known list to not search it again known_list.append(bad_element) + # inform caller that a bad element was found + if found_callback != None: + found_callback(bad_element) + # Perform a sanity check. If we have found all of the bad items, then # compiling with all but these bad items will cause a good build. # This will fail if our hypothesis class is wrong @@ -764,7 +768,11 @@ def bisect_build_and_check(trouble_src, gt_src): print('Searching for bad source files:') logging.info('Searching for bad source files under the trouble' ' compilation') - bad_sources = bisect_search(bisect_build_and_check, sources) + + bad_source_callback = lambda filename : \ + printlog('Found bad source file {}'.format(filename)) + bad_sources = bisect_search(bisect_build_and_check, sources, + bad_source_callback) return bad_sources def search_for_symbol_problems(args, bisect_path, replacements, sources, @@ -843,7 +851,12 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): .format(sym=sym) logging.info('%s', message) - bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples) + bad_symbol_msg = ('Found bad symbol ' + '{sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}') + bad_symbol_callback = lambda sym : \ + printlog(bad_symbol_msg.format(sym=sym)) + bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples, + bad_symbols_callback) return bad_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, diff --git a/scripts/flitcli/flitutil.py b/scripts/flitcli/flitutil.py index d9ebc7f4..9a318703 100644 --- a/scripts/flitcli/flitutil.py +++ b/scripts/flitcli/flitutil.py @@ -349,3 +349,7 @@ def extract_make_var(var, makefile='Makefile', directory='.'): var_values = output.split('=', maxsplit=1)[1].split() return var_values +def printlog(message): + 'Prints the message to stdout and logs the message at the info level' + print(message) + logging.info(message) From 8cae3b35f6ee89ec6aa36ab63789e5b956d5a343 Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Fri, 20 Jul 2018 10:59:57 -0600 Subject: [PATCH 002/196] updates working --- scripts/flitcli/flit_bisect.py | 7 ++++--- scripts/flitcli/flitutil.py | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 0b3fe26b..ea30bc00 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -769,8 +769,9 @@ def bisect_build_and_check(trouble_src, gt_src): logging.info('Searching for bad source files under the trouble' ' compilation') + bas_source_msg = 'Found bad source file {}' bad_source_callback = lambda filename : \ - printlog('Found bad source file {}'.format(filename)) + util.printlog(bad_source_msg.format(filename)) bad_sources = bisect_search(bisect_build_and_check, sources, bad_source_callback) return bad_sources @@ -854,9 +855,9 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): bad_symbol_msg = ('Found bad symbol ' '{sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}') bad_symbol_callback = lambda sym : \ - printlog(bad_symbol_msg.format(sym=sym)) + util.printlog(bad_symbol_msg.format(sym=sym)) bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples, - bad_symbols_callback) + bad_symbol_callback) return bad_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, diff --git a/scripts/flitcli/flitutil.py b/scripts/flitcli/flitutil.py index 9a318703..8f2efa47 100644 --- a/scripts/flitcli/flitutil.py +++ b/scripts/flitcli/flitutil.py @@ -87,6 +87,7 @@ import flitconfig as conf import copy +import logging import os import socket import sqlite3 From ddf0ce7c19e0ad7b01e85ad9329f2d77da7b9969 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 20 Jul 2018 12:04:54 -0600 Subject: [PATCH 003/196] bisect: add function bisect_biggest() - not yet used --- scripts/flitcli/flit_bisect.py | 85 ++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index fbcffa45..4dae79fb 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -89,6 +89,7 @@ import argparse import csv import datetime +import heapq import glob import hashlib import logging @@ -412,6 +413,90 @@ def extract_symbols(file_or_filelist, objdir): return symbol_tuples +def bisect_biggest(score_func, elements, k=1): + ''' + Performs the bisect search, attempting to find the biggest offenders. This + is different from bisect_search() in that the function that is passed gives + a numerical score of badness of the selection of elements, whereas + bisect_search() takes in a function that merely returns True or False. + + We want to not call score_func() very much. We assume the score_func() is + an expensive operation. + + Note: The same assumption as bisect_search() is in place. That is that all + bad elements are independent. This means if an element contributes to a + bad score, then it would contribute to a bad score by itself as well. This + is not always true, bit there is an assertion checking the assumption, + meaning if the assumption is violated, then an AssertionError is raised. + + @param score_func: a function that takes one argument (to_test) and returns + a number greater than zero if the function is bad. This value returned + is used to compare the elements so that the largest k offenders are + found and returned. If all offenders return the same numerical value, + then this will be less efficient than bisect_search. + Note: if the set of elements is good, then either return 0 or a + negative value. + @param elements: the elements to search over. Subsets of this list will be + given to score_func(). + @param k: number of biggest elements to return. The default is to return + the one biggest offender. If there are less than k elements that + return positive scores, then only the found offenders will be returned. + + @return list of the biggest offenders with their scores + [(elem, score), ...] + + >>> call_count = 0 + >>> def score_func(x): + ... global call_count + ... print('scoring:', x) + ... call_count += 1 + ... return -2*min(x) + + >>> call_count = 0 + >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], 3) + scoring: [1, 3, 4, 5, -1, 10, 0, -15, 3] + scoring: [1, 3, 4, 5] + scoring: [-1, 10, 0, -15, 3] + scoring: [-1, 10] + scoring: [0, -15, 3] + scoring: [0] + scoring: [-15, 3] + scoring: [-15] + scoring: [3] + scoring: [-1] + scoring: [10] + [(-15, 30), (-1, 2)] + + >>> call_count + 11 + + >>> call_count = 0 + >>> bisect_biggest(score_func, [-1, -2, -3, -4, -5], 3) + scoring: [-1, -2, -3, -4, -5] + scoring: [-1, -2] + scoring: [-3, -4, -5] + scoring: [-3] + scoring: [-4, -5] + scoring: [-4] + scoring: [-5] + [(-5, 10), (-4, 8), (-3, 6)] + >>> call_count + 7 + ''' + found_list = [] + frontier = [] + push = lambda x: heapq.heappush(frontier, (-score_func(x), x)) + pop = lambda: heapq.heappop(frontier) + push(elements) + while frontier and frontier[0][0] < 0 and len(found_list) < k: + score, elems = pop() + if len(elems) == 1: + found_list.append((elems[0], -score)) + else: + push(elems[:len(elems) // 2]) + push(elems[len(elems) // 2:]) + return found_list + def bisect_search(is_bad, elements): ''' Performs the bisect search, attempting to minimize the bad list. We could From ddc8b9fff0dc9c4b1ffbc8fcdc14afda97c22304 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 20 Jul 2018 14:36:27 -0600 Subject: [PATCH 004/196] flitutil: add unit test for printlog() --- scripts/flitcli/flitutil.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/scripts/flitcli/flitutil.py b/scripts/flitcli/flitutil.py index 8f2efa47..69eeeaf2 100644 --- a/scripts/flitcli/flitutil.py +++ b/scripts/flitcli/flitutil.py @@ -351,6 +351,19 @@ def extract_make_var(var, makefile='Makefile', directory='.'): return var_values def printlog(message): - 'Prints the message to stdout and logs the message at the info level' + ''' + Prints the message to stdout and then logs the message at the info level. + It is expected that the logging module has already been configured using + the root logger. + + >>> logger = logging.getLogger() + >>> for handler in logger.handlers[:]: + ... logger.removeHandler(handler) + >>> import sys + >>> logging.basicConfig(stream=sys.stdout, level=logging.INFO) + >>> printlog('Danger Will Robinson!') + Danger Will Robinson! + INFO:root:Danger Will Robinson! + ''' print(message) logging.info(message) From e0ea4beb82420909dc76525a7d13bee78ed0b96e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 20 Jul 2018 14:47:03 -0600 Subject: [PATCH 005/196] bisect: fix review comments about callback and testing --- scripts/flitcli/flit_bisect.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index ea30bc00..99b96c78 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -441,7 +441,7 @@ def bisect_search(is_bad, elements, found_callback=None): >>> def is_bad(x,y): ... global call_count ... call_count += 1 - ... return min(x) < 0 + ... return min(x) < 0 if x else False >>> x = bisect_search(is_bad, [1, 3, 4, 5, -1, 10, 0, -15, 3]) >>> sorted(x) [-15, -1] @@ -451,6 +451,14 @@ def bisect_search(is_bad, elements, found_callback=None): >>> call_count 9 + Test out the found_callback() functionality. + >>> s = set() + >>> y = bisect_search(is_bad, [-1, -2, -3, -4], found_callback=s.add) + >>> sorted(y) + [-4, -3, -2, -1] + >>> sorted(s) + [-4, -3, -2, -1] + See what happens when it has a pair that only show up together and not alone. Only if -6 and 5 are in the list, then is_bad returns true. The assumption of this algorithm is that bad elements are independent, @@ -500,13 +508,13 @@ def bisect_search(is_bad, elements, found_callback=None): # double check that we found a bad element before declaring it bad if last_result or is_bad([bad_element], known_list + quest_list): bad_list.append(bad_element) + # inform caller that a bad element was found + if found_callback != None: + found_callback(bad_element) # add to the known list to not search it again known_list.append(bad_element) - # inform caller that a bad element was found - if found_callback != None: - found_callback(bad_element) # Perform a sanity check. If we have found all of the bad items, then # compiling with all but these bad items will cause a good build. From 35e0a574303f59ef6829ff0ed52a1dcca2afb2e8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 20 Jul 2018 14:49:07 -0600 Subject: [PATCH 006/196] bisect: add one more test for found_callback --- scripts/flitcli/flit_bisect.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 99b96c78..e36e1b8e 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -465,10 +465,18 @@ def bisect_search(is_bad, elements, found_callback=None): so this should throw an exception. >>> def is_bad(x,y): ... return max(x) - min(x) > 10 - >>> x = bisect_search(is_bad, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) + >>> bisect_search(is_bad, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) Traceback (most recent call last): ... AssertionError: Assumption that bad elements are independent was wrong + + Check that the found_callback is not called on false positives. Here I + expect no output since no single element can be found. + >>> try: + ... bisect_search(is_bad, [-6, 2, 3, -3, -1, 0, 0, -5, 5], + ... found_callback=print) + ... except AssertionError: + ... pass ''' # copy the incoming list so that we don't modify it quest_list = list(elements) From fc80a743fd284b6a9deeb20e4d294903364b4604 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 20 Jul 2018 15:14:03 -0600 Subject: [PATCH 007/196] bisect_biggest: fix for empty list --- scripts/flitcli/flit_bisect.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 4dae79fb..de4108a6 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -426,8 +426,8 @@ def bisect_biggest(score_func, elements, k=1): Note: The same assumption as bisect_search() is in place. That is that all bad elements are independent. This means if an element contributes to a bad score, then it would contribute to a bad score by itself as well. This - is not always true, bit there is an assertion checking the assumption, - meaning if the assumption is violated, then an AssertionError is raised. + is not always true, and this function does not verify this assumption. + Instead, it will only return the largest singleton offenders. @param score_func: a function that takes one argument (to_test) and returns a number greater than zero if the function is bad. This value returned @@ -445,14 +445,10 @@ def bisect_biggest(score_func, elements, k=1): @return list of the biggest offenders with their scores [(elem, score), ...] - >>> call_count = 0 >>> def score_func(x): - ... global call_count ... print('scoring:', x) - ... call_count += 1 ... return -2*min(x) - >>> call_count = 0 >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], 3) scoring: [1, 3, 4, 5, -1, 10, 0, -15, 3] scoring: [1, 3, 4, 5] @@ -467,10 +463,6 @@ def bisect_biggest(score_func, elements, k=1): scoring: [10] [(-15, 30), (-1, 2)] - >>> call_count - 11 - - >>> call_count = 0 >>> bisect_biggest(score_func, [-1, -2, -3, -4, -5], 3) scoring: [-1, -2, -3, -4, -5] scoring: [-1, -2] @@ -480,9 +472,12 @@ def bisect_biggest(score_func, elements, k=1): scoring: [-4] scoring: [-5] [(-5, 10), (-4, 8), (-3, 6)] - >>> call_count - 7 + + >>> bisect_biggest(score_func, []) + [] ''' + if not elements: + return [] found_list = [] frontier = [] push = lambda x: heapq.heappush(frontier, (-score_func(x), x)) From 436c6a02353c8340ade66e100426ff84218ab429 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 18:27:30 -0600 Subject: [PATCH 008/196] bisect: add helper function get_comparison_result() --- scripts/flitcli/flit_bisect.py | 94 +++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 6 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index de4108a6..fac6724d 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -309,6 +309,48 @@ def update_gt_results(directory, verbose=False, print(' - done') logging.info('Finished Updating ground-truth results') +def get_comparison_result(resultfile): + ''' + Returns the floating-point comparison value stored in the flit comparison + csv file (resultfile). + + The result is pulled simply from the comparison column (first row). + + >>> from tempfile import NamedTemporaryFile as TFile + >>> with TFile(mode='w', delete=False) as fout: + ... _ = fout.write('name,host,compiler,...,comparison,...\\n' + ... 'test,name,clang++,...,15.342,...\\n') + ... fname = fout.name + >>> get_comparison_result(fname) + 15.342 + + Make sure NULL values are handled appropriately + >>> with open(fname, 'w') as fout: + ... _ = fout.write('comparison\\n' + ... 'NULL\\n') + >>> print(get_comparison_result(fname)) + None + + Try out a value that is not a number and not NULL + >>> with open(fname, 'w') as fout: + ... _ = fout.write('comparison\\n' + ... 'coconut\\n') + >>> get_comparison_result(fname) + Traceback (most recent call last): + ... + ValueError: could not convert string to float: 'coconut' + + Delete the file now that we're done with it + >>> import os + >>> os.remove(fname) + ''' + with open(resultfile, 'r') as fin: + parser = csv.DictReader(fin) + # should only have one row + for row in parser: + val = row['comparison'] + return float(val) if val != 'NULL' else None + def is_result_bad(resultfile): ''' Returns True if the results from the resultfile is considered 'bad', @@ -316,13 +358,53 @@ def is_result_bad(resultfile): @param resultfile: path to the results csv file after comparison @return True if the result is different from ground-truth + + Try out a positive value + >>> from tempfile import NamedTemporaryFile as TFile + >>> with TFile(mode='w', delete=False) as fout: + ... _ = fout.write('name,host,compiler,...,comparison,...\\n' + ... 'test,name,clang++,...,15.342,...\\n') + ... fname = fout.name + >>> is_result_bad(fname) + True + + Try out a value that is less than zero + >>> with open(fname, 'w') as fout: + ... _ = fout.write('comparison\\n' + ... '-1e-34\\n') + >>> is_result_bad(fname) + True + + Try out a value that is identically zero + >>> with open(fname, 'w') as fout: + ... _ = fout.write('comparison\\n' + ... '0.0\\n') + >>> is_result_bad(fname) + False + + Make sure NULL values are handled appropriately + >>> with open(fname, 'w') as fout: + ... _ = fout.write('comparison\\n' + ... 'NULL\\n') + >>> is_result_bad(fname) + Traceback (most recent call last): + ... + TypeError: float() argument must be a string or a number, not 'NoneType' + + Try out a value that is not a number and not NULL + >>> with open(fname, 'w') as fout: + ... _ = fout.write('comparison\\n' + ... 'coconut\\n') + >>> is_result_bad(fname) + Traceback (most recent call last): + ... + ValueError: could not convert string to float: 'coconut' + + Delete the file now that we're done with it + >>> import os + >>> os.remove(fname) ''' - with open(resultfile, 'r') as fin: - parser = csv.DictReader(fin) - # should only have one row - for row in parser: - # identical to ground truth means comparison is zero - return float(row['comparison']) != 0.0 + return float(get_comparison_result(resultfile)) != 0.0 SymbolTuple = namedtuple('SymbolTuple', 'src, symbol, demangled, fname, lineno') SymbolTuple.__doc__ = ''' From 85293ab601cbd0f31f3f5b1bace4b2170bea8eb4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 18:45:31 -0600 Subject: [PATCH 009/196] bisect: add argument --biggest to specify how many to find --- scripts/flitcli/flit_bisect.py | 44 +++++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index fac6724d..6253f0f9 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -794,6 +794,17 @@ def parse_args(arguments, prog=sys.argv[0]): runbusect-01-out), or the object files (e.g. bisect-01/obj/*). ''') + parser.add_argument('-k', '--biggest', metavar='K', type=int, default=None, + help=''' + Instead of returning all of the offenders of + variability, only return the largest K offenders, + with their contribution to variability. If K is + close to the total number of offenders, then this + is a much slower approach than the full algorithm. + It is best if K is small. This value used comes + from the custom comparison function you provide for + your flit test. + ''') args = parser.parse_args(arguments) @@ -913,18 +924,26 @@ def bisect_build_and_check(trouble_src, gt_src): resultfile = util.extract_make_var('BISECT_RESULT', makepath, args.directory)[0] resultpath = os.path.join(args.directory, resultfile) - result_is_bad = is_result_bad(resultpath) + if args.biggest is None: + result = is_result_bad(resultpath) + result_str = 'bad' if result_is_bad else 'good' + else: + result = get_comparison_result(resultpath) + result_str = str(result) - result_str = 'bad' if result_is_bad else 'good' sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) - return result_is_bad + return result print('Searching for bad source files:') logging.info('Searching for bad source files under the trouble' ' compilation') - bad_sources = bisect_search(bisect_build_and_check, sources) + if args.biggest is None: + bad_sources = bisect_search(bisect_build_and_check, sources) + else: + bad_sources = bisect_biggest(bisect_build_and_check, sources, + k=args.biggest) return bad_sources def search_for_symbol_problems(args, bisect_path, replacements, sources, @@ -991,13 +1010,17 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): resultfile = util.extract_make_var('BISECT_RESULT', makepath, args.directory)[0] resultpath = os.path.join(args.directory, resultfile) - result_is_bad = is_result_bad(resultpath) + if args.biggest is None: + result = is_result_bad(resultpath) + result_str = 'bad' if result_is_bad else 'good' + else: + result = get_comparison_result(resultpath) + result_str = str(result) - result_str = 'bad' if result_is_bad else 'good' sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) - return result_is_bad + return result print('Searching for bad symbols in:', bad_source) logging.info('Searching for bad symbols in: %s', bad_source) @@ -1021,7 +1044,12 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): logging.warning('%s', message_2) return [] - bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples) + if args.biggest is None: + bad_symbols = bisect_search(bisect_symbol_build_and_check, + symbol_tuples) + else: + bad_symbols = bisect_biggest(bisect_symbol_build_and_check, + symbol_tuples, k=args.biggest) return bad_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, From a11b46134c4db68fff3e37c33b9bdad52ad7e8c0 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 20:59:48 -0600 Subject: [PATCH 010/196] bisect: change bisect_search to take a function with only one argument This is more in line with delta debugging. It makes it so that we only pass in the list of objects we want to test. It is really implementation details for the problem being addressed that says we actually care about the complement. Also, the complement is easy enough to compute in the test function without adding unnecessary computational complexity --- scripts/flitcli/flit_bisect.py | 80 +++++++++++++++------------------- 1 file changed, 36 insertions(+), 44 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 45e4bc82..5bbfe372 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -427,9 +427,9 @@ def bisect_search(is_bad, elements, found_callback=None): within the algorithm to verify that this assumption is not vialoated. If the assumption is found to be violated, then an AssertionError is raised. - @param is_bad: a function that takes two arguments (maybe_bad_list, - maybe_good_list) and returns True if the maybe_bad_list has a bad - element + @param is_bad: a function that takes one argument, the list of elements to + test if they are bad. The function then returns True if the given list + has a bad element @param elements: contains bad elements, but potentially good elements too @return minimal bad list of all elements that cause is_bad() to return True @@ -437,7 +437,7 @@ def bisect_search(is_bad, elements, found_callback=None): Here's an example of finding all negative numbers in a list. Not very useful for this particular task, but it is demonstrative of how to use it. >>> call_count = 0 - >>> def is_bad(x,y): + >>> def is_bad(x): ... global call_count ... call_count += 1 ... return min(x) < 0 if x else False @@ -462,7 +462,7 @@ def bisect_search(is_bad, elements, found_callback=None): alone. Only if -6 and 5 are in the list, then is_bad returns true. The assumption of this algorithm is that bad elements are independent, so this should throw an exception. - >>> def is_bad(x,y): + >>> def is_bad(x): ... return max(x) - min(x) > 10 >>> bisect_search(is_bad, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) Traceback (most recent call last): @@ -479,55 +479,41 @@ def bisect_search(is_bad, elements, found_callback=None): ''' # copy the incoming list so that we don't modify it quest_list = list(elements) - known_list = [] bad_list = [] - while len(quest_list) > 0 and is_bad(quest_list, known_list): + while len(quest_list) > 0 and is_bad(quest_list): # find one bad element quest_copy = quest_list - no_test = list(known_list) last_result = False while len(quest_copy) > 1: # split the questionable list into two lists half_1 = quest_copy[:len(quest_copy) // 2] half_2 = quest_copy[len(quest_copy) // 2:] - last_result = is_bad(half_1, no_test + half_2) + last_result = is_bad(half_1) if last_result: quest_copy = half_1 - no_test.extend(half_2) - # TODO: possible optimization. - # TODO- if the length of half_2 is big enough, test - # TODO- is_bad(half_2, no_test + half_1) - # TODO- and if that returns False, then mark half_2 as known so - # TODO- that we don't need to search it again. else: # optimization: mark half_1 as known, so that we don't need to # search it again quest_list = quest_list[len(half_1):] - known_list.extend(half_1) # update the local search quest_copy = half_2 - no_test.extend(half_1) bad_element = quest_list.pop(0) # double check that we found a bad element before declaring it bad - if last_result or is_bad([bad_element], known_list + quest_list): + if last_result or is_bad([bad_element]): bad_list.append(bad_element) # inform caller that a bad element was found if found_callback != None: found_callback(bad_element) - # add to the known list to not search it again - known_list.append(bad_element) - - # Perform a sanity check. If we have found all of the bad items, then # compiling with all but these bad items will cause a good build. # This will fail if our hypothesis class is wrong good_list = list(set(elements).difference(bad_list)) - assert not is_bad(good_list, bad_list), \ + assert not is_bad(good_list), \ 'Assumption that bad elements are independent was wrong' return bad_list @@ -683,7 +669,7 @@ def search_for_linker_problems(args, bisect_path, replacements, sources, libs): the libraries included, and checks to see if there are reproducibility problems. ''' - def bisect_libs_build_and_check(trouble_libs, dummy_libs): + def bisect_libs_build_and_check(trouble_libs): ''' Compiles all source files under the ground truth compilation and statically links in the trouble_libs. @@ -729,9 +715,13 @@ def bisect_libs_build_and_check(trouble_libs, dummy_libs): print('Searching for bad intel static libraries:') logging.info('Searching for bad static libraries included by intel linker:') - #bad_libs = bisect_search(bisect_libs_build_and_check, libs) + #bas_library_msg = 'Found bad library {}' + #bad_library_callback = lambda filename : \ + # util.printlog(bad_library_msg.format(filename)) + #bad_libs = bisect_search(bisect_libs_build_and_check, libs, + # found_callback=bad_library_callback) #return bad_libs - if bisect_libs_build_and_check(libs, []): + if bisect_libs_build_and_check(libs): return libs return [] @@ -739,7 +729,7 @@ def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. ''' - def bisect_build_and_check(trouble_src, gt_src): + def bisect_build_and_check(trouble_src): ''' Compiles the compilation with trouble_src compiled with the trouble compilation and with gt_src compiled with the ground truth compilation. @@ -750,6 +740,7 @@ def bisect_build_and_check(trouble_src, gt_src): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. ''' + gt_src = list(set(sources).difference(trouble_src)) makefile = create_bisect_makefile(bisect_path, replacements, gt_src, trouble_src, dict()) makepath = os.path.join(bisect_path, makefile) @@ -783,11 +774,11 @@ def bisect_build_and_check(trouble_src, gt_src): logging.info('Searching for bad source files under the trouble' ' compilation') - bas_source_msg = 'Found bad source file {}' + bad_source_msg = 'Found bad source file {}' bad_source_callback = lambda filename : \ util.printlog(bad_source_msg.format(filename)) bad_sources = bisect_search(bisect_build_and_check, sources, - bad_source_callback) + found_callback=bad_source_callback) return bad_sources def search_for_symbol_problems(args, bisect_path, replacements, sources, @@ -804,7 +795,19 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, @return a list of identified bad symbols (if any) ''' - def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): + print('Searching for bad symbols in:', bad_source) + logging.info('Searching for bad symbols in: %s', bad_source) + logging.info('Note: inlining disabled to isolate functions') + logging.info('Note: only searching over globally exported functions') + logging.debug('Symbols:') + symbol_tuples = extract_symbols(bad_source, + os.path.join(args.directory, 'obj')) + for sym in symbol_tuples: + message = ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' \ + .format(sym=sym) + logging.info('%s', message) + + def bisect_symbol_build_and_check(trouble_symbols): ''' Compiles the compilation with all files compiled under the ground truth compilation except for the given symbols for the given files. @@ -820,6 +823,7 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. ''' + gt_symbols = list(set(symbol_tuples).difference(trouble_symbols)) all_sources = list(sources) # copy the list of all source files symbol_sources = [x.src for x in trouble_symbols + gt_symbols] trouble_src = [] @@ -862,20 +866,8 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): return result_is_bad - print('Searching for bad symbols in:', bad_source) - logging.info('Searching for bad symbols in: %s', bad_source) - logging.info('Note: inlining disabled to isolate functions') - logging.info('Note: only searching over globally exported functions') - logging.debug('Symbols:') - symbol_tuples = extract_symbols(bad_source, - os.path.join(args.directory, 'obj')) - for sym in symbol_tuples: - message = ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' \ - .format(sym=sym) - logging.info('%s', message) - # Check to see if -fPIC destroyed any chance of finding any bad symbols - if not bisect_symbol_build_and_check(symbol_tuples, []): + if not bisect_symbol_build_and_check(symbol_tuples): message_1 = ' Warning: -fPIC compilation destroyed the optimization' message_2 = ' Cannot find any trouble symbols' print(message_1) @@ -889,7 +881,7 @@ def bisect_symbol_build_and_check(trouble_symbols, gt_symbols): bad_symbol_callback = lambda sym : \ util.printlog(bad_symbol_msg.format(sym=sym)) bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples, - bad_symbol_callback) + found_callback=bad_symbol_callback) return bad_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, From fb4e2f86e7e8414147fe4e5bc03d9a8a3b5dac4c Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 21:00:51 -0600 Subject: [PATCH 011/196] bisect: add a large unit test that runs bisect --- tests/flit_bisect/Makefile | 31 +++ tests/flit_bisect/data/tests/BisectTest.cpp | 32 ++++ tests/flit_bisect/data/tests/file1.cpp | 41 ++++ tests/flit_bisect/data/tests/file1.h | 11 ++ tests/flit_bisect/data/tests/file2.cpp | 26 +++ tests/flit_bisect/data/tests/file2.h | 11 ++ tests/flit_bisect/data/tests/file3.cpp | 34 ++++ tests/flit_bisect/data/tests/file3.h | 11 ++ tests/flit_bisect/tst_bisect.py | 201 ++++++++++++++++++++ 9 files changed, 398 insertions(+) create mode 100644 tests/flit_bisect/Makefile create mode 100644 tests/flit_bisect/data/tests/BisectTest.cpp create mode 100644 tests/flit_bisect/data/tests/file1.cpp create mode 100644 tests/flit_bisect/data/tests/file1.h create mode 100644 tests/flit_bisect/data/tests/file2.cpp create mode 100644 tests/flit_bisect/data/tests/file2.h create mode 100644 tests/flit_bisect/data/tests/file3.cpp create mode 100644 tests/flit_bisect/data/tests/file3.h create mode 100644 tests/flit_bisect/tst_bisect.py diff --git a/tests/flit_bisect/Makefile b/tests/flit_bisect/Makefile new file mode 100644 index 00000000..1d04452e --- /dev/null +++ b/tests/flit_bisect/Makefile @@ -0,0 +1,31 @@ +RUNNER := python3 +SRC := $(wildcard tst_*.py) +RUN_TARGETS := $(SRC:%.py=run_%) +MPIRUN := $(shell command -v mpirun 2>/dev/null) +MPICXX := $(shell command -v mpic++ 2>/dev/null) + +include ../color_out.mk + +.PHONY: check help clean build run_% +ifeq ($(MPIRUN),) +check: + $(call color_out,RED,Warning: mpirun is not found on your system; skipping the MPI tests) +else ifeq ($(MPICXX),) +check: + $(call color_out,RED,Warning: mpic++ is not found on your system; skipping the MPI tests) +else +check: $(TARGETS) $(RUN_TARGETS) +endif + +help: + @echo "Makefile for running tests on FLiT framework" + @echo " help print this help documentation and exit" + @echo " build just compile the targets" + @echo " check run tests and print results to the console" + @echo " clean remove all generated files" + +build: +clean: + +run_% : %.py + @$(RUNNER) $< diff --git a/tests/flit_bisect/data/tests/BisectTest.cpp b/tests/flit_bisect/data/tests/BisectTest.cpp new file mode 100644 index 00000000..e0fe34f6 --- /dev/null +++ b/tests/flit_bisect/data/tests/BisectTest.cpp @@ -0,0 +1,32 @@ +#include "file1.h" +#include "file2.h" +#include "file3.h" + +#include + +#include + +#include + +template +class BisectTest : public flit::TestBase { +public: + BisectTest(std::string id) : flit::TestBase(std::move(id)) {} + virtual size_t getInputsPerRun() override { return 0; } + virtual std::vector getDefaultInput() override { return {}; } + virtual long double compare(long double ground_truth, + long double test_results) const override { + return std::abs(test_results - ground_truth); + } + +protected: + virtual flit::Variant run_impl(const std::vector &ti) override { + FLIT_UNUSED(ti); + return file1_all() + file2_all() + file3_all(); + } + +protected: + using flit::TestBase::id; +}; + +REGISTER_TYPE(BisectTest) diff --git a/tests/flit_bisect/data/tests/file1.cpp b/tests/flit_bisect/data/tests/file1.cpp new file mode 100644 index 00000000..d685cd6d --- /dev/null +++ b/tests/flit_bisect/data/tests/file1.cpp @@ -0,0 +1,41 @@ +#include "file1.h" + +#include + +#include + +int file1_func1() { return 1; } + +int file1_func2_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 2 + 5; // variability introduced = 5 + } else { + return 2; + } +} + +int file1_func3_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 3 + 2; // variability introduced = 2 + } else { + return 3; + } +} + +int file1_func4_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 4 + 3; // variability introduced = 3 + } else { + return 4; + } +} + +int file1_func5() { return 5; } + +int file1_all() { + return file1_func1() + + file1_func2_PROBLEM() + + file1_func3_PROBLEM() + + file1_func4_PROBLEM() + + file1_func5(); +} diff --git a/tests/flit_bisect/data/tests/file1.h b/tests/flit_bisect/data/tests/file1.h new file mode 100644 index 00000000..3d804f81 --- /dev/null +++ b/tests/flit_bisect/data/tests/file1.h @@ -0,0 +1,11 @@ +#ifndef FILE1_H +#define FILE1_H + +int file1_func1(); +int file1_func2_PROBLEM(); // variability = 5 +int file1_func3_PROBLEM(); // variability = 2 +int file1_func4_PROBLEM(); // variability = 3 +int file1_func5(); +int file1_all(); + +#endif // FILE1_H diff --git a/tests/flit_bisect/data/tests/file2.cpp b/tests/flit_bisect/data/tests/file2.cpp new file mode 100644 index 00000000..67420345 --- /dev/null +++ b/tests/flit_bisect/data/tests/file2.cpp @@ -0,0 +1,26 @@ +#include "file2.h" + +#include + +#include + +int file2_func1_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 1 + 7; // variability introduced = 7 + } else { + return 1; + } +} + +int file2_func2() { return 2; } +int file2_func3() { return 3; } +int file2_func4() { return 4; } +int file2_func5() { return 5; } + +int file2_all() { + return file2_func1_PROBLEM() + + file2_func2() + + file2_func3() + + file2_func4() + + file2_func5(); +} diff --git a/tests/flit_bisect/data/tests/file2.h b/tests/flit_bisect/data/tests/file2.h new file mode 100644 index 00000000..9ca12d4d --- /dev/null +++ b/tests/flit_bisect/data/tests/file2.h @@ -0,0 +1,11 @@ +#ifndef FILE2_H +#define FILE2_H + +int file2_func1_PROBLEM(); // variability = 7 +int file2_func2(); +int file2_func3(); +int file2_func4(); +int file2_func5(); +int file2_all(); + +#endif // FILE2_H diff --git a/tests/flit_bisect/data/tests/file3.cpp b/tests/flit_bisect/data/tests/file3.cpp new file mode 100644 index 00000000..48ab8b98 --- /dev/null +++ b/tests/flit_bisect/data/tests/file3.cpp @@ -0,0 +1,34 @@ +#include "file1.h" + +#include + +#include + +int file3_func1() { return 1; } + +int file3_func2_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 2 + 1; // variability introduced = 1 + } else { + return 2; + } +} + +int file3_func3() { return 3; } +int file3_func4() { return 4; } + +int file3_func5_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 5 + 3; // variability introduced = 3 + } else { + return 5; + } +} + +int file3_all() { + return file3_func1() + + file3_func2_PROBLEM() + + file3_func3() + + file3_func4() + + file3_func5_PROBLEM(); +} diff --git a/tests/flit_bisect/data/tests/file3.h b/tests/flit_bisect/data/tests/file3.h new file mode 100644 index 00000000..e7968667 --- /dev/null +++ b/tests/flit_bisect/data/tests/file3.h @@ -0,0 +1,11 @@ +#ifndef FILE3_H +#define FILE3_H + +int file3_func1(); +int file3_func2_PROBLEM(); // variability = 1 +int file3_func3(); +int file3_func4(); +int file3_func5_PROBLEM(); // variability = 3 +int file3_all(); + +#endif // FILE3_H diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py new file mode 100644 index 00000000..4e1126fc --- /dev/null +++ b/tests/flit_bisect/tst_bisect.py @@ -0,0 +1,201 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests FLiT's capabilities to run bisect and identify the problem files and +functions + +The tests are below using doctest + +Let's now make a temporary directory and test that we can successfully compile +and run FLiT bisect + +>>> import glob +>>> import os +>>> import shutil +>>> import subprocess as subp + +>>> with th.tempdir() as temp_dir: +... _ = th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS +... print() +... shutil.rmtree(os.path.join(temp_dir, 'tests')) +... _ = shutil.copytree(os.path.join('data', 'tests'), +... os.path.join(temp_dir, 'tests')) +... _ = th.flit.main(['bisect', '-C', temp_dir, '--precision', 'double', +... 'g++ -O3', 'BisectTest']) # doctest:+ELLIPSIS +... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: +... log_contents = fin.read() +Creating /.../flit-config.toml +Creating /.../custom.mk +Creating /.../main.cpp +Creating /.../tests/Empty.cpp +Creating /.../Makefile + +Updating ground-truth results - ground-truth.csv - done +Searching for bad source files: + Created /.../bisect-01/bisect-make-01.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-02.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-03.mk - compiling and running - good + Created /.../bisect-01/bisect-make-04.mk - compiling and running - bad +Found bad source file tests/file1.cpp + Created /.../bisect-01/bisect-make-05.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-06.mk - compiling and running - bad +Found bad source file tests/file3.cpp + Created /.../bisect-01/bisect-make-07.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-08.mk - compiling and running - good + Created /.../bisect-01/bisect-make-09.mk - compiling and running - bad +Found bad source file tests/file2.cpp + Created /.../bisect-01/bisect-make-10.mk - compiling and running - good + bad sources: + tests/file1.cpp + tests/file3.cpp + tests/file2.cpp +Searching for bad symbols in: tests/file1.cpp + Created /.../bisect-01/bisect-make-11.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-12.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-13.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-14.mk - compiling and running - good + Created /.../bisect-01/bisect-make-15.mk - compiling and running - good + Created /.../bisect-01/bisect-make-16.mk - compiling and running - bad +Found bad symbol /.../tests/file1.cpp:9 ... -- file1_func2_PROBLEM() + Created /.../bisect-01/bisect-make-17.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-18.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-19.mk - compiling and running - bad +Found bad symbol /.../tests/file1.cpp:17 ... -- file1_func3_PROBLEM() + Created /.../bisect-01/bisect-make-20.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-21.mk - compiling and running - bad +Found bad symbol /.../tests/file1.cpp:25 ... -- file1_func4_PROBLEM() + Created /.../bisect-01/bisect-make-22.mk - compiling and running - good + Created /.../bisect-01/bisect-make-23.mk - compiling and running - good + bad symbols in tests/file1.cpp: + line 9 -- file1_func2_PROBLEM() + line 17 -- file1_func3_PROBLEM() + line 25 -- file1_func4_PROBLEM() +Searching for bad symbols in: tests/file3.cpp + Created /.../bisect-01/bisect-make-24.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-25.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-26.mk - compiling and running - good + Created /.../bisect-01/bisect-make-27.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-28.mk - compiling and running - bad +Found bad symbol /.../tests/file3.cpp:9 ... -- file3_func2_PROBLEM() + Created /.../bisect-01/bisect-make-29.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-30.mk - compiling and running - bad +Found bad symbol /.../tests/file3.cpp:20 ... -- file3_func5_PROBLEM() + Created /.../bisect-01/bisect-make-31.mk - compiling and running - good + Created /.../bisect-01/bisect-make-32.mk - compiling and running - good + bad symbols in tests/file3.cpp: + line 9 -- file3_func2_PROBLEM() + line 20 -- file3_func5_PROBLEM() +Searching for bad symbols in: tests/file2.cpp + Created /.../bisect-01/bisect-make-33.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-34.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-35.mk - compiling and running - good + Created /.../bisect-01/bisect-make-36.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-37.mk - compiling and running - good + Created /.../bisect-01/bisect-make-38.mk - compiling and running - bad +Found bad symbol /.../tests/file2.cpp:8 ... -- file2_func1_PROBLEM() + Created /.../bisect-01/bisect-make-39.mk - compiling and running - good + Created /.../bisect-01/bisect-make-40.mk - compiling and running - good + bad symbols in tests/file2.cpp: + line 8 -- file2_func1_PROBLEM() +All bad symbols: + /.../tests/file1.cpp:9 ... -- file1_func2_PROBLEM() + /.../tests/file1.cpp:17 ... -- file1_func3_PROBLEM() + /.../tests/file1.cpp:25 ... -- file1_func4_PROBLEM() + /.../tests/file3.cpp:9 ... -- file3_func2_PROBLEM() + /.../tests/file3.cpp:20 ... -- file3_func5_PROBLEM() + /.../tests/file2.cpp:8 ... -- file2_func1_PROBLEM() + +TODO: test the log_contents variable +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From 59e6d1dfcfb429c1db1a35088a1bdd473792d26b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 21:08:05 -0600 Subject: [PATCH 012/196] bisect: indent found callback messages --- scripts/flitcli/flit_bisect.py | 8 ++++---- tests/flit_bisect/tst_bisect.py | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 5bbfe372..f187d385 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -715,7 +715,7 @@ def bisect_libs_build_and_check(trouble_libs): print('Searching for bad intel static libraries:') logging.info('Searching for bad static libraries included by intel linker:') - #bas_library_msg = 'Found bad library {}' + #bas_library_msg = ' Found bad library {}' #bad_library_callback = lambda filename : \ # util.printlog(bad_library_msg.format(filename)) #bad_libs = bisect_search(bisect_libs_build_and_check, libs, @@ -774,7 +774,7 @@ def bisect_build_and_check(trouble_src): logging.info('Searching for bad source files under the trouble' ' compilation') - bad_source_msg = 'Found bad source file {}' + bad_source_msg = ' Found bad source file {}' bad_source_callback = lambda filename : \ util.printlog(bad_source_msg.format(filename)) bad_sources = bisect_search(bisect_build_and_check, sources, @@ -876,8 +876,8 @@ def bisect_symbol_build_and_check(trouble_symbols): logging.warning('%s', message_2) return [] - bad_symbol_msg = ('Found bad symbol ' - '{sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}') + bad_symbol_msg = \ + ' Found bad symbol on line {sym.lineno} -- {sym.demangled}' bad_symbol_callback = lambda sym : \ util.printlog(bad_symbol_msg.format(sym=sym)) bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples, diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index 4e1126fc..2bb9e75e 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -116,14 +116,14 @@ Created /.../bisect-01/bisect-make-02.mk - compiling and running - bad Created /.../bisect-01/bisect-make-03.mk - compiling and running - good Created /.../bisect-01/bisect-make-04.mk - compiling and running - bad -Found bad source file tests/file1.cpp + Found bad source file tests/file1.cpp Created /.../bisect-01/bisect-make-05.mk - compiling and running - bad Created /.../bisect-01/bisect-make-06.mk - compiling and running - bad -Found bad source file tests/file3.cpp + Found bad source file tests/file3.cpp Created /.../bisect-01/bisect-make-07.mk - compiling and running - bad Created /.../bisect-01/bisect-make-08.mk - compiling and running - good Created /.../bisect-01/bisect-make-09.mk - compiling and running - bad -Found bad source file tests/file2.cpp + Found bad source file tests/file2.cpp Created /.../bisect-01/bisect-make-10.mk - compiling and running - good bad sources: tests/file1.cpp @@ -136,14 +136,14 @@ Created /.../bisect-01/bisect-make-14.mk - compiling and running - good Created /.../bisect-01/bisect-make-15.mk - compiling and running - good Created /.../bisect-01/bisect-make-16.mk - compiling and running - bad -Found bad symbol /.../tests/file1.cpp:9 ... -- file1_func2_PROBLEM() + Found bad symbol on line 9 -- file1_func2_PROBLEM() Created /.../bisect-01/bisect-make-17.mk - compiling and running - bad Created /.../bisect-01/bisect-make-18.mk - compiling and running - bad Created /.../bisect-01/bisect-make-19.mk - compiling and running - bad -Found bad symbol /.../tests/file1.cpp:17 ... -- file1_func3_PROBLEM() + Found bad symbol on line 17 -- file1_func3_PROBLEM() Created /.../bisect-01/bisect-make-20.mk - compiling and running - bad Created /.../bisect-01/bisect-make-21.mk - compiling and running - bad -Found bad symbol /.../tests/file1.cpp:25 ... -- file1_func4_PROBLEM() + Found bad symbol on line 25 -- file1_func4_PROBLEM() Created /.../bisect-01/bisect-make-22.mk - compiling and running - good Created /.../bisect-01/bisect-make-23.mk - compiling and running - good bad symbols in tests/file1.cpp: @@ -156,10 +156,10 @@ Created /.../bisect-01/bisect-make-26.mk - compiling and running - good Created /.../bisect-01/bisect-make-27.mk - compiling and running - bad Created /.../bisect-01/bisect-make-28.mk - compiling and running - bad -Found bad symbol /.../tests/file3.cpp:9 ... -- file3_func2_PROBLEM() + Found bad symbol on line 9 -- file3_func2_PROBLEM() Created /.../bisect-01/bisect-make-29.mk - compiling and running - bad Created /.../bisect-01/bisect-make-30.mk - compiling and running - bad -Found bad symbol /.../tests/file3.cpp:20 ... -- file3_func5_PROBLEM() + Found bad symbol on line 20 -- file3_func5_PROBLEM() Created /.../bisect-01/bisect-make-31.mk - compiling and running - good Created /.../bisect-01/bisect-make-32.mk - compiling and running - good bad symbols in tests/file3.cpp: @@ -172,7 +172,7 @@ Created /.../bisect-01/bisect-make-36.mk - compiling and running - bad Created /.../bisect-01/bisect-make-37.mk - compiling and running - good Created /.../bisect-01/bisect-make-38.mk - compiling and running - bad -Found bad symbol /.../tests/file2.cpp:8 ... -- file2_func1_PROBLEM() + Found bad symbol on line 8 -- file2_func1_PROBLEM() Created /.../bisect-01/bisect-make-39.mk - compiling and running - good Created /.../bisect-01/bisect-make-40.mk - compiling and running - good bad symbols in tests/file2.cpp: From 44739301ef572da3d48c745a7157443cfbb7abc1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 21:12:38 -0600 Subject: [PATCH 013/196] bisect: add license to test file headers --- tests/flit_bisect/data/tests/BisectTest.cpp | 83 +++++++++++++++++++++ tests/flit_bisect/data/tests/file1.cpp | 83 +++++++++++++++++++++ tests/flit_bisect/data/tests/file1.h | 83 +++++++++++++++++++++ tests/flit_bisect/data/tests/file2.cpp | 83 +++++++++++++++++++++ tests/flit_bisect/data/tests/file2.h | 83 +++++++++++++++++++++ tests/flit_bisect/data/tests/file3.cpp | 83 +++++++++++++++++++++ tests/flit_bisect/data/tests/file3.h | 83 +++++++++++++++++++++ 7 files changed, 581 insertions(+) diff --git a/tests/flit_bisect/data/tests/BisectTest.cpp b/tests/flit_bisect/data/tests/BisectTest.cpp index e0fe34f6..f59d1b65 100644 --- a/tests/flit_bisect/data/tests/BisectTest.cpp +++ b/tests/flit_bisect/data/tests/BisectTest.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "file1.h" #include "file2.h" #include "file3.h" diff --git a/tests/flit_bisect/data/tests/file1.cpp b/tests/flit_bisect/data/tests/file1.cpp index d685cd6d..5e37a6a8 100644 --- a/tests/flit_bisect/data/tests/file1.cpp +++ b/tests/flit_bisect/data/tests/file1.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "file1.h" #include diff --git a/tests/flit_bisect/data/tests/file1.h b/tests/flit_bisect/data/tests/file1.h index 3d804f81..e426f2ca 100644 --- a/tests/flit_bisect/data/tests/file1.h +++ b/tests/flit_bisect/data/tests/file1.h @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #ifndef FILE1_H #define FILE1_H diff --git a/tests/flit_bisect/data/tests/file2.cpp b/tests/flit_bisect/data/tests/file2.cpp index 67420345..45d84bcf 100644 --- a/tests/flit_bisect/data/tests/file2.cpp +++ b/tests/flit_bisect/data/tests/file2.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "file2.h" #include diff --git a/tests/flit_bisect/data/tests/file2.h b/tests/flit_bisect/data/tests/file2.h index 9ca12d4d..087b0ba0 100644 --- a/tests/flit_bisect/data/tests/file2.h +++ b/tests/flit_bisect/data/tests/file2.h @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #ifndef FILE2_H #define FILE2_H diff --git a/tests/flit_bisect/data/tests/file3.cpp b/tests/flit_bisect/data/tests/file3.cpp index 48ab8b98..22fcfea5 100644 --- a/tests/flit_bisect/data/tests/file3.cpp +++ b/tests/flit_bisect/data/tests/file3.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "file1.h" #include diff --git a/tests/flit_bisect/data/tests/file3.h b/tests/flit_bisect/data/tests/file3.h index e7968667..70334e98 100644 --- a/tests/flit_bisect/data/tests/file3.h +++ b/tests/flit_bisect/data/tests/file3.h @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #ifndef FILE3_H #define FILE3_H From 1bf36f35987052da34ed2e1a2136d0acb3791afc Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 21:20:15 -0600 Subject: [PATCH 014/196] bisect: simplify test Makefile --- tests/flit_bisect/Makefile | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tests/flit_bisect/Makefile b/tests/flit_bisect/Makefile index 1d04452e..162e9d20 100644 --- a/tests/flit_bisect/Makefile +++ b/tests/flit_bisect/Makefile @@ -1,21 +1,9 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) -MPIRUN := $(shell command -v mpirun 2>/dev/null) -MPICXX := $(shell command -v mpic++ 2>/dev/null) - -include ../color_out.mk .PHONY: check help clean build run_% -ifeq ($(MPIRUN),) -check: - $(call color_out,RED,Warning: mpirun is not found on your system; skipping the MPI tests) -else ifeq ($(MPICXX),) -check: - $(call color_out,RED,Warning: mpic++ is not found on your system; skipping the MPI tests) -else check: $(TARGETS) $(RUN_TARGETS) -endif help: @echo "Makefile for running tests on FLiT framework" From 2fd91f6dc4080519465650d53b5836e2e137a93b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 22:10:54 -0600 Subject: [PATCH 015/196] bisect: update test from adding license --- tests/flit_bisect/tst_bisect.py | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index 2bb9e75e..5b4fe084 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -136,35 +136,35 @@ Created /.../bisect-01/bisect-make-14.mk - compiling and running - good Created /.../bisect-01/bisect-make-15.mk - compiling and running - good Created /.../bisect-01/bisect-make-16.mk - compiling and running - bad - Found bad symbol on line 9 -- file1_func2_PROBLEM() + Found bad symbol on line 92 -- file1_func2_PROBLEM() Created /.../bisect-01/bisect-make-17.mk - compiling and running - bad Created /.../bisect-01/bisect-make-18.mk - compiling and running - bad Created /.../bisect-01/bisect-make-19.mk - compiling and running - bad - Found bad symbol on line 17 -- file1_func3_PROBLEM() + Found bad symbol on line 100 -- file1_func3_PROBLEM() Created /.../bisect-01/bisect-make-20.mk - compiling and running - bad Created /.../bisect-01/bisect-make-21.mk - compiling and running - bad - Found bad symbol on line 25 -- file1_func4_PROBLEM() + Found bad symbol on line 108 -- file1_func4_PROBLEM() Created /.../bisect-01/bisect-make-22.mk - compiling and running - good Created /.../bisect-01/bisect-make-23.mk - compiling and running - good bad symbols in tests/file1.cpp: - line 9 -- file1_func2_PROBLEM() - line 17 -- file1_func3_PROBLEM() - line 25 -- file1_func4_PROBLEM() + line 92 -- file1_func2_PROBLEM() + line 100 -- file1_func3_PROBLEM() + line 108 -- file1_func4_PROBLEM() Searching for bad symbols in: tests/file3.cpp Created /.../bisect-01/bisect-make-24.mk - compiling and running - bad Created /.../bisect-01/bisect-make-25.mk - compiling and running - bad Created /.../bisect-01/bisect-make-26.mk - compiling and running - good Created /.../bisect-01/bisect-make-27.mk - compiling and running - bad Created /.../bisect-01/bisect-make-28.mk - compiling and running - bad - Found bad symbol on line 9 -- file3_func2_PROBLEM() + Found bad symbol on line 92 -- file3_func2_PROBLEM() Created /.../bisect-01/bisect-make-29.mk - compiling and running - bad Created /.../bisect-01/bisect-make-30.mk - compiling and running - bad - Found bad symbol on line 20 -- file3_func5_PROBLEM() + Found bad symbol on line 103 -- file3_func5_PROBLEM() Created /.../bisect-01/bisect-make-31.mk - compiling and running - good Created /.../bisect-01/bisect-make-32.mk - compiling and running - good bad symbols in tests/file3.cpp: - line 9 -- file3_func2_PROBLEM() - line 20 -- file3_func5_PROBLEM() + line 92 -- file3_func2_PROBLEM() + line 103 -- file3_func5_PROBLEM() Searching for bad symbols in: tests/file2.cpp Created /.../bisect-01/bisect-make-33.mk - compiling and running - bad Created /.../bisect-01/bisect-make-34.mk - compiling and running - bad @@ -172,18 +172,18 @@ Created /.../bisect-01/bisect-make-36.mk - compiling and running - bad Created /.../bisect-01/bisect-make-37.mk - compiling and running - good Created /.../bisect-01/bisect-make-38.mk - compiling and running - bad - Found bad symbol on line 8 -- file2_func1_PROBLEM() + Found bad symbol on line 91 -- file2_func1_PROBLEM() Created /.../bisect-01/bisect-make-39.mk - compiling and running - good Created /.../bisect-01/bisect-make-40.mk - compiling and running - good bad symbols in tests/file2.cpp: - line 8 -- file2_func1_PROBLEM() + line 91 -- file2_func1_PROBLEM() All bad symbols: - /.../tests/file1.cpp:9 ... -- file1_func2_PROBLEM() - /.../tests/file1.cpp:17 ... -- file1_func3_PROBLEM() - /.../tests/file1.cpp:25 ... -- file1_func4_PROBLEM() - /.../tests/file3.cpp:9 ... -- file3_func2_PROBLEM() - /.../tests/file3.cpp:20 ... -- file3_func5_PROBLEM() - /.../tests/file2.cpp:8 ... -- file2_func1_PROBLEM() + /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() + /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() + /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() + /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() + /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() + /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() TODO: test the log_contents variable ''' From 064bd8af41a3a8bece142fd62672e51374ef8154 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 23 Jul 2018 15:40:21 -0600 Subject: [PATCH 016/196] travis-ci: first attempt at simplifying and running --- .travis.yml | 45 ++++++++++++--------------------------------- 1 file changed, 12 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index 36732aa3..28762c43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -80,39 +80,18 @@ # # -- LICENSE END -- -sudo: required language: cpp -dist: trusty -# addons: -# apt: -# packages: -# - gcc-5 -# - g++-5 + addons: + apt: + packages: + - python3-toml -env: - global: - - LLVM_VERSION=3.9.0 - - LLVM_ARCHIVE_PATH=$HOME/clang+llvm.tar.xz - - export PATH=$HOME/usr/bin:$PATH - - export LD_LIBRARY_PATH=$HOME/usr/lib:$LD_LIBRARY_PATH +script: make -j 4 && make check -install: - #starts in $HOME/build/PRUNERS/FLiT - - cd $HOME/build - # Install LLVM/Clang 3.9 - - wget http://llvm.org/releases/$LLVM_VERSION/clang+llvm-$LLVM_VERSION-x86_64-linux-gnu-ubuntu-14.04.tar.xz -O $LLVM_ARCHIVE_PATH - - mkdir $HOME/usr - - tar xf $LLVM_ARCHIVE_PATH -C $HOME/usr --strip-components 1 - -# script: - - export CLANG_ONLY=True - - cd $HOME/build/PRUNERS/FLiT/src - - make -j 4 - -notifications: - email: false - slack: - rooms: - - pruners:aXHVdiVFtqtMfzNW4IutZNDW - on_success: always - on_failure: always +#notifications: +# email: false +# slack: +# rooms: +# - pruners:aXHVdiVFtqtMfzNW4IutZNDW +# on_success: always +# on_failure: always From 0e6844980869c7c0d1e4cf4f7eac1d67b5074d04 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 23 Jul 2018 15:56:51 -0600 Subject: [PATCH 017/196] travis-ci: try to fix it with dependencies in --- .travis.yml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 28762c43..bef299bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,10 +81,13 @@ # -- LICENSE END -- language: cpp - addons: - apt: - packages: - - python3-toml +addons: + apt: + packages: + - python3 + - python3-toml + - openmpi-bin + - libopenmpi-dev script: make -j 4 && make check From aef71da94e13d6462eaadf38c580eaf15a08fb71 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 23 Jul 2018 16:03:39 -0600 Subject: [PATCH 018/196] travis-ci: specify xenial as the distribution apparently the trusty distribution failed to do an apt-get update --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index bef299bf..47900222 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,6 +81,7 @@ # -- LICENSE END -- language: cpp +dist: xenial addons: apt: packages: From 28bfda04565fa42386ecc0515037e7073caaecc6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 23 Jul 2018 16:07:55 -0600 Subject: [PATCH 019/196] travis-ci: try specifying apt source --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 47900222..98fd11b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -81,9 +81,11 @@ # -- LICENSE END -- language: cpp -dist: xenial +os: linux addons: apt: + sources: + - ubuntu-toolchain-r-test packages: - python3 - python3-toml From c376c5deb249096fc61dea5f646aab3a1dbca5f3 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 23 Jul 2018 16:16:26 -0600 Subject: [PATCH 020/196] travis-ci: install toml using pip --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 98fd11b1..3d42c599 100644 --- a/.travis.yml +++ b/.travis.yml @@ -88,10 +88,12 @@ addons: - ubuntu-toolchain-r-test packages: - python3 - - python3-toml + - python3-pip - openmpi-bin - libopenmpi-dev +before_install: pip3 install --user toml + script: make -j 4 && make check #notifications: From 14ccc2edbef809507625a1d9ff4f817d878ed924 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 12:36:55 -0600 Subject: [PATCH 021/196] Makefile: change from CC to CXX since it is C++ --- Makefile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 281634ca..b4e71358 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ PREFIX ?= /usr -#CC := clang++ -CC := g++ +#CXX ?= clang++ +CXX ?= g++ FFLAGS ?= LIBDIR := lib SRCDIR := src @@ -68,10 +68,10 @@ help: $(TARGET): $(OBJ) mkdir -p lib - $(CC) $(CPPFLAGS) -o $@ $^ $(LINKFLAGS) + $(CXX) $(CPPFLAGS) -o $@ $^ $(LINKFLAGS) $(SRCDIR)/%.o: $(SRCDIR)/%.cpp Makefile - $(CC) $(CPPFLAGS) $(DEPFLAGS) -c $< -o $@ + $(CXX) $(CPPFLAGS) $(DEPFLAGS) -c $< -o $@ .PRECIOUS: src/%.d -include $(SOURCE:%.cpp=%.d) From 5308482a56290dff85140054874aadfc9271b45f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 12:39:14 -0600 Subject: [PATCH 022/196] Makefile.in: add -no-pie flag if not using GCC 4 or 5 --- data/Makefile.in | 50 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 426053d8..6b6f89e1 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -137,7 +137,9 @@ DEV_CFLAGS += -Wuninitialized DEV_CFLAGS += -Wno-shift-count-overflow # This flag specifies NOT to link as a position-independent executable -LD_REQUIRED += -no-pie +# Note: this flag does not exist in GCC 4 or GCC 5 so it will fail to compile +# we need extra logic to check for this and conditionally add this flag +#LD_REQUIRED += -no-pie LD_REQUIRED += -lm LD_REQUIRED += -lstdc++ ifeq ($(UNAME_S),Darwin) # If we are on a Mac OSX system @@ -147,7 +149,44 @@ else LD_REQUIRED += -Wl,-rpath=$(realpath $(FLIT_LIB_DIR)) endif -DEV_LDFLAGS += +# Helper functions to determine if the compiler is a particular version of GCC + +# Returns the compiler name as output by the --version flag +# @param 1: executable name or path to compiler +GET_COMPILER = $(shell $1 --version | head -n 1 | awk '{{ print $$1 }}') + +# Returns 1 if the given compiler is GCC, else 0 +# @param 1: executable name or path to compiler +IS_GCC = $(shell expr $(call GET_COMPILER,$(1)) = gcc \| \ + $(call GET_COMPILER,$1) = g++) + +# Returns the version of the compiler as returned by -dumpversion +# @param 1: executable name or path to compiler +GET_COMPILER_VER = $(shell $1 -dumpversion) + +# Returns 1 if the major version matches else 0 +# @param 1: executable name or path to compiler +# @param 2: major version number as an integer +IS_MAJOR_VER = $(shell expr substr $(call GET_COMPILER_VER,$1) 1 1 = $2) + +# Returns 1 if the compiler is GCC version 4 or version 5 +# @param 1: executable name or path to compiler +IS_GCC_4_OR_5 = $(shell expr $(call IS_GCC,$1) \& \ + \( $(call IS_MAJOR_VER,$1,4) \| \ + $(call IS_MAJOR_VER,$1,5) \)) + +DEV_LDFLAGS = +GT_LDFLAGS = + +# if the dev compiler is not an old version of GCC +ifeq ($(call IS_GCC_4_OR_5,$(DEV_CC)),0) + DEV_LDFLAGS += -no-pie +endif + +# if the gt compiler is not an old version of GCC +ifeq ($(call IS_GCC_4_OR_5,$(GT_CC)),0) + GT_LDFLAGS += -no-pie +endif DEPFLAGS += -MMD -MF $(patsubst %.o,%.d,$@) @@ -365,6 +404,11 @@ R_DEP := $(R_OBJ:%.o=%.d) .PHONY: rec rec: $(R_TARGET) +# if the current compiler is not GCC 4 or 5, then enable -no-pie +ifeq ($(call IS_GCC_4_OR_5,$($(R_CUR_COMPILER))),0) + LD_REQUIRED += -no-pie +endif + $(R_TARGET): $(R_OBJ) $($(R_CUR_COMPILER)) $($(R_CUR_OPTL)) $($(R_CUR_SWITCHES)) \ $($(R_CUR_COMPILER)_REQUIRED) $(CC_REQUIRED) \ @@ -530,7 +574,7 @@ $(GT_OUT): $(GT_TARGET) $(RUNWRAP) ./$(GT_TARGET) --output $(GT_OUT) --no-timing $(GT_TARGET): $(GT_OBJ) Makefile custom.mk - $(GT_CC) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) + $(GT_CC) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) $(OBJ_DIR)/%_gt.o: %.cpp Makefile custom.mk | $(OBJ_DIR) $(GT_CC) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ From 0a6a399f0d2a8f9ba622e9f52308dbfad7f05c87 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 13:06:55 -0600 Subject: [PATCH 023/196] travis-ci: remove extra apt repository - not yet needed --- .travis.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3d42c599..78bc916b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,13 +84,11 @@ language: cpp os: linux addons: apt: - sources: - - ubuntu-toolchain-r-test packages: - - python3 - - python3-pip - - openmpi-bin - - libopenmpi-dev + - python3 + - python3-pip + - openmpi-bin + - libopenmpi-dev before_install: pip3 install --user toml From bb5c60b04d46631357e3e33f9ae19d4e824adcb1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 13:07:37 -0600 Subject: [PATCH 024/196] Makefile: check dev and gt only when not in recursive mode --- data/Makefile.in | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 6b6f89e1..3a85f741 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -178,16 +178,6 @@ IS_GCC_4_OR_5 = $(shell expr $(call IS_GCC,$1) \& \ DEV_LDFLAGS = GT_LDFLAGS = -# if the dev compiler is not an old version of GCC -ifeq ($(call IS_GCC_4_OR_5,$(DEV_CC)),0) - DEV_LDFLAGS += -no-pie -endif - -# if the gt compiler is not an old version of GCC -ifeq ($(call IS_GCC_4_OR_5,$(GT_CC)),0) - GT_LDFLAGS += -no-pie -endif - DEPFLAGS += -MMD -MF $(patsubst %.o,%.d,$@) TESTS = $(wildcard tests/*.cpp) @@ -429,6 +419,16 @@ $(OBJ_DIR)/%_$(R_ID).o: %.cpp Makefile custom.mk | $(OBJ_DIR) # Otherwise, we're not in a recursion. else # ifndef R_IS_RECURSED +# if the dev compiler is not an old version of GCC +ifeq ($(call IS_GCC_4_OR_5,$(DEV_CC)),0) + DEV_LDFLAGS += -no-pie +endif + +# if the gt compiler is not an old version of GCC +ifeq ($(call IS_GCC_4_OR_5,$(GT_CC)),0) + GT_LDFLAGS += -no-pie +endif + $(OBJ_DIR): mkdir -p $(OBJ_DIR) $(RESULTS_DIR): From f7346524437048a646fe59745fd46ff8a76cb242 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 13:08:22 -0600 Subject: [PATCH 025/196] bisect: get the GCC 4 and 5 fix to work with bisect --- data/Makefile_bisect_binary.in | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/data/Makefile_bisect_binary.in b/data/Makefile_bisect_binary.in index aca9b2fb..58c403d3 100644 --- a/data/Makefile_bisect_binary.in +++ b/data/Makefile_bisect_binary.in @@ -124,6 +124,13 @@ SPLIT_SRC := {EXTRA_CC_FLAGS} {EXTRA_LD_FLAGS} +TROUBLE_LDFLAGS = + +# if the trouble compiler is not GCC 4 or 5, then add -no-pie +ifeq ($(call IS_GCC_4_OR_5,$(TROUBLE_CC)),0) + TROUBLE_LDFLAGS += -no-pie +endif + BUILD_GT_LOCAL := {build_gt_local} TROUBLE_TARGET_OBJ := $(addprefix \ @@ -204,10 +211,10 @@ $(TROUBLE_TARGET_OUT): $(TROUBLE_TARGET) | $(BISECT_DIR) $(RUNWRAP) ./$< --precision "$(PRECISION)" --output $@ $(TEST_CASE) --no-timing $(BISECT_TARGET): $(BISECT_OBJ) $(SPLIT_OBJ) Makefile custom.mk | $(BISECT_DIR) - $(GT_CC) $(CC_REQUIRED) -o $@ $(BISECT_OBJ) $(SPLIT_OBJ) $(LD_REQUIRED) + $(GT_CC) $(CC_REQUIRED) -o $@ $(BISECT_OBJ) $(SPLIT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) $(TROUBLE_TARGET): $(TROUBLE_TARGET_OBJ) Makefile custom.mk | $(BISECT_DIR) - $(TROUBLE_CC) $(CC_REQUIRED) -o $@ $(TROUBLE_TARGET_OBJ) $(LD_REQUIRED) + $(TROUBLE_CC) $(CC_REQUIRED) -o $@ $(TROUBLE_TARGET_OBJ) $(LD_REQUIRED) $(TROUBLE_LDFLAGS) .PHONY: trouble trouble-out trouble: $(TROUBLE_TARGET) From 1f8f10274a32457d957f36e103d66af317745d0f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 15:25:46 -0600 Subject: [PATCH 026/196] tst_bisect: make more robust --- scripts/flitcli/flit.py | 21 +++++++- tests/flit_bisect/tst_bisect.py | 90 ++++++++++++++++++++++++++++++--- 2 files changed, 103 insertions(+), 8 deletions(-) diff --git a/scripts/flitcli/flit.py b/scripts/flitcli/flit.py index 399aaaf6..df51a97c 100755 --- a/scripts/flitcli/flit.py +++ b/scripts/flitcli/flit.py @@ -160,7 +160,26 @@ def generate_help_documentation(subcom_map): return (parser.format_help(), help_subparser.format_help()) -def main(arguments): +def main(arguments, outstream=sys.stdout): + ''' + Main logic here. + + For ease of use when within python, the stdout can be captured using the + optional outstream parameter. You can use this to capture the stdout that + would go to the console and put it into a StringStream or maybe a file. + ''' + if outstream == sys.stdout: + return _main_impl(arguments) + else: + try: + oldout = sys.stdout + sys.stdout = outstream + _main_impl(arguments) + finally: + sys.stdout = oldout + +def _main_impl(arguments): + 'Implementation of main' script_dir = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, script_dir) import flitconfig as conf diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index 5b4fe084..f9152542 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -93,24 +93,100 @@ >>> import os >>> import shutil >>> import subprocess as subp +>>> from io import StringIO >>> with th.tempdir() as temp_dir: -... _ = th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS -... print() +... with StringIO() as ostream: +... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() ... shutil.rmtree(os.path.join(temp_dir, 'tests')) ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) -... _ = th.flit.main(['bisect', '-C', temp_dir, '--precision', 'double', -... 'g++ -O3', 'BisectTest']) # doctest:+ELLIPSIS +... with StringIO() as ostream: +... _ = th.flit.main(['bisect', '-C', temp_dir, +... '--precision', 'double', +... 'g++ -O3', 'BisectTest'], +... outstream=ostream) +... bisect_out = ostream.getvalue().splitlines() ... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: -... log_contents = fin.read() +... log_contents = fin.readlines() + +Verify the output of flit init +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS Creating /.../flit-config.toml Creating /.../custom.mk Creating /.../main.cpp Creating /.../tests/Empty.cpp Creating /.../Makefile - -Updating ground-truth results - ground-truth.csv - done + +Let's see that the ground truth results are updated first +>>> bisect_out[0] +'Updating ground-truth results - ground-truth.csv - done' + +Verify that all source files were found and output during the search +>>> sorted([x.split()[-1] for x in bisect_out +... if x.startswith(' Found bad source file')]) +['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] + +Verify that the three bad sources were output in the "bad sources:" section +>>> idx = bisect_out.index(' bad sources:') +>>> sorted(bisect_out[idx+1:idx+4]) +[' tests/file1.cpp', ' tests/file2.cpp', ' tests/file3.cpp'] +>>> bisect_out[idx+4].startswith('Searching for bad symbols in:') +True + +Verify that all three files were searched individually +>>> sorted([x.split()[-1] for x in bisect_out +... if x.startswith('Searching for bad symbols in:')]) +['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] + +Verify all functions were identified during the symbol searches +>>> print('\\n'.join( +... sorted([' '.join(x.split()[-4:]) for x in bisect_out +... if x.startswith(' Found bad symbol on line')]))) +line 100 -- file1_func3_PROBLEM() +line 103 -- file3_func5_PROBLEM() +line 108 -- file1_func4_PROBLEM() +line 91 -- file2_func1_PROBLEM() +line 92 -- file1_func2_PROBLEM() +line 92 -- file3_func2_PROBLEM() + +Verify the bad symbols section for file1.cpp +>>> idx = bisect_out.index(' bad symbols in tests/file1.cpp:') +>>> print('\\n'.join(sorted(bisect_out[idx+1:idx+4]))) + line 100 -- file1_func3_PROBLEM() + line 108 -- file1_func4_PROBLEM() + line 92 -- file1_func2_PROBLEM() +>>> bisect_out[idx+4].startswith(' ') +False + +Verify the bad symbols section for file2.cpp +>>> idx = bisect_out.index(' bad symbols in tests/file2.cpp:') +>>> bisect_out[idx+1] +' line 91 -- file2_func1_PROBLEM()' +>>> bisect_out[idx+2].startswith(' ') +False + +Verify the bad symbols section for file3.cpp +>>> idx = bisect_out.index(' bad symbols in tests/file3.cpp:') +>>> print('\\n'.join(sorted(bisect_out[idx+1:idx+3]))) + line 103 -- file3_func5_PROBLEM() + line 92 -- file3_func2_PROBLEM() +>>> bisect_out[idx+3].startswith(' ') +False + +Test the All bad symbols section of the output +>>> idx = bisect_out.index('All bad symbols:') +>>> print('\\n'.join(sorted(bisect_out[idx+1:]))) # doctest:+ELLIPSIS + /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() + /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() + /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() + /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() + /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() + /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() + +Example output to be expected: + Searching for bad source files: Created /.../bisect-01/bisect-make-01.mk - compiling and running - bad Created /.../bisect-01/bisect-make-02.mk - compiling and running - bad From 01972e6e0c78e955048a001fb8a494e52afac62a Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 15:41:42 -0600 Subject: [PATCH 027/196] tst_uninstall: remove use of recursive glob The Travis CI framework uses Ubuntu 14.04 by default and that version has python 3.4. The recursive use of glob was added in python 3.5 --- tests/flit_install/tst_uninstall_runthrough.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/flit_install/tst_uninstall_runthrough.py b/tests/flit_install/tst_uninstall_runthrough.py index b442035a..9f4a2670 100644 --- a/tests/flit_install/tst_uninstall_runthrough.py +++ b/tests/flit_install/tst_uninstall_runthrough.py @@ -121,10 +121,12 @@ ... stdout=subp.DEVNULL, stderr=subp.DEVNULL) ... prevdir = os.path.realpath(os.curdir) ... os.chdir(temp_dir) -... all_files = glob.glob('**', recursive=True) +... all_files = [os.path.join(base, name) +... for base, folders, filenames in os.walk('.') +... for name in folders + filenames] ... os.chdir(prevdir) >>> sorted(all_files) -['lib', 'lib/otherlib.so'] +['./lib', './lib/otherlib.so'] ''' # Test setup before the docstring is run. From 4875cbfefb10cae01ff722aa4f480b9410259d3f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 15:55:09 -0600 Subject: [PATCH 028/196] flit.py: fix outstream when used with doctest --- scripts/flitcli/flit.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/flitcli/flit.py b/scripts/flitcli/flit.py index df51a97c..0da95c91 100755 --- a/scripts/flitcli/flit.py +++ b/scripts/flitcli/flit.py @@ -160,7 +160,7 @@ def generate_help_documentation(subcom_map): return (parser.format_help(), help_subparser.format_help()) -def main(arguments, outstream=sys.stdout): +def main(arguments, outstream=None): ''' Main logic here. @@ -168,7 +168,7 @@ def main(arguments, outstream=sys.stdout): optional outstream parameter. You can use this to capture the stdout that would go to the console and put it into a StringStream or maybe a file. ''' - if outstream == sys.stdout: + if outstream is None: return _main_impl(arguments) else: try: From 03cc0d70bb17c3503c400995fa57e8cddb70c63c Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 18:25:09 -0600 Subject: [PATCH 029/196] tests/mpi: make test more robust to order of output --- tests/flit_mpi/tst_run_mpi.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/flit_mpi/tst_run_mpi.py b/tests/flit_mpi/tst_run_mpi.py index 10d38069..d33e1cc1 100644 --- a/tests/flit_mpi/tst_run_mpi.py +++ b/tests/flit_mpi/tst_run_mpi.py @@ -137,15 +137,15 @@ Make sure the info statement about MPI being enabled is done at each make call ->>> compile_str[1] -'MPI is enabled' ->>> run_str[1] -'MPI is enabled' +>>> 'MPI is enabled' in compile_str +True +>>> 'MPI is enabled' in run_str +True Make sure the correct arguments are passed to mpirun ->>> run_str[2] -'mpirun -n 2 ./gtrun --output ground-truth.csv --no-timing' +>>> 'mpirun -n 2 ./gtrun --output ground-truth.csv --no-timing' in run_str +True Make sure the console messages are there, but they can be out of order From 5fed1a1eb0e1b394d2933fbae3baddb0934f9f0e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 24 Jul 2018 20:18:33 -0600 Subject: [PATCH 030/196] tst_flit_cpp: fix one test to work with noncompliant gcc This test was made using the C++11 specifications, but fails with GCC 4.8.4, which is supposed to be C++11 compliant. Well, now it will work with the old specification as well as the new (but FLiT still needs C++11). --- tests/flit_src/tst_flit_cpp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/flit_src/tst_flit_cpp.cpp b/tests/flit_src/tst_flit_cpp.cpp index 8971e0e1..1a720904 100644 --- a/tests/flit_src/tst_flit_cpp.cpp +++ b/tests/flit_src/tst_flit_cpp.cpp @@ -90,6 +90,7 @@ #include #include +#include #include #include #include @@ -577,7 +578,7 @@ TH_REGISTER(tst_readFile_exists); void tst_readFile_doesnt_exist() { TH_THROWS(flit::readFile("/this/file/should/not/exist"), - std::system_error); + std::ios_base::failure); } TH_REGISTER(tst_readFile_doesnt_exist); From 8d0890b02f34277d1332d26f5919a6fb50160037 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 25 Jul 2018 17:35:22 -0600 Subject: [PATCH 031/196] README: Travis CI build status Added for master and devel branches. Currently the values do not look good, but after this branch gets merged into devel, and devel gets merged into master, that should change to passing on both counts. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index e1a38e0d..c37574f2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +| branch | status | +|---------|---------| +| master | [![Build Status](https://travis-ci.org/PRUNERS/FLiT.svg?branch=master)](https://travis-ci.org/PRUNERS/FLiT) | +| devel | [![Build Status](https://travis-ci.org/PRUNERS/FLiT.svg?branch=devel)](https://travis-ci.org/PRUNERS/FLiT) | + # FLiT [![FLiT Bird](/images/flit-small.png)](https://github.com/PRUNERS/FLiT "FLiT") From f319463c436c9cad856ea1d45ad4cf12ca630bad Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 22:01:43 -0600 Subject: [PATCH 032/196] bisect: memoize every test function passed to bisect --- scripts/flitcli/flit_bisect.py | 16 +++++++++++++- tests/flit_bisect/tst_bisect.py | 37 +++++++++++++++------------------ 2 files changed, 32 insertions(+), 21 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index f187d385..43cf03b5 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -669,6 +669,7 @@ def search_for_linker_problems(args, bisect_path, replacements, sources, libs): the libraries included, and checks to see if there are reproducibility problems. ''' + memo = {} # for memoization def bisect_libs_build_and_check(trouble_libs): ''' Compiles all source files under the ground truth compilation and @@ -681,6 +682,9 @@ def bisect_libs_build_and_check(trouble_libs): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground-truth compilation. ''' + idx = tuple(trouble_libs) + if idx in memo: + return memo[idx] repl_copy = dict(replacements) repl_copy['link_flags'] = list(repl_copy['link_flags']) repl_copy['link_flags'].extend(trouble_libs) @@ -711,6 +715,7 @@ def bisect_libs_build_and_check(trouble_libs): sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) + memo[idx] = result_is_bad return result_is_bad print('Searching for bad intel static libraries:') @@ -729,6 +734,7 @@ def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. ''' + memo = {} # for memoization def bisect_build_and_check(trouble_src): ''' Compiles the compilation with trouble_src compiled with the trouble @@ -740,6 +746,9 @@ def bisect_build_and_check(trouble_src): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. ''' + idx = tuple(trouble_src) + if idx in memo: + return memo[idx] gt_src = list(set(sources).difference(trouble_src)) makefile = create_bisect_makefile(bisect_path, replacements, gt_src, trouble_src, dict()) @@ -768,6 +777,7 @@ def bisect_build_and_check(trouble_src): sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) + memo[idx] = result_is_bad return result_is_bad print('Searching for bad source files:') @@ -807,6 +817,7 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, .format(sym=sym) logging.info('%s', message) + memo = {} # for memoization def bisect_symbol_build_and_check(trouble_symbols): ''' Compiles the compilation with all files compiled under the ground truth @@ -823,6 +834,9 @@ def bisect_symbol_build_and_check(trouble_symbols): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. ''' + idx = tuple(trouble_symbols) + if idx in memo: + return memo[idx] gt_symbols = list(set(symbol_tuples).difference(trouble_symbols)) all_sources = list(sources) # copy the list of all source files symbol_sources = [x.src for x in trouble_symbols + gt_symbols] @@ -864,6 +878,7 @@ def bisect_symbol_build_and_check(trouble_symbols): sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) + memo[idx] = result_is_bad return result_is_bad # Check to see if -fPIC destroyed any chance of finding any bad symbols @@ -1368,6 +1383,5 @@ def main(arguments, prog=sys.argv[0]): _, _, _, _, ret = run_bisect(arguments, prog) return ret - if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index f9152542..b181fa57 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -208,49 +208,46 @@ Searching for bad symbols in: tests/file1.cpp Created /.../bisect-01/bisect-make-11.mk - compiling and running - bad Created /.../bisect-01/bisect-make-12.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-13.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-13.mk - compiling and running - good Created /.../bisect-01/bisect-make-14.mk - compiling and running - good - Created /.../bisect-01/bisect-make-15.mk - compiling and running - good - Created /.../bisect-01/bisect-make-16.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-15.mk - compiling and running - bad Found bad symbol on line 92 -- file1_func2_PROBLEM() + Created /.../bisect-01/bisect-make-16.mk - compiling and running - bad Created /.../bisect-01/bisect-make-17.mk - compiling and running - bad Created /.../bisect-01/bisect-make-18.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-19.mk - compiling and running - bad Found bad symbol on line 100 -- file1_func3_PROBLEM() + Created /.../bisect-01/bisect-make-19.mk - compiling and running - bad Created /.../bisect-01/bisect-make-20.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-21.mk - compiling and running - bad Found bad symbol on line 108 -- file1_func4_PROBLEM() + Created /.../bisect-01/bisect-make-21.mk - compiling and running - good Created /.../bisect-01/bisect-make-22.mk - compiling and running - good - Created /.../bisect-01/bisect-make-23.mk - compiling and running - good bad symbols in tests/file1.cpp: line 92 -- file1_func2_PROBLEM() line 100 -- file1_func3_PROBLEM() line 108 -- file1_func4_PROBLEM() Searching for bad symbols in: tests/file3.cpp - Created /.../bisect-01/bisect-make-24.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-23.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-24.mk - compiling and running - good Created /.../bisect-01/bisect-make-25.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-26.mk - compiling and running - good + Created /.../bisect-01/bisect-make-26.mk - compiling and running - bad + Found bad symbol on line 92 -- file3_func2_PROBLEM() Created /.../bisect-01/bisect-make-27.mk - compiling and running - bad Created /.../bisect-01/bisect-make-28.mk - compiling and running - bad - Found bad symbol on line 92 -- file3_func2_PROBLEM() - Created /.../bisect-01/bisect-make-29.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-30.mk - compiling and running - bad Found bad symbol on line 103 -- file3_func5_PROBLEM() - Created /.../bisect-01/bisect-make-31.mk - compiling and running - good - Created /.../bisect-01/bisect-make-32.mk - compiling and running - good + Created /.../bisect-01/bisect-make-29.mk - compiling and running - good + Created /.../bisect-01/bisect-make-30.mk - compiling and running - good bad symbols in tests/file3.cpp: line 92 -- file3_func2_PROBLEM() line 103 -- file3_func5_PROBLEM() Searching for bad symbols in: tests/file2.cpp + Created /.../bisect-01/bisect-make-31.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-32.mk - compiling and running - good Created /.../bisect-01/bisect-make-33.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-34.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-35.mk - compiling and running - good - Created /.../bisect-01/bisect-make-36.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-37.mk - compiling and running - good - Created /.../bisect-01/bisect-make-38.mk - compiling and running - bad + Created /.../bisect-01/bisect-make-34.mk - compiling and running - good + Created /.../bisect-01/bisect-make-35.mk - compiling and running - bad Found bad symbol on line 91 -- file2_func1_PROBLEM() - Created /.../bisect-01/bisect-make-39.mk - compiling and running - good - Created /.../bisect-01/bisect-make-40.mk - compiling and running - good + Created /.../bisect-01/bisect-make-36.mk - compiling and running - good + Created /.../bisect-01/bisect-make-37.mk - compiling and running - good bad symbols in tests/file2.cpp: line 91 -- file2_func1_PROBLEM() All bad symbols: From 7c55391cbde8b42a4ffeddc645b3e93df3b68e8a Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 21 Jul 2018 22:40:13 -0600 Subject: [PATCH 033/196] bisect: memoize in a more systematic way --- scripts/flitcli/flit_bisect.py | 66 +++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 20 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 43cf03b5..c0953800 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -412,6 +412,41 @@ def extract_symbols(file_or_filelist, objdir): return symbol_tuples +def memoize_strlist_func(func): + ''' + Memoize a function that takes a list of strings and returns a value. This + function returns the memoized version. It is expected that the list of + strings passed in will be in the same order. This memoization will not + work if for instance the input is first shuffled. + + >>> def to_memoize(strlist): + ... print(strlist) + ... return strlist[0] + >>> memoized = memoize_strlist_func(to_memoize) + >>> memoized([1, 2, 3]) + [1, 2, 3] + 1 + >>> memoized([1, 2, 3]) + 1 + >>> memoized([3, 2]) + [3, 2] + 3 + >>> memoized([1, 2, 3]) + 1 + >>> memoized([3, 2]) + 3 + ''' + memo = {} + def memoized_func(strlist): + 'func but memoized' + idx = tuple(strlist) + if idx in memo: + return memo[idx] + value = func(strlist) + memo[idx] = value + return value + return memoized_func + def bisect_search(is_bad, elements, found_callback=None): ''' Performs the bisect search, attempting to minimize the bad list. We could @@ -669,7 +704,6 @@ def search_for_linker_problems(args, bisect_path, replacements, sources, libs): the libraries included, and checks to see if there are reproducibility problems. ''' - memo = {} # for memoization def bisect_libs_build_and_check(trouble_libs): ''' Compiles all source files under the ground truth compilation and @@ -682,9 +716,6 @@ def bisect_libs_build_and_check(trouble_libs): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground-truth compilation. ''' - idx = tuple(trouble_libs) - if idx in memo: - return memo[idx] repl_copy = dict(replacements) repl_copy['link_flags'] = list(repl_copy['link_flags']) repl_copy['link_flags'].extend(trouble_libs) @@ -715,18 +746,19 @@ def bisect_libs_build_and_check(trouble_libs): sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) - memo[idx] = result_is_bad return result_is_bad + memoized_checker = memoize_strlist_func(bisect_libs_build_and_check) + print('Searching for bad intel static libraries:') logging.info('Searching for bad static libraries included by intel linker:') #bas_library_msg = ' Found bad library {}' #bad_library_callback = lambda filename : \ # util.printlog(bad_library_msg.format(filename)) - #bad_libs = bisect_search(bisect_libs_build_and_check, libs, + #bad_libs = bisect_search(memoized_checker, libs, # found_callback=bad_library_callback) #return bad_libs - if bisect_libs_build_and_check(libs): + if memoized_checker(libs): return libs return [] @@ -734,7 +766,6 @@ def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. ''' - memo = {} # for memoization def bisect_build_and_check(trouble_src): ''' Compiles the compilation with trouble_src compiled with the trouble @@ -746,9 +777,6 @@ def bisect_build_and_check(trouble_src): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. ''' - idx = tuple(trouble_src) - if idx in memo: - return memo[idx] gt_src = list(set(sources).difference(trouble_src)) makefile = create_bisect_makefile(bisect_path, replacements, gt_src, trouble_src, dict()) @@ -777,9 +805,10 @@ def bisect_build_and_check(trouble_src): sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) - memo[idx] = result_is_bad return result_is_bad + memoized_checker = memoize_strlist_func(bisect_build_and_check) + print('Searching for bad source files:') logging.info('Searching for bad source files under the trouble' ' compilation') @@ -787,7 +816,7 @@ def bisect_build_and_check(trouble_src): bad_source_msg = ' Found bad source file {}' bad_source_callback = lambda filename : \ util.printlog(bad_source_msg.format(filename)) - bad_sources = bisect_search(bisect_build_and_check, sources, + bad_sources = bisect_search(memoized_checker, sources, found_callback=bad_source_callback) return bad_sources @@ -817,7 +846,6 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, .format(sym=sym) logging.info('%s', message) - memo = {} # for memoization def bisect_symbol_build_and_check(trouble_symbols): ''' Compiles the compilation with all files compiled under the ground truth @@ -834,9 +862,6 @@ def bisect_symbol_build_and_check(trouble_symbols): @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. ''' - idx = tuple(trouble_symbols) - if idx in memo: - return memo[idx] gt_symbols = list(set(symbol_tuples).difference(trouble_symbols)) all_sources = list(sources) # copy the list of all source files symbol_sources = [x.src for x in trouble_symbols + gt_symbols] @@ -878,11 +903,12 @@ def bisect_symbol_build_and_check(trouble_symbols): sys.stdout.write(' - {0}\n'.format(result_str)) logging.info('Result was %s', result_str) - memo[idx] = result_is_bad return result_is_bad + memoized_checker = memoize_strlist_func(bisect_symbol_build_and_check) + # Check to see if -fPIC destroyed any chance of finding any bad symbols - if not bisect_symbol_build_and_check(symbol_tuples): + if not memoized_checker(symbol_tuples): message_1 = ' Warning: -fPIC compilation destroyed the optimization' message_2 = ' Cannot find any trouble symbols' print(message_1) @@ -895,7 +921,7 @@ def bisect_symbol_build_and_check(trouble_symbols): ' Found bad symbol on line {sym.lineno} -- {sym.demangled}' bad_symbol_callback = lambda sym : \ util.printlog(bad_symbol_msg.format(sym=sym)) - bad_symbols = bisect_search(bisect_symbol_build_and_check, symbol_tuples, + bad_symbols = bisect_search(memoized_checker, symbol_tuples, found_callback=bad_symbol_callback) return bad_symbols From 70f6e5856f765aaa7429488590d5659e669a9c0e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 27 Jul 2018 12:38:52 -0600 Subject: [PATCH 034/196] Add image for bisect search from Ian --- images/bisect-search.pdf | Bin 0 -> 12316 bytes images/bisect-search.svg | 1452 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 1452 insertions(+) create mode 100644 images/bisect-search.pdf create mode 100644 images/bisect-search.svg diff --git a/images/bisect-search.pdf b/images/bisect-search.pdf new file mode 100644 index 0000000000000000000000000000000000000000..cfb2a179debe6d2e8dbe80ef1dda8260c35bef3b GIT binary patch literal 12316 zcmd6NbzGEN*R~?vAkxAp-7^C-Ln95+-QC@dAfR+e2}nvK(jh1vqm;Cibg6W=zB70{ z$8*l}eDCl3{`%&Ixo5APYwdlndtdun49XHx93V~zHbdQ3`2{vN00?k0wZ#?`1aQe) zI9j<|19%W3RcrtNz$Im4?{49WxZ9h!TS!=#Ihk8v3kzerxw~4JIAD8cbiYt=n&Bl3 z-8sMGRvT2;y9f(%ATZeERL%*j7bXGvDiiZ5nlhDb-I@O-*R2 zG8B#=!rm`2#fX6XG$0usN9Ro{wFh)Yg`d#a^!4Kgsqz$F-Vw=U*mBkl%ma@b0?KeiW~oRbA)% zd!Br#=bv>)%FqgIJTMEGm2I97K<^klY)Su2|716h^c!!SbwRehXpD62Qqch>jsG%{ znRvGO>tL%x%q&?LO*_eG78+=T?hB!in9KnyjmgH|$h}4sA$IEuJ1xwjcO64QPv5*4 zB-dW(A=O=EN>_A6qwxhltqPK@hUo75h;8IB)}Ye7{bq>MiQB$n4a~W9xANfSqFfTU z{;XKid6EDc+f{`Zc8KPzae{@TQYkr78vUFsy34U>q&F#XNn8_A>gu?=XctFSk$Rzkr$9CAVnYm^p^-x5ApX$|FA#%2XLwT zI9mX?lufKGuE(Nm;%b3t8uY6kmx6`4jft3(H$V>|0s_E1P+m@MD2xvb0Pz4}oIoHD z%)Tz9dSe{2@6jfGYeH|F=UZH454b_=H%gOX5j`v8ddc-C3z8Pq_KZ{d+_}^tpD`( zKz8%*O2MA%W$(@$pNYbc!Om^`@qYU@_& zz~{B^J|ZUvjdqzH9}Vrc>OSq97_>6oxOL-p(#>EicnDfI?IYz;sRoQ+@%YejG3MIsT+%9VFo8cm6gnFUPtD><#~`69c~=#vX8?>HsASUj24ldYt_5rY`H6G+Enhm8>uFkM@q_p!y#yKq0%Mbvc*xB6RQgp0e-92rye!h z2bq{{WIwXh6d@{LF{yTi$wbc`B3kWW(OIwwHSjX z{dV7YxiT@Q1`Fvv#rt9HvN!m$vN7oLPpKa!vum^ypJ_}>bXz}DIIdsocZ+%R!1v(D z@}e%f`JN?w|8R?^xjVbdW~*D((eLWr<)tFX((2+yFx8r;{`2)d2IEj?@(mmf6nsqW z%h+)uDd`WW?hR5>L-i9LH0i~Q&@UpO{&%H@_axnEfEhj6Fw`kOp*&C$pB80#YjD%QtNe?w!LlVe9obn*KR|@ zMPZyI#{_+s)+X;{+uJlZ`I@hzhWmKH<*tkDlc%4wHs~X1mTK(TTdeNSY#G%Sf759F zQ7?25mt`Dij*-8$g_aJZonuYD)YjAD$wTw{GD!>A#0lX!Jdyk^5i~zyZ0f%6o!c(h zTVfQ1uX+BgkSc8b-S=YJkG0-qMy7&`Vg!#2I<@EffsM){O`L?}-_I}e-shKXwI`ELyw>*^|(-cC?1rcK2>PJ z1WUD=W$H5<&urTEw>!@_6=N0l^1B%5%YbFTiptlO{O%43^xgTX!@-)hCYaM8Vn1UN zsXh=q|1c>d$xrQ}TCeJ-!m+~Ie2Ep&IsLV7ol7C6cl$o~ud2)VCRBfZefxv^r!b47 z4W-GYS9=158tU>!*`p0x7X(GkR}Y4(f(uHmw)eMuk4H};k9+vuB_=W{9naEOZ5-)$ z7hdh{h1FCSDw3yc;K>&2>Z+}yfBDp>+A)EpqP!`0gN(Zz_MfoVTJAsqfL{h1?&KdEl8lY2GSzbPl2Xuv@UwMe=?O-b6b}-021gTb1D}&tRU@ zQ-I~)e&S|~pH4U6G7teK&hzQNL$+e~ILaJ;OEm2!8&i92Exo#y0Y2$m|a3_erBbVGadc=dhMy*-EV{>xQ{k2+S2nopG zT?9aujEJm6AV5_2sCsTXo3gfOg~#1JgL8_Tnef@jJN1Vzw6y`0T?Fb>*w|i#5aJ|4 z1Dhu)SWQCQDrM7&K@2iS zsM5>d7);348I4xg*&C1sWD_MWeheSjHSe-G?3dl|KKq2^y=HW)7&{Ft8)HK>mrnGh4hd%2!oDQdccYc3|% zT8f)J{_&Au%KCxnT*n<(RCD~e^Q*{%oq_Y|mn-WSiAE6dc%`ad>{Rw+x0n=4DyJze z^a4f}0)Og7NM3?)J|DN4{?+bh7U7~-EZ8tx#u_Y0TAzI0s(u}8{`541ry#hUxwI{& zx`X~UEBlk)v7r_zsci4_N(QniLFkX%UFB#%09)aA9oM~st@VPj;}!=I8HTMsP+{K* zTa`o}+T8w;xB{d&K`K`IhiH#A7(8GO#)p*2d2Q z&+f*Tfq7wN*()nV-o(wLeoKIL?q40auDF5jWaRi|O?h_1b2=hh-;p;qrn&i~Fy&T|D8}=! z;|Ta8{H?LY7O0{H_U=Zj z55UL`6R4#e)#KEccy-QR1Dsb4>RZKbkt$J#Eunibwe+8q?i7=a?Np() zrs%EE__&Ft?B^sA^<$tUoRl8Vj_l}8$6=6I&0KA|UK}0sv$R~9&3=z~w_5h3g2oK@ zK+@wqdBBXVCnl9Ca|`+1XdcJv$H#?*+rUn%&Dx;sw-(RWn}gg_&Mwk)GNg;=D+5N_ z9Mc=}9=$Q0_DQ@lGxETo6ur1ibS!=Lt%fCRRcHv{V)@J@iAKtQn0#Y& zj38p%=fjbmixg?OINDm?)Yh<}~IgTAqUPL%;_RYQf(p+DELb^3@EGMp{|JHr!v_Q@%Vz4^} zv_0W>!hiV5$x_}bgdCiP_d+;?7^P&H&c%z6jQdF&rcteqYP;uT?(+ljA>%1C*kq$? zN-_mIu$M-nghhayiU))446uiqx;E-s=U=A1f!be^U;X+cp$^7&0ZeMv^~YV&Lro*z z>XHRMhO@q$*fDqB$r-?7@%+JHNTs}JnxxnhvHPyuJegt>pqvVvWpTZajs{?ru?V{U zi4r|qT$B0Rg=fTf!a(;?lgP&{SmO3_L|)w+QJlVO3S@44agQFxAN<*|iPPP|!MurD zbT)U0-@5H^cZlpo{IhiBj7sRs=il_OvgzIF$-goNzuJDwxAeVeNWfwxzM$eRz93Jl ztKY&)G`o5X6uu)I+L@7B?(sylrmZtAxSvO zwZ_Y#g#KtepNyGdX)Gv=3RMF3zMQ~(6{XE!$A-p4%V7TtuifQ$50LZWs~`$2wy!87Z*@7y&cA#J#dVx46nlH1{N?08(7ZD+JB-I` z{hr@}z+f{4_Ez8rF%m1kn5@vD#;;um1nq7`=edoUI=B_guc@JvN$80ruYzq?(Cxy{ z@cDi9n{D=!ZpaomEsVJw)i1ccj}KA{apvI<_U5sukH@wA2L5n-q2E}pOSbk^n;FEO zTJ|mc%e~-3@vCS7owug|Wuw-MXG{K^UZ0|S>)kJNTrb-VB((UtW%RspR`11mt=>y` z$3_$%@KA!h!O*=tu6SgHReR^rd68hgm3lshLX7*de7%t^J%*1P&4>g^fY(5P{DlvV z>5ig=m@4MbRTaxu7Ow*1IgvsP*UutF7+Cz%W^0)(UNajw^&-b-tr2nE$x}ut$vh&5 zw&G{-gu!`>#re4(RxL-FH?R6=(m>o$@X^xusBFvpRuR{+-uHp6%+UK=AIi-XBHrTV zc|TSv^ado^AJZ5;AI`~@9afeq?*Zd$nLEGSd7scb5D&)zfWhu@!lq~ z{)4EUVrWdmaIjzzL8D?xDxF@12pUFHltH$hmwqQLjs-REazZexg*WF~QU^29QE-Y+ zfrPv&@wkL|?(p*V;JIAhB(n`^HrL=fj+hoJ+qhM-)wp)#P0W|OL*AR6svben2TxS^ zC1q``9!A;j5P)>Lw;SXk%sZ&-Wm zu60qjZ_)RB1I%Bs3|6|Y6P{1q9Cjo*q}(w6t}23?4zfauZxg( zH^qfmu4!I=d2PpNn(XJKOJ&{m#K>~?tsBD~o4C&nSzbIk!rFV~9bIOesHwj?Iymna z$IB^9Le{K{yL$MMcR&DFx1Xig>ua7mr<4& zE1M!1k%c=5P%_XTjK#llQc><>toDCl^ch0?@L&qI7T5^nUnZXU0Ii~YRcCNSK7L#N zM`_AA&PK=g)$&Y%AL^z#qaySAVvd56YHQO5_CIRlo^FOC+@at5En z`S~1sm|BAxI+XN$gt<+Uv)uzqaXd^j)!$RC0jAye_Q@7hIquV1;RZg)V#ELO`qMa`W2 zFh7FFH6uGHMtyzgk|JTGMq>76J?_WO8fH1OoX||B7R7e2N?aznf}~rA$&umTmun{| zbX$qmdfEoLZ)36~!^3^~?R<9y&__?tj2-TAum$y0YP@t;iYZca@2anPqf@hwJJz9d z$?>r}Zqk*{aPD4QP_H5?ke1bEC+3{8Ae@7K?npOxhm+&k!Ia{u>PM}j(Yc*3)Wc~P z`4L?zL_ErRIg=4Z?e=_{gazmJxEU(%d%xCZc`B3Lp19!##IYPz!`cjOeik~eEGvL^ zrh&e@W4+3F#=X>-P!``3!p)1Knj_O9rJdOO0MeHJs>9;pLC%}^hFm^QT(3_QQkVEZ z5YDm_5qBZaaW#U*qfbw10;Q$5N%$g_%GQUEzCgzM=1vC#Z1!tv=ayZIyuZyz$9|di zF#nE8na=Z+=7l9*4a@OMU9}+bapiDVg94FoLa@cd$Y?TYW`YV z&G*Dxo@$FLhYlK2|9Et=b3!(~U8w*u%qUWeiSB%X<&&L8L<+YLb3)NHUV4eDn;cFSr4_Z(dRH4+X3_$fp6ebt; z7zeDDKmc!fMc?*m_@__BMKaaPCXZXP4{zp=>ho1RNo>+>4Kp78;Z&JGIXuuCE}P&J zAtveW2|Y8}A2%z0^pNi|uWLZl_R!uNrA=msO7DjJ7;LoW>=8I-5JlT2^9X-wO3?w5 zrZLU^g#LXC&4ZbjKj!JegQ=LrS^MwXvBo$1D@rSP%9&Z0&Q&(is<52S?9VH7^D4irhXeX;T94&1asvKn#gb<8S?FBIly%B0w|Dnc!lF zAFN9q97OGXwidi7Vh+$;$j;rp6|{qMnb&rLnpFZHE&6;}+otB|54){|Em*I={62Rt z6KGFzTHhvuDag7T-u4EShSXceIHWBEg}|CzdvWz<(03StYik?qWPJ}tu#|4G{~gxk zADC5f>*Qhu*3_W1urc1CwLlYegkp5N;T@q-oyjaGR|Q*_fxun=6f!UV-8=WslQloz z+qDRqL34Cl&byF}p`v3KeE7SvP1a9;bgi>dIp7`H17O7AN?J-w6?2oxrU zP4DsD7G`r6uS<3!)OP4*)m7Js*~qTiJL)-&#+#^H8nq+XFG4FX>tD7bSegbm?z3=J z^mjhYzDy#Uz|?PkMPS6?tU>FaFzLUq`C8j%?T(_p4cwKInXBv0lQC>A&WT;DpuXp} z{%LIml$=D`jFsv+70Y|wQD@62WL$8`r`q7DZn>t@)V8N6v~`OpIKrkKXDGCe-9BZf z%4{DUx=n-JP`?{4+;TY;2&$=D^gpI=GFo`u?M>?uiTaU5o7p+E?JEinx=8@roLReI zP%9Cy!onB}qj24wqSW09llaStH19WUM#DX=l(C5hyb)7p`Is4By0FZ|&rpLJEt}*P zP6f97o7x1nyu;dDc(@f8CTF(%?V0Cj%vRsbxJ2KP#-Y}Tp(}NH(l(RN6QIY2FB1MH zRy@0nI;b<0{}jlCf0wu;jNkc#F&pjD24;J^CN(`!Z=vm`qHyIMjKenvHx)OtE!M8K zQZ3*Cj+=Jf{d)a^Y6~2e{W7ovT(-jWDy0|kCsk%Ii2STfZMnFVIJyj3@aOuXSn%Z) z_xD%yKs`|rhTKZHq7@XkQQQL0{Dp*^bx4$p7uB|_6iU4n1)Nvgw`xwWD1kDFaAZ6s)6cH*|giXICwBWlD^KPp`TPr*02O859 z)ylsQ=8-4Ce;mw1AW+z^gK-e@i2EOh#-P8>!vE8$G2$HhPtMUGq0g}sKqz_QkJjf- zbVfu4Bd%62pyE1L9u2q=>S9|0#}vT%@yIHbIr(knInuwPt_P$z5H z@H@;t{}@tpf|TK?+$6`^4Tq%fo?uaPW?`p3Y_;_;9czvnf(-pn4L!4o>3-gXs=b>W z{NZ`6A7&@M_Lm$$p3tVYRe;GH*zV#se2&7ZutZ5?*lTg)6)B&gu?W1At#?DG(53zP z=B6hBM->G z>^r@YcgQ($-Kl7XhnFeDu^uJ8<@0T5eFwx)E!ZKex2{qD_k3PY(jOCw*i-&FpMNne zznBgrb0T5kX69<+?C#`xOVeMAUwc-mK6I*mT-W8U?6~l2Z|s{V0_#F5SSbM2TdaDZenj^ChBNq zZvg;a*AsO!L$WS>VBYH_a(u`%2bddjEf65Es~B1&fdn+3c#gh<0$IrX7fvMT~Eu# z+}+v@K{|1RkZjd|y8e64U!{4uf3FSYLs|qul);de`0L_DOwz9ul#d4hBKQAcn z-^(JUP=p%DG7uiV>pK(#0dPZp%Anlb05A-8{SSfhUEld&$TqnV^$?8Qb=y3MUl7Fl z;70Ih$ee5b46#I=G#qV^p$vd)PxSlTf&N1@1nB=94)Hso1%?56|3+wytJ|roPu!XF zYVostY!WK442%p9=3T-W76q_Q$1mW}YJiBQU*ty1yw)Vi(+-~2<}oEv8z9eq37;Oo#5p=ga7YG}tD7dSOkhSIVfs6KkF*#AskpYF8Kd&i7-6!1~3pu-}eTg&UWR z1c|I2ra1|h(Q_FBCS0Zw;pg2976)V;6!rc$iBLxu&v3M!)2q90#$P#BDRE}P-aEO) zh=}Jq-R7)O$DHAQ4sP#I$sUpHV~viP)(dvRjx}s(@WziX5pxbRHXF`}1UL6LJ&}>b zQDoQSudvTwy*>3xwEAI>1OxSu+*m-#N3q#Q!{-Lz`SJT>wuy>1OoIkg58;h=>*aV~ zmt(OnZ;7>E}n%4rRT7(i}**G{Z#CJSe96uc5@979EZ!Ep(s)&Fs zB}4Vx=;e;hrCp_b;g$XIy7sP4Zo!2G?-@6I6zpxV(T%(dShNKt-;Ivtlg*ZOPQ~(M zlx0ruj>Os&bWg{Zjy&YZR4mnDjr7Ib_4Fw6t0|VVd^>S>qxzYp;&$c;tiTCg`C5KU zJ+d^r({f_TG1@Tui{g@of9=L8R{dN^SPYf*^k%8Ejg$2@)^PmscfpmuSmCwQ7k621 zslJVWE*dj-|GTUm#t#w=ZD877Xn zk*5rAbL0=xpo!lY;LZaDcyCfYMvA^2o#QsE{E%@fU~krU8jm`3<+yt>7V_=!>qTA* z*O8gAD9XAhb;bA2cfRtLuYdD=8?H&6%a$OSa>}7DcTu8h>tYjSQ&%#=Bc2M=VB1P+ z)ZQ$cHY`(kB~Vya;OR^G)&^y3d|FZqXEwJk)kc@&1Tw3B|EQIvN_X{Akri=tZl}^! z7}PNyw!<~hd?Nqgm2E4`X~eciF!4B@YJgL&+8oPk^RcJcJIlF;9%G?9CRlUhua3;G z_#UB*2h83iQ7P-1qYyUZ9M+6H-hGWL4J#Xpsug$F;HvIVo-FE!q_=9e31wz|xm>N8 ziZ{%oS_(%m;jvf9(Ui-|Vq9kkE_kSZn?nknZ$aPILH(in~+fk#?1VlrZ_oJ+*x!+0Lj@)a$@=?-H7{y8kwTAMh8 zhr?PgZE|vouk1mb)>F}OI!q-A*euHRX&=`!2XZWq z%gN7v_0A(X`yZT4Re)6uJXP>wSsE3yeyVuZipR`Qp)v9_kM-f5_vV3$&G(rFr#a=D zuLgh2tP3#C;Ly$ACWqRdP_NkNbYV$&wmcH%nKeAc`%!VT@g>84RzcdvYUYLSN-uWc z4&(d*y5-0N)&lD@SMpjqYJ)gPZ;rHGKeiYjE1v+?`p?+gVMLDXo4mH>Ma>&W(7{`=MrRv@SEo)y`5k~Y6+ugp`kJDfbr1knde0WH{D>+sTJ)(on+daor7s^v`Y42#RG zJps5AMcK^^o3AAwfx5m+FvF$+UV|;=BEN+sDkcghawnjn)#ZylHn?515jd9n1;u-6 zYu$Afg=l!F<@g6{UVc3YPo7Ckz@bJQKmW``M4s@K2EjLq3RLGOdtkZ`-VuAbv|N*W zmnLz(b8($v8Q&@~!ZLW7C24UN`QTjS7~~>erXtHzk35fFlU;0{rqOyVsgkvEM>qTB zjvK^3P1x~t;-qDshEZHD3|RaSzy5?ZB0se!{rSefS~&l9FM zJf%z&dbU=j90QZpQWdkCDs?p~8>2A4%80!#c>6ajIJ~`>C=Fs(x#&_lz0k3&`I^kM znRX*zZ9}lwbAc(kE{<ixINs9V%~&=RHCGV5IYyxcelvWXAiJ^v*+>wz9sy=5x05(tl!zh*N_a72^xrW z;x1GKjj6*)ZY5GAc7Y?}VZ+Kk20&1IAtPm~ai=%D;RYQ2Szp6^(yMKPdqosxjP37F zNzD$Kizv4`iZ{t2y%C%7(B!R+=yn+@DPSn~cAsm>h1iE)9`)xqX%w2tHh|7Z6QOv= z5U*kl9}4j@@&ro_aeJ8>Q)kdblF_)o(KsM-={-r^oNIZ?V&Uy?KIJ+gm2dYiVvvs(rFC})C?#b z`Bq}Z**m+xbT~(bBrXz`#Zr@Ngzt5JtdxA097Du0H|(fQp@M#&f@q1fy|TghSez`6 z69ypd2wt_bWmaS5xz#m92?;!6bXfS&ne)Tr<_`~gf3$4kxflOotNVLU5g+u=pd!Q` z|hEmh;d_wpXcRwVT0vK}8PR!}T5CU9U39%;8cG|x?KGV;S)w5=z2mbiT zS*4cagA!wkJQcN}J@p>*jR%H3_s@Xsix=QcrOp>41Ru%48Ilu0lJA%2+FJ-8s6SSz=LHB(Gk%Y6fGZg{$R{s(g+P4owHK<=&o2$8zp zb^d#={MT0Y&)w}$_~{{|hzWhIc?ePs4e zjPe(J_|N7+R8aGALtqzKM@uK99gwkFsuor@2t}+r0fP_rfc<7JVuzz9?Bot8ni7o(oKm@jc0ug(8FdqPk5)2G} ziyiy5CXnO#Z`vZ|Khf9!rsgkT1K|2Kat@j6Vf@5-<|YWdhOiqF?SQT!+s|ma-@pL! z(f-?X{Pw8-93L`(?Ej%+~Ji&iq`6=tG3m%GJc#+Q!U{)5+C}%YXt83F->+?q#;$M}#T`erJ5kZI`Y((7QA0Ge|0^x=LECD}dAP@wK zII%%~0FHmifFLjgF{OW(0f9)5`F9xtT_a%D-(|c&1aSYm3=zu-{C6MRya> cSLF2?cXKy!b-$iz5QrDZht0qssU(H{KbZJSsQ>@~ literal 0 HcmV?d00001 diff --git a/images/bisect-search.svg b/images/bisect-search.svg new file mode 100644 index 00000000..cc641e97 --- /dev/null +++ b/images/bisect-search.svg @@ -0,0 +1,1452 @@ + + + +image/svg+xml= +Found second bad file +X +Mark passing obj, assume other half fails and split + +Mark passing obj, assume other half fails and split + +Split in half +X +Restart search using unmarked files +Found first bad file += +X +Mark passing obj, assume other half fails and split + +Split in half +X +Split in half +X +Check that the test fails + \ No newline at end of file From ec8e6d3374a44ce9fd73ab550e545ff0ef9bf9cb Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sun, 29 Jul 2018 10:48:48 -0600 Subject: [PATCH 035/196] Add some more badges to the top README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c37574f2..76d23011 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,9 @@ | master | [![Build Status](https://travis-ci.org/PRUNERS/FLiT.svg?branch=master)](https://travis-ci.org/PRUNERS/FLiT) | | devel | [![Build Status](https://travis-ci.org/PRUNERS/FLiT.svg?branch=devel)](https://travis-ci.org/PRUNERS/FLiT) | +![PyPI - License](https://img.shields.io/pypi/l/Django.svg) +![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg) + # FLiT [![FLiT Bird](/images/flit-small.png)](https://github.com/PRUNERS/FLiT "FLiT") From 898adb6821c5816d87622eff4afdf2e9776ab609 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 9 Aug 2018 20:14:01 -0600 Subject: [PATCH 036/196] bisect: always relay the score instead of just good and bad --- scripts/flitcli/flit_bisect.py | 203 +++++++++++++++++++-------------- 1 file changed, 116 insertions(+), 87 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index af7fb58f..80378535 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -533,12 +533,15 @@ def memoized_func(strlist): def bisect_biggest(score_func, elements, k=1): ''' Performs the bisect search, attempting to find the biggest offenders. This - is different from bisect_search() in that the function that is passed gives - a numerical score of badness of the selection of elements, whereas - bisect_search() takes in a function that merely returns True or False. + is different from bisect_search() in that this function only tries to + identify the top k offenders, not all of them. If k is less than or equal + to the total number of offenders, then bisect_biggest() is more expensive + than bisect_search(). - We want to not call score_func() very much. We assume the score_func() is - an expensive operation. + We do not want to call score_func() very much. We assume the score_func() is + is an expensive operation. We could go throught the list one at a time, + but that would cause us to potentially call score_func() more than + necessary. Note: The same assumption as bisect_search() is in place. That is that all bad elements are independent. This means if an element contributes to a @@ -564,7 +567,7 @@ def bisect_biggest(score_func, elements, k=1): >>> def score_func(x): ... print('scoring:', x) - ... return -2*min(x) + ... return -2*min(x) if x else 0 >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], 3) scoring: [1, 3, 4, 5, -1, 10, 0, -15, 3] @@ -609,61 +612,84 @@ def bisect_biggest(score_func, elements, k=1): push(elems[len(elems) // 2:]) return found_list -def bisect_search(is_bad, elements, found_callback=None): +def bisect_search(score_func, elements, found_callback=None): ''' - Performs the bisect search, attempting to minimize the bad list. We could - go through the list one at a time, but that would cause us to call is_bad() - more than necessary. Here we assume that calling is_bad() is expensive, so - we want to minimize calls to is_bad(). This function has - O(k*log(n))*O(is_bad) - where n is the size of the questionable_list and k is - the number of bad elements in questionable_list. + Performs the bisect search, attempting to find all elements contributing to + a positive score. This score_func() function is intended to identify when + there are "bad" elements by returning a positive score. This is different + from bisect_biggest() in that we find all offenders and can therefore do + some optimization that bisect_biggest() cannot do. + + We do not want to call score_func() very much. We assume the score_func() + is an expensive operation. We could go throught the list one at a time, + but that would cause us to potentially call score_func() more than + necessary. + + This function has complexity + O(k*log(n))*O(score_func) + where n is the size of the elements and k is the number of bad elements to + find. Note: A key assumption to this algorithm is that all bad elements are independent. That may not always be true, so there are redundant checks within the algorithm to verify that this assumption is not vialoated. If the assumption is found to be violated, then an AssertionError is raised. - @param is_bad: a function that takes one argument, the list of elements to - test if they are bad. The function then returns True if the given list - has a bad element + @param score_func: a function that takes one argument, the list of elements to + test if they are bad. The function then returns a positive value if + the given list has a bad element. If the given list does not have a + bad element, this can return zero or a negative value. + Note: this function must be able to handle empty lists. An empty list + should instantly return a non-positive value, as there cannot possibly + be a bad element passed to it. + It is expected that this function is memoized because it may be called + more than once on the same input during the execution of this + algorithm. @param elements: contains bad elements, but potentially good elements too @param found_callback: a callback function to be called on every found bad - element + element. Will be given two arguments, the element, and the score from + score_func(). - @return minimal bad list of all elements that cause is_bad() to return True + @return minimal bad list of all elements that cause score_func() to return + positive values, along with their scores, sorted descending by score. + [(elem, score), ...] Here's an example of finding all negative numbers in a list. Not very useful for this particular task, but it is demonstrative of how to use it. >>> call_count = 0 - >>> def is_bad(x): - ... global call_count - ... call_count += 1 - ... return min(x) < 0 if x else False - >>> x = bisect_search(is_bad, [1, 3, 4, 5, -1, 10, 0, -15, 3]) - >>> sorted(x) - [-15, -1] + >>> memo = {} + >>> def score_func(x): + ... idx = tuple(sorted(x)) + ... if idx not in memo: + ... global call_count + ... call_count += 1 + ... memo[idx] = -2*min(x) if x else 0 + ... return memo[idx] + >>> bisect_search(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3]) + [(-15, 30), (-1, 2)] as a rough performance metric, we want to be sure our call count remains - low for the is_bad() function. + low for the score_func() function. Note, we implemented memoization in + score_func(), so we are only counting unique calls and not duplicate calls + to score_func(). >>> call_count 9 Test out the found_callback() functionality. >>> s = set() - >>> y = bisect_search(is_bad, [-1, -2, -3, -4], found_callback=s.add) - >>> sorted(y) - [-4, -3, -2, -1] + >>> bisect_search(score_func, [-1, -2, -3, -4], + ... found_callback=lambda x, y: s.add(x)) + [(-4, 8), (-3, 6), (-2, 4), (-1, 2)] >>> sorted(s) [-4, -3, -2, -1] See what happens when it has a pair that only show up together and not - alone. Only if -6 and 5 are in the list, then is_bad returns true. - The assumption of this algorithm is that bad elements are independent, - so this should throw an exception. - >>> def is_bad(x): - ... return max(x) - min(x) > 10 - >>> bisect_search(is_bad, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) + alone. Only if -6 and 5 are in the list, then score_func() returns a + positive value. The assumption of this algorithm is that bad elements are + independent, so this should throw an exception. + >>> def score_func(x): + ... return max(x) - min(x) - 10 if x else 0 + >>> bisect_search(score_func, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) Traceback (most recent call last): ... AssertionError: Assumption that bad elements are independent was wrong @@ -671,50 +697,54 @@ def bisect_search(is_bad, elements, found_callback=None): Check that the found_callback is not called on false positives. Here I expect no output since no single element can be found. >>> try: - ... bisect_search(is_bad, [-6, 2, 3, -3, -1, 0, 0, -5, 5], + ... bisect_search(score_func, [-6, 2, 3, -3, -1, 0, 0, -5, 5], ... found_callback=print) ... except AssertionError: ... pass ''' + if not elements: + return [] + # copy the incoming list so that we don't modify it quest_list = list(elements) bad_list = [] - while len(quest_list) > 0 and is_bad(quest_list): - + while len(quest_list) > 0 and score_func(quest_list) > 0: + # find one bad element quest_copy = quest_list - last_result = False while len(quest_copy) > 1: - # split the questionable list into two lists half_1 = quest_copy[:len(quest_copy) // 2] - half_2 = quest_copy[len(quest_copy) // 2:] - last_result = is_bad(half_1) - if last_result: + if score_func(half_1) > 0: quest_copy = half_1 else: # optimization: mark half_1 as known, so that we don't need to # search it again quest_list = quest_list[len(half_1):] # update the local search - quest_copy = half_2 + quest_copy = quest_copy[len(half_1):] + # since we remove known good elements as we find them, the bad element + # will be at the beginning of quest_list. bad_element = quest_list.pop(0) # double check that we found a bad element before declaring it bad - if last_result or is_bad([bad_element]): - bad_list.append(bad_element) + score = score_func([bad_element]) + if score > 0: + bad_list.append((bad_element, score)) # inform caller that a bad element was found if found_callback != None: - found_callback(bad_element) + found_callback(bad_element, score) # Perform a sanity check. If we have found all of the bad items, then # compiling with all but these bad items will cause a good build. # This will fail if our hypothesis class is wrong - good_list = list(set(elements).difference(bad_list)) - assert not is_bad(good_list), \ + good_list = list(set(elements).difference(x[0] for x in bad_list)) + assert score_func(good_list) <= 0, \ 'Assumption that bad elements are independent was wrong' + bad_list.sort(key=lambda x: -x[1]) + return bad_list def parse_args(arguments, prog=sys.argv[0]): @@ -915,23 +945,27 @@ def bisect_libs_build_and_check(trouble_libs): resultfile = util.extract_make_var('BISECT_RESULT', makepath, args.directory)[0] resultpath = os.path.join(args.directory, resultfile) - result_is_bad = is_result_bad(resultpath) + result = get_comparison_result(resultpath) + result_str = str(result) - result_str = 'bad' if result_is_bad else 'good' - sys.stdout.write(' - {0}\n'.format(result_str)) + sys.stdout.write(' - score {0}\n'.format(result_str)) logging.info('Result was %s', result_str) - return result_is_bad + return result memoized_checker = memoize_strlist_func(bisect_libs_build_and_check) print('Searching for bad intel static libraries:') logging.info('Searching for bad static libraries included by intel linker:') - #bas_library_msg = ' Found bad library {}' - #bad_library_callback = lambda filename : \ - # util.printlog(bad_library_msg.format(filename)) - #bad_libs = bisect_search(memoized_checker, libs, - # found_callback=bad_library_callback) + #bas_library_msg = ' Found bad library {} (score {})' + #bad_library_callback = lambda filename, score: \ + # util.printlog(bad_library_msg.format(filename, score)) + #if args.biggest is None: + # bad_libs = bisect_search(memoized_checker, libs, + # found_callback=bad_library_callback) + #else: + # bad_libs = bisect_biggest(memoized_checker, libs, + # k=args.biggest) #return bad_libs if memoized_checker(libs): return libs @@ -974,14 +1008,10 @@ def bisect_build_and_check(trouble_src): resultfile = util.extract_make_var('BISECT_RESULT', makepath, args.directory)[0] resultpath = os.path.join(args.directory, resultfile) - if args.biggest is None: - result = is_result_bad(resultpath) - result_str = 'bad' if result else 'good' - else: - result = get_comparison_result(resultpath) - result_str = str(result) + result = get_comparison_result(resultpath) + result_str = str(result) - sys.stdout.write(' - {0}\n'.format(result_str)) + sys.stdout.write(' - score {0}\n'.format(result_str)) logging.info('Result was %s', result_str) return result @@ -991,9 +1021,9 @@ def bisect_build_and_check(trouble_src): print('Searching for bad source files:') logging.info('Searching for bad source files under the trouble' ' compilation') - bad_source_msg = ' Found bad source file {}' - bad_source_callback = lambda filename: \ - util.printlog(bad_source_msg.format(filename)) + bad_source_msg = ' Found bad source file {}: score {}' + bad_source_callback = lambda filename, score: \ + util.printlog(bad_source_msg.format(filename, score)) if args.biggest is None: bad_sources = bisect_search(memoized_checker, sources, found_callback=bad_source_callback) @@ -1079,14 +1109,10 @@ def bisect_symbol_build_and_check(trouble_symbols): resultfile = util.extract_make_var('BISECT_RESULT', makepath, args.directory)[0] resultpath = os.path.join(args.directory, resultfile) - if args.biggest is None: - result = is_result_bad(resultpath) - result_str = 'bad' if result else 'good' - else: - result = get_comparison_result(resultpath) - result_str = str(result) + result = get_comparison_result(resultpath) + result_str = str(result) - sys.stdout.write(' - {0}\n'.format(result_str)) + sys.stdout.write(' - score {0}\n'.format(result_str)) logging.info('Result was %s', result_str) return result @@ -1104,9 +1130,10 @@ def bisect_symbol_build_and_check(trouble_symbols): return [] bad_symbol_msg = \ - ' Found bad symbol on line {sym.lineno} -- {sym.demangled}' - bad_symbol_callback = lambda sym: \ - util.printlog(bad_symbol_msg.format(sym=sym)) + ' Found bad symbol on line {sym.lineno} -- ' \ + '{sym.demangled} (score {score})' + bad_symbol_callback = lambda sym, score: \ + util.printlog(bad_symbol_msg.format(sym=sym, score=score)) if args.biggest is None: bad_symbols = bisect_search(memoized_checker, symbol_tuples, @@ -1317,7 +1344,7 @@ def run_bisect(arguments, prog=sys.argv[0]): print(' bad sources:') logging.info('BAD SOURCES:') for src in bad_sources: - print(' ' + src) + print(' {} (score {})'.format(src[0], src[1])) logging.info(' %s', src) if len(bad_sources) == 0: print(' None') @@ -1328,7 +1355,7 @@ def run_bisect(arguments, prog=sys.argv[0]): # This will allow us to maybe find some symbols where crashes before would # cause problems and no symbols would be identified bad_symbols = [] - for bad_source in bad_sources: + for bad_source, _ in bad_sources: try: file_bad_symbols = search_for_symbol_problems( args, bisect_path, replacements, sources, bad_source) @@ -1343,17 +1370,19 @@ def run_bisect(arguments, prog=sys.argv[0]): if len(file_bad_symbols) > 0: print(' bad symbols in {}:'.format(bad_source)) logging.info(' bad symbols in %s:', bad_source) - for sym in file_bad_symbols: - message = ' line {sym.lineno} -- {sym.demangled}' \ - .format(sym=sym) + for sym, score in file_bad_symbols: + message = \ + ' line {sym.lineno} -- {sym.demangled} (score {score})' \ + .format(sym=sym, score=score) print(message) logging.info('%s', message) print('All bad symbols:') logging.info('BAD SYMBOLS:') - for sym in bad_symbols: - message = ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' \ - .format(sym=sym) + for sym, score in bad_symbols: + message = \ + ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled} ' \ + '(score {score})'.format(sym=sym, score=score) print(message) logging.info('%s', message) if len(bad_symbols) == 0: From 32321670aed2299a98b3633e830a615cc2d63256 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 9 Aug 2018 20:22:02 -0600 Subject: [PATCH 037/196] bisect: sort results by score, then element --- scripts/flitcli/flit_bisect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 80378535..e861b20a 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -743,6 +743,7 @@ def bisect_search(score_func, elements, found_callback=None): assert score_func(good_list) <= 0, \ 'Assumption that bad elements are independent was wrong' + # sort descending by score bad_list.sort(key=lambda x: -x[1]) return bad_list @@ -1377,6 +1378,7 @@ def run_bisect(arguments, prog=sys.argv[0]): print(message) logging.info('%s', message) + bad_symbols.sort(key=lambda x: (-x[1], x[0])) print('All bad symbols:') logging.info('BAD SYMBOLS:') for sym, score in bad_symbols: From 24b0a6bf10a313b96eee432de927822704f08a60 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 9 Aug 2018 20:32:43 -0600 Subject: [PATCH 038/196] bisect-biggest: implement found_callback to display progress --- scripts/flitcli/flit_bisect.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index e861b20a..cdc8648b 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -530,7 +530,7 @@ def memoized_func(strlist): return value return memoized_func -def bisect_biggest(score_func, elements, k=1): +def bisect_biggest(score_func, elements, found_callback=None, k=1): ''' Performs the bisect search, attempting to find the biggest offenders. This is different from bisect_search() in that this function only tries to @@ -558,6 +558,9 @@ def bisect_biggest(score_func, elements, k=1): negative value. @param elements: the elements to search over. Subsets of this list will be given to score_func(). + @param found_callback: a callback function to be called on every found bad + element. Will be given two arguments, the element, and the score from + score_func(). @param k: number of biggest elements to return. The default is to return the one biggest offender. If there are less than k elements that return positive scores, then only the found offenders will be returned. @@ -569,7 +572,7 @@ def bisect_biggest(score_func, elements, k=1): ... print('scoring:', x) ... return -2*min(x) if x else 0 - >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], 3) + >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], k=3) scoring: [1, 3, 4, 5, -1, 10, 0, -15, 3] scoring: [1, 3, 4, 5] scoring: [-1, 10, 0, -15, 3] @@ -583,7 +586,8 @@ def bisect_biggest(score_func, elements, k=1): scoring: [10] [(-15, 30), (-1, 2)] - >>> bisect_biggest(score_func, [-1, -2, -3, -4, -5], 3) + >>> bisect_biggest(score_func, [-1, -2, -3, -4, -5], k=3, + ... found_callback=print) scoring: [-1, -2, -3, -4, -5] scoring: [-1, -2] scoring: [-3, -4, -5] @@ -591,6 +595,9 @@ def bisect_biggest(score_func, elements, k=1): scoring: [-4, -5] scoring: [-4] scoring: [-5] + -5 10 + -4 8 + -3 6 [(-5, 10), (-4, 8), (-3, 6)] >>> bisect_biggest(score_func, []) @@ -607,6 +614,8 @@ def bisect_biggest(score_func, elements, k=1): score, elems = pop() if len(elems) == 1: found_list.append((elems[0], -score)) + if found_callback is not None: + found_callback(elems[0], -score) else: push(elems[:len(elems) // 2]) push(elems[len(elems) // 2:]) @@ -966,6 +975,7 @@ def bisect_libs_build_and_check(trouble_libs): # found_callback=bad_library_callback) #else: # bad_libs = bisect_biggest(memoized_checker, libs, + # found_callback=bad_library_callback, # k=args.biggest) #return bad_libs if memoized_checker(libs): @@ -1030,6 +1040,7 @@ def bisect_build_and_check(trouble_src): found_callback=bad_source_callback) else: bad_sources = bisect_biggest(memoized_checker, sources, + found_callback=bad_source_callback, k=args.biggest) return bad_sources @@ -1141,7 +1152,9 @@ def bisect_symbol_build_and_check(trouble_symbols): found_callback=bad_symbol_callback) else: bad_symbols = bisect_biggest(memoized_checker, - symbol_tuples, k=args.biggest) + symbol_tuples, + found_callback=bad_symbol_callback, + k=args.biggest) return bad_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, From 84f55c75d9e912a0daa4e9db1d22197502439ee8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 9 Aug 2018 20:57:12 -0600 Subject: [PATCH 039/196] bisect: fix output and logging --- scripts/flitcli/flit_bisect.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index cdc8648b..193cab81 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1355,8 +1355,15 @@ def run_bisect(arguments, prog=sys.argv[0]): logging.exception('Failed to search for bad sources.') return bisect_num, bad_libs, None, None, 1 - print(' bad sources:') - logging.info('BAD SOURCES:') + if args.biggest is None: + print(' all variability inducing source file(s):') + logging.info('ALL VARIABILITY INCUDING SOURCE FILE(S):') + else: + print(' {} highest variability source file{}:'.format( + args.biggest, 's' if args.biggest > 1 else '')) + logging.info('%d HIGHEST VARIABILITY SOURCE FILE%s:', + args.biggest, 'S' if args.biggest > 1 else '') + for src in bad_sources: print(' {} (score {})'.format(src[0], src[1])) logging.info(' %s', src) @@ -1382,8 +1389,13 @@ def run_bisect(arguments, prog=sys.argv[0]): bad_source) bad_symbols.extend(file_bad_symbols) if len(file_bad_symbols) > 0: - print(' bad symbols in {}:'.format(bad_source)) - logging.info(' bad symbols in %s:', bad_source) + if args.biggest is None: + message = ' All bad symbols in {}:'.format(bad_source) + else: + message = ' {} bad symbol{} in {}:'.format( + args.biggest, 's' if args.biggest > 1 else '', bad_source) + print(message) + logging.info(message) for sym, score in file_bad_symbols: message = \ ' line {sym.lineno} -- {sym.demangled} (score {score})' \ @@ -1392,8 +1404,17 @@ def run_bisect(arguments, prog=sys.argv[0]): logging.info('%s', message) bad_symbols.sort(key=lambda x: (-x[1], x[0])) - print('All bad symbols:') - logging.info('BAD SYMBOLS:') + + if args.biggest is None: + print('All variability inducing symbols:') + logging.info('ALL VARIABILITY INCUDING SYMBOLS:') + else: + print('{} highest variability symbol{} from each found source file:' + .format(args.biggest, 's' if args.biggest > 1 else '')) + logging.info( + '%d HIGHEST VARIABILITY INDUCING SYMBOL%s FROM EACH FOUND SOURCE FILE:', + args.biggest, 'S' if args.biggest > 1 else '') + for sym, score in bad_symbols: message = \ ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled} ' \ From 9becc657fa39d08dc38c260d5e050ed84c04b947 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 02:25:01 -0600 Subject: [PATCH 040/196] bisect: get the bisect unit tests passing again --- tests/flit_bisect/tst_bisect.py | 198 ++++++++++++++++---------------- 1 file changed, 101 insertions(+), 97 deletions(-) diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index b181fa57..a747d641 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -124,14 +124,16 @@ 'Updating ground-truth results - ground-truth.csv - done' Verify that all source files were found and output during the search ->>> sorted([x.split()[-1] for x in bisect_out +>>> sorted([x.split(':')[0].split()[-1] for x in bisect_out ... if x.startswith(' Found bad source file')]) ['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] Verify that the three bad sources were output in the "bad sources:" section ->>> idx = bisect_out.index(' bad sources:') ->>> sorted(bisect_out[idx+1:idx+4]) -[' tests/file1.cpp', ' tests/file2.cpp', ' tests/file3.cpp'] +>>> idx = bisect_out.index(' all variability inducing source file(s):') +>>> print('\\n'.join(bisect_out[idx+1:idx+4])) + tests/file1.cpp (score 10.0) + tests/file2.cpp (score 7.0) + tests/file3.cpp (score 4.0) >>> bisect_out[idx+4].startswith('Searching for bad symbols in:') True @@ -142,123 +144,125 @@ Verify all functions were identified during the symbol searches >>> print('\\n'.join( -... sorted([' '.join(x.split()[-4:]) for x in bisect_out +... sorted([' '.join(x.split()[-6:]) for x in bisect_out ... if x.startswith(' Found bad symbol on line')]))) -line 100 -- file1_func3_PROBLEM() -line 103 -- file3_func5_PROBLEM() -line 108 -- file1_func4_PROBLEM() -line 91 -- file2_func1_PROBLEM() -line 92 -- file1_func2_PROBLEM() -line 92 -- file3_func2_PROBLEM() +line 100 -- file1_func3_PROBLEM() (score 2.0) +line 103 -- file3_func5_PROBLEM() (score 3.0) +line 108 -- file1_func4_PROBLEM() (score 3.0) +line 91 -- file2_func1_PROBLEM() (score 7.0) +line 92 -- file1_func2_PROBLEM() (score 5.0) +line 92 -- file3_func2_PROBLEM() (score 1.0) Verify the bad symbols section for file1.cpp ->>> idx = bisect_out.index(' bad symbols in tests/file1.cpp:') ->>> print('\\n'.join(sorted(bisect_out[idx+1:idx+4]))) - line 100 -- file1_func3_PROBLEM() - line 108 -- file1_func4_PROBLEM() - line 92 -- file1_func2_PROBLEM() +>>> idx = bisect_out.index(' All bad symbols in tests/file1.cpp:') +>>> print('\\n'.join(bisect_out[idx+1:idx+4])) + line 92 -- file1_func2_PROBLEM() (score 5.0) + line 108 -- file1_func4_PROBLEM() (score 3.0) + line 100 -- file1_func3_PROBLEM() (score 2.0) >>> bisect_out[idx+4].startswith(' ') False Verify the bad symbols section for file2.cpp ->>> idx = bisect_out.index(' bad symbols in tests/file2.cpp:') +>>> idx = bisect_out.index(' All bad symbols in tests/file2.cpp:') >>> bisect_out[idx+1] -' line 91 -- file2_func1_PROBLEM()' +' line 91 -- file2_func1_PROBLEM() (score 7.0)' >>> bisect_out[idx+2].startswith(' ') False Verify the bad symbols section for file3.cpp ->>> idx = bisect_out.index(' bad symbols in tests/file3.cpp:') ->>> print('\\n'.join(sorted(bisect_out[idx+1:idx+3]))) - line 103 -- file3_func5_PROBLEM() - line 92 -- file3_func2_PROBLEM() +>>> idx = bisect_out.index(' All bad symbols in tests/file3.cpp:') +>>> print('\\n'.join(bisect_out[idx+1:idx+3])) + line 103 -- file3_func5_PROBLEM() (score 3.0) + line 92 -- file3_func2_PROBLEM() (score 1.0) >>> bisect_out[idx+3].startswith(' ') False Test the All bad symbols section of the output ->>> idx = bisect_out.index('All bad symbols:') ->>> print('\\n'.join(sorted(bisect_out[idx+1:]))) # doctest:+ELLIPSIS - /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() - /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() - /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() - /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() - /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() - /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() +>>> idx = bisect_out.index('All variability inducing symbols:') +>>> print('\\n'.join(bisect_out[idx+1:])) # doctest:+ELLIPSIS + /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() (score 7.0) + /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) + /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) + /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) + /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) + /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) Example output to be expected: +Updating ground-truth results - ground-truth.csv - done Searching for bad source files: - Created /.../bisect-01/bisect-make-01.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-02.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-03.mk - compiling and running - good - Created /.../bisect-01/bisect-make-04.mk - compiling and running - bad - Found bad source file tests/file1.cpp - Created /.../bisect-01/bisect-make-05.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-06.mk - compiling and running - bad - Found bad source file tests/file3.cpp - Created /.../bisect-01/bisect-make-07.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-08.mk - compiling and running - good - Created /.../bisect-01/bisect-make-09.mk - compiling and running - bad - Found bad source file tests/file2.cpp - Created /.../bisect-01/bisect-make-10.mk - compiling and running - good - bad sources: - tests/file1.cpp - tests/file3.cpp - tests/file2.cpp + Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 + Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 10.0 + Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 10.0 + Found bad source file tests/file1.cpp: score 10.0 + Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 11.0 + Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 4.0 + Found bad source file tests/file3.cpp: score 4.0 + Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-08.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-09.mk - compiling and running - score 7.0 + Found bad source file tests/file2.cpp: score 7.0 + Created /.../bisect-01/bisect-make-10.mk - compiling and running - score 0.0 + all variability inducing source file(s): + tests/file1.cpp (score 10.0) + tests/file2.cpp (score 7.0) + tests/file3.cpp (score 4.0) Searching for bad symbols in: tests/file1.cpp - Created /.../bisect-01/bisect-make-11.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-12.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-13.mk - compiling and running - good - Created /.../bisect-01/bisect-make-14.mk - compiling and running - good - Created /.../bisect-01/bisect-make-15.mk - compiling and running - bad - Found bad symbol on line 92 -- file1_func2_PROBLEM() - Created /.../bisect-01/bisect-make-16.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-17.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-18.mk - compiling and running - bad - Found bad symbol on line 100 -- file1_func3_PROBLEM() - Created /.../bisect-01/bisect-make-19.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-20.mk - compiling and running - bad - Found bad symbol on line 108 -- file1_func4_PROBLEM() - Created /.../bisect-01/bisect-make-21.mk - compiling and running - good - Created /.../bisect-01/bisect-make-22.mk - compiling and running - good - bad symbols in tests/file1.cpp: - line 92 -- file1_func2_PROBLEM() - line 100 -- file1_func3_PROBLEM() - line 108 -- file1_func4_PROBLEM() -Searching for bad symbols in: tests/file3.cpp - Created /.../bisect-01/bisect-make-23.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-24.mk - compiling and running - good - Created /.../bisect-01/bisect-make-25.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-26.mk - compiling and running - bad - Found bad symbol on line 92 -- file3_func2_PROBLEM() - Created /.../bisect-01/bisect-make-27.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-28.mk - compiling and running - bad - Found bad symbol on line 103 -- file3_func5_PROBLEM() - Created /.../bisect-01/bisect-make-29.mk - compiling and running - good - Created /.../bisect-01/bisect-make-30.mk - compiling and running - good - bad symbols in tests/file3.cpp: - line 92 -- file3_func2_PROBLEM() - line 103 -- file3_func5_PROBLEM() + Created /.../bisect-01/bisect-make-11.mk - compiling and running - score 10.0 + Created /.../bisect-01/bisect-make-12.mk - compiling and running - score 5.0 + Created /.../bisect-01/bisect-make-13.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-14.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-15.mk - compiling and running - score 5.0 + Found bad symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) + Created /.../bisect-01/bisect-make-16.mk - compiling and running - score 5.0 + Created /.../bisect-01/bisect-make-17.mk - compiling and running - score 5.0 + Created /.../bisect-01/bisect-make-18.mk - compiling and running - score 2.0 + Found bad symbol on line 100 -- file1_func3_PROBLEM() (score 2.0) + Created /.../bisect-01/bisect-make-19.mk - compiling and running - score 3.0 + Created /.../bisect-01/bisect-make-20.mk - compiling and running - score 3.0 + Found bad symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) + Created /.../bisect-01/bisect-make-21.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-22.mk - compiling and running - score 0.0 + All bad symbols in tests/file1.cpp: + line 92 -- file1_func2_PROBLEM() (score 5.0) + line 108 -- file1_func4_PROBLEM() (score 3.0) + line 100 -- file1_func3_PROBLEM() (score 2.0) Searching for bad symbols in: tests/file2.cpp - Created /.../bisect-01/bisect-make-31.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-32.mk - compiling and running - good - Created /.../bisect-01/bisect-make-33.mk - compiling and running - bad - Created /.../bisect-01/bisect-make-34.mk - compiling and running - good - Created /.../bisect-01/bisect-make-35.mk - compiling and running - bad - Found bad symbol on line 91 -- file2_func1_PROBLEM() - Created /.../bisect-01/bisect-make-36.mk - compiling and running - good - Created /.../bisect-01/bisect-make-37.mk - compiling and running - good - bad symbols in tests/file2.cpp: - line 91 -- file2_func1_PROBLEM() -All bad symbols: - /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() - /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() - /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() - /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() - /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() - /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() + Created /.../bisect-01/bisect-make-23.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-24.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-25.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-26.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-27.mk - compiling and running - score 7.0 + Found bad symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Created /.../bisect-01/bisect-make-28.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-29.mk - compiling and running - score 0.0 + All bad symbols in tests/file2.cpp: + line 91 -- file2_func1_PROBLEM() (score 7.0) +Searching for bad symbols in: tests/file3.cpp + Created /.../bisect-01/bisect-make-30.mk - compiling and running - score 4.0 + Created /.../bisect-01/bisect-make-31.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-32.mk - compiling and running - score 4.0 + Created /.../bisect-01/bisect-make-33.mk - compiling and running - score 1.0 + Found bad symbol on line 92 -- file3_func2_PROBLEM() (score 1.0) + Created /.../bisect-01/bisect-make-34.mk - compiling and running - score 3.0 + Created /.../bisect-01/bisect-make-35.mk - compiling and running - score 3.0 + Found bad symbol on line 103 -- file3_func5_PROBLEM() (score 3.0) + Created /.../bisect-01/bisect-make-36.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-37.mk - compiling and running - score 0.0 + All bad symbols in tests/file3.cpp: + line 103 -- file3_func5_PROBLEM() (score 3.0) + line 92 -- file3_func2_PROBLEM() (score 1.0) +All variability inducing symbols: + /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() (score 7.0) + /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) + /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) + /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) + /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) + /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) TODO: test the log_contents variable +TODO: test the -k flag ''' # Test setup before the docstring is run. From fce5bc70d33885961f35c7b70d6f7145b9bb9a32 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 02:32:32 -0600 Subject: [PATCH 041/196] bisect: put in a TODO comment to work on soon. --- scripts/flitcli/flit_bisect.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 193cab81..5b9eb370 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1029,6 +1029,16 @@ def bisect_build_and_check(trouble_src): memoized_checker = memoize_strlist_func(bisect_build_and_check) + # TODO: make a callback that immediately starts the symbol search on the + # TODO- first found file. Do this for when args.biggest is defined. + # TODO- What we want here is that the first file found triggers a symbol + # TODO- search. Then the top k symbols are found from that file. We move + # TODO- to the next file. If that file has a greater variance than the kth + # TODO- symbol found from the previous set of files, then we're done, else + # TODO- run symbol bisect on it to get the top k symbols as well (we can + # TODO- stop as soon as a symbol is less than the kth symbol (after + # TODO- updating the list of k). + print('Searching for bad source files:') logging.info('Searching for bad source files under the trouble' ' compilation') From 761bed0d72ce66c94f0a928f9a1b292523100eeb Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Fri, 10 Aug 2018 13:16:16 -0600 Subject: [PATCH 042/196] Documentation updated --- scripts/flitcli/flit_bisect.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index c0953800..c804cdda 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -414,9 +414,9 @@ def extract_symbols(file_or_filelist, objdir): def memoize_strlist_func(func): ''' - Memoize a function that takes a list of strings and returns a value. This - function returns the memoized version. It is expected that the list of - strings passed in will be in the same order. This memoization will not + Memoize a function that takes a list and returns a value. This + function returns the memoized version. It is expected that the list + passed in will be in the same order. This memoization will not work if for instance the input is first shuffled. >>> def to_memoize(strlist): From 79c8e61d49910224dc938c5c360021ba494c5d7f Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Fri, 10 Aug 2018 14:14:10 -0600 Subject: [PATCH 043/196] sqrt of a negative input was causing NaN --- litmus-tests/tests/InliningProblem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/litmus-tests/tests/InliningProblem.cpp b/litmus-tests/tests/InliningProblem.cpp index a3b8cc05..66aa5258 100644 --- a/litmus-tests/tests/InliningProblem.cpp +++ b/litmus-tests/tests/InliningProblem.cpp @@ -93,7 +93,7 @@ class InliningProblem : public flit::TestBase { virtual size_t getInputsPerRun() override { return 1; } virtual std::vector getDefaultInput() override { - return { .1, 1.1e3, -.1, -1.1e3, 1/3 }; + return { .1, 1.1e3, 0.5, 3.14159256, 1/3 }; } protected: From 42b140bd96dfd8ef341b2c53110c5c426438cd1c Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Fri, 10 Aug 2018 14:14:36 -0600 Subject: [PATCH 044/196] updated input set --- litmus-tests/tests/ReciprocalMath.cpp | 54 ++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/litmus-tests/tests/ReciprocalMath.cpp b/litmus-tests/tests/ReciprocalMath.cpp index b0b31204..0ebf2733 100644 --- a/litmus-tests/tests/ReciprocalMath.cpp +++ b/litmus-tests/tests/ReciprocalMath.cpp @@ -89,7 +89,59 @@ class ReciprocalMath : public flit::TestBase { virtual size_t getInputsPerRun() override { return 5; } virtual std::vector getDefaultInput() override { - return { .1, 1.1e3, -.1, -1.1e3, 1/3 }; + return { 7505932213.155222, + -0.0003670095914968359, + 8780.668938367293, + -0.0006155790233503232, + 1.0530559711831378, + + 8338244879.47946, + -26.46659826627008, + -46.167772633949596, + -8.01886332371321, + 9.389477622336432, + + 87.0485837234231, + 814.095091206393, + 376.6986397719769, + 21.457991635073714, + -34.26603687459364, + + 31.594514417427042, + 0.0007624103417064105, + -0.02577922636404706, + -0.0009569015524931334, + -0.0003699749232482463, + + 5902221514.636204, + -0.00021708934100337198, + 9749.762436162175, + 0.8607435476176816, + -94.28304433351171, + + -49.70966603739113, + 7238595461.899788, + 985.3112995369329, + -707.7407922965596, + -671.0617089400928, + + -3699.38938030149, + -7073528488.719316, + -164.55786123623116, + -0.9364155629331614, + 7707.943761459553, + + -62.53791853138796, + -199.1618358455679, + -52.036903076794985, + -2.8204333352680377, + -2930.340776062591, + + -2852.2836425016662, + 72.33604399822339, + 378.80829294847405, + 9.71642682532883, + -2.6077212300950436}; } protected: From 1ca09219ea988facf668071ff83eadcc13a5d348 Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Fri, 10 Aug 2018 14:15:18 -0600 Subject: [PATCH 045/196] Test input hex values were creating NaNs --- .../tests/DistributivityOfMultiplication.cpp | 79 ++++++++++--------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/litmus-tests/tests/DistributivityOfMultiplication.cpp b/litmus-tests/tests/DistributivityOfMultiplication.cpp index d416c9ff..90686a66 100644 --- a/litmus-tests/tests/DistributivityOfMultiplication.cpp +++ b/litmus-tests/tests/DistributivityOfMultiplication.cpp @@ -247,45 +247,46 @@ DistributivityOfMultiplication::getDefaultInput() { // These are entered as hex values to maintain the exact value instead of trying // to specify enough decimal digits to get the same floating-point value std::vector ti = { - convert(0x2b99, 0x2bb4d082ca2e7ec7), // 3.586714e-1573 - convert(0x725a, 0x14c0a0cd445b52d5), // 6.131032e+3879 - convert(0x075d, 0x0bc91b713fc2fba5), // 4.278225e-4366 - - convert(0x3408, 0xd98776d83be541b8), // 1.497721e-922 - convert(0x7da5, 0x32daa5df77e78b5e), // 2.847787e+4750 - convert(0x376a, 0xfa52e8946985dab4), // 8.479921e-662 - - convert(0x2355, 0xb32ca57fbcc68a6c), // 1.541551e-2209 - convert(0x7337, 0x4855e1d4f174504d), // 7.201858e+3946 - convert(0x736a, 0xac4f338d852e88cd), // 3.863064e+3962 - - convert(0x4727, 0x9c8f934e1cc682d2), // 3.753403e+551 - convert(0x02e7, 0x3b753c2d81c6bf78), // 3.612998e-4709 - convert(0x485b, 0xeae81af41947d10a), // 2.936812e+644 - - convert(0x1b91, 0x9e18ddbb66670e9f), // 4.852600e-2808 - convert(0x205f, 0x58ab17d3e5309234), // 5.031688e-2438 - convert(0x4a4a, 0x1b8a0c6541700676), // 3.521930e+792 - - convert(0x4178, 0xd2cee20bba5c6843), // 5.069741e+113 - convert(0x3564, 0x58406d82dd970b8e), // 3.483973e-818 - convert(0x150a, 0x92cde10402bc42ef), // 4.292064e-3311 - - convert(0x1965, 0x630847ac1ecd253c), // 1.288694e-2975 - convert(0x004c, 0x6e2b4c6a070d3835), // 1.093228e-4909 - convert(0x380f, 0x92b14ca6d81b5a24), // 2.324058e-612 - - convert(0x4492, 0x870e870425dcb0cf), // 3.384007e+352 - convert(0x71dd, 0x159330946cecd9a8), // 1.498527e+3842 - convert(0x586a, 0xfc38e15fe5d604a5), // 1.079136e+1882 - - convert(0x240d, 0xae73609d2bf51b7d), // 3.680220e-2154 - convert(0x2a67, 0x89b93255d3362c94), // 8.669256e-1665 - convert(0x2462, 0x79d020dd3c308e90), // 9.941326e-2129 - - convert(0x6703, 0x6455d50eb2825cf7), // 3.818039e+3006 - convert(0x1f77, 0x70b75c7169817349), // 9.267715e-2508 - convert(0x4ab4, 0x27faa40914dad6a6), // 4.148019e+824 + // 0x663B40322A41D3AE972B + convert(0x2B97, 0xAED3412A32403B66), // 3.586714e-1573 + convert(0x7257, 0xA605064F0279F445), // 6.131032e+3879 + convert(0x0759, 0xBC91B5B4C128340B), // 4.278225e-4366 + + convert(0x3408, 0xD9877B209C448671), // 1.497721e-922 + convert(0x7DA3, 0xCB6A9713AF8B33A1), // 2.847787e+4750 + convert(0x376A, 0xFA52E8978C6C9B9C), // 8.479921e-662 + + convert(0x2355, 0xB32CA7EC5E694CA3), // 1.541551e-2209 + convert(0x7336, 0x90ABC4405309DE21), // 7.201858e+3946 + convert(0x736A, 0xAC4F344252296368), // 3.863064e+3962 + + convert(0x4727, 0x9C8F926F9D81F76F), // 3.753403e+551 + convert(0x02E5, 0xEDD4EED5EB8D326F), // 3.612998e-4709 + convert(0x485B, 0xEAE81D2B24F2F2D4), // 2.936812e+644 + + convert(0x1B91, 0x9E18DE75A88B8EFF), // 4.852600e-2808 + convert(0x205E, 0xB156306D61A021F2), // 5.031688e-2438 + convert(0x4A47, 0xDC5062844DCD1D50), // 3.521930e+792 + + convert(0x4178, 0xD2CEE24A186FAE99), // 5.069741e+113 + convert(0x3563, 0xB080DC1B4056BCFC), // 3.483973e-818 + convert(0x150A, 0x92CDDFF068A532AC), // 4.292064e-3311 + + convert(0x1964, 0xC6108B7B0B1846FF), // 1.288694e-2975 + convert(0x004B, 0xDC569B288F230CA5), // 1.093228e-4909 + convert(0x380F, 0x92B14C59FBC79205), // 2.324058e-612 + + convert(0x4492, 0x870E87461590FB53), // 3.384007e+352 + convert(0x71DA, 0xAC9981EE164A3F4A), // 1.498527e+3842 + convert(0x586A, 0xFC38E006060C3819), // 1.079136e+1882 + + convert(0x240D, 0xAE736174E4368DE7), // 3.680220e-2154 + convert(0x2A67, 0x89B932A8729137A3), // 8.669256e-1665 + convert(0x2461, 0xF3A041588E81E4FA), // 9.941326e-2129 + + convert(0x6702, 0xC8ABA8F1D29CA39F), // 3.818039e+3006 + convert(0x1F76, 0xE16EB83CE645D0EF), // 9.267715e-2508 + convert(0x4AB2, 0x9FEA8F04FC4E664D), // 4.148019e+824 }; return ti; From 0ebf78df4f1a44e1c2870ae843587d7a59a81d70 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 16:17:01 -0600 Subject: [PATCH 046/196] Update flit_bisect.py Yes, it can work with any list of hashable types, but it only needs to work right now with lists of strings. I think it's easier to change the example in the docstring. This will not be able to memoize something that takes a list of lists, or a list of dictionaries, or even a list of sets. That's why I was specific, and why the bisect algorithm cannot memoize in general, since it would matter what is being memoized. --- scripts/flitcli/flit_bisect.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index c804cdda..a0cc9594 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -414,7 +414,7 @@ def extract_symbols(file_or_filelist, objdir): def memoize_strlist_func(func): ''' - Memoize a function that takes a list and returns a value. This + Memoize a function that takes a list of strings and returns a value. This function returns the memoized version. It is expected that the list passed in will be in the same order. This memoization will not work if for instance the input is first shuffled. @@ -423,18 +423,18 @@ def memoize_strlist_func(func): ... print(strlist) ... return strlist[0] >>> memoized = memoize_strlist_func(to_memoize) - >>> memoized([1, 2, 3]) - [1, 2, 3] - 1 - >>> memoized([1, 2, 3]) - 1 - >>> memoized([3, 2]) - [3, 2] - 3 - >>> memoized([1, 2, 3]) - 1 - >>> memoized([3, 2]) - 3 + >>> memoized(['a', 'b', 'c']) + ['a', 'b', 'c'] + a + >>> memoized(['a', 'b', 'c']) + a + >>> memoized(['e', 'a']) + ['e', 'a'] + e + >>> memoized(['a', 'b', 'c']) + a + >>> memoized(['e', 'a']) + e ''' memo = {} def memoized_func(strlist): From 999175b368add0810484b0f45fad75dea183cf59 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 16:55:32 -0600 Subject: [PATCH 047/196] bisect: extract similar code from test functions out --- scripts/flitcli/flit_bisect.py | 126 ++++++++++++--------------------- 1 file changed, 45 insertions(+), 81 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 5b9eb370..ff682048 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -719,7 +719,7 @@ def bisect_search(score_func, elements, found_callback=None): bad_list = [] while len(quest_list) > 0 and score_func(quest_list) > 0: - + # find one bad element quest_copy = quest_list while len(quest_copy) > 1: @@ -937,31 +937,7 @@ def bisect_libs_build_and_check(trouble_libs): makefile = create_bisect_makefile(bisect_path, repl_copy, sources, [], dict()) makepath = os.path.join(bisect_path, makefile) - - print(' Create {0} - compiling and running'.format(makepath), - end='', flush=True) - logging.info('Created %s', makepath) - logging.info('Checking:') - for lib in trouble_libs: - logging.info(' %s', lib) - - try: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs) - finally: - if args.delete: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs, target='bisect-smallclean') - resultfile = util.extract_make_var('BISECT_RESULT', makepath, - args.directory)[0] - resultpath = os.path.join(args.directory, resultfile) - result = get_comparison_result(resultpath) - result_str = str(result) - - sys.stdout.write(' - score {0}\n'.format(result_str)) - logging.info('Result was %s', result_str) - - return result + return test_makefile(args, makepath, trouble_libs) memoized_checker = memoize_strlist_func(bisect_libs_build_and_check) @@ -982,6 +958,43 @@ def bisect_libs_build_and_check(trouble_libs): return libs return [] +def test_makefile(args, makepath, testing_list): + ''' + Runs the compilation in the makefile and returns the generated comparison + result. + + @param args: parsed command-line arguments (see parse_args()) + @param makepath (str): absolute or relative path to the Makefile + @param testing_list (list(str)): list of items being tested (for logging + purposes) + + @return (float) generated comparison result + ''' + print(' Created {0} - compiling and running'.format(makepath), end='', + flush=True) + logging.info('Created %s', makepath) + logging.info('Checking:') + for src in testing_list: + logging.info(' %s', src) + + try: + build_bisect(makepath, args.directory, verbose=args.verbose, + jobs=args.jobs) + finally: + if args.delete: + build_bisect(makepath, args.directory, verbose=args.verbose, + jobs=args.jobs, target='bisect-smallclean') + resultfile = util.extract_make_var('BISECT_RESULT', makepath, + args.directory)[0] + resultpath = os.path.join(args.directory, resultfile) + result = get_comparison_result(resultpath) + result_str = str(result) + + sys.stdout.write(' - score {0}\n'.format(result_str)) + logging.info('Result was %s', result_str) + + return result + def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. @@ -1001,31 +1014,7 @@ def bisect_build_and_check(trouble_src): makefile = create_bisect_makefile(bisect_path, replacements, gt_src, trouble_src, dict()) makepath = os.path.join(bisect_path, makefile) - - print(' Created {0} - compiling and running'.format(makepath), end='', - flush=True) - logging.info('Created %s', makepath) - logging.info('Checking:') - for src in trouble_src: - logging.info(' %s', src) - - try: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs) - finally: - if args.delete: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs, target='bisect-smallclean') - resultfile = util.extract_make_var('BISECT_RESULT', makepath, - args.directory)[0] - resultpath = os.path.join(args.directory, resultfile) - result = get_comparison_result(resultpath) - result_str = str(result) - - sys.stdout.write(' - score {0}\n'.format(result_str)) - logging.info('Result was %s', result_str) - - return result + return test_makefile(args, makepath, trouble_src) memoized_checker = memoize_strlist_func(bisect_build_and_check) @@ -1090,8 +1079,6 @@ def bisect_symbol_build_and_check(trouble_symbols): @param trouble_symbols: (list of SymbolTuple) symbols to use from the trouble compilation - @param gt_symbols: (list of SymbolTuple) symbols to use from - the ground truth compilation @return True if the compilation has a non-zero comparison between this mixed compilation and the full ground truth compilation. @@ -1110,34 +1097,11 @@ def bisect_symbol_build_and_check(trouble_symbols): makefile = create_bisect_makefile(bisect_path, replacements, gt_src, trouble_src, symbol_map) makepath = os.path.join(bisect_path, makefile) - - print(' Created {0} - compiling and running'.format(makepath), end='', - flush=True) - logging.info('Created %s', makepath) - logging.info('Checking:') - for sym in trouble_symbols: - logging.info( - '%s', - ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' - .format(sym=sym)) - - try: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs) - finally: - if args.delete: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs, target='bisect-smallclean') - resultfile = util.extract_make_var('BISECT_RESULT', makepath, - args.directory)[0] - resultpath = os.path.join(args.directory, resultfile) - result = get_comparison_result(resultpath) - result_str = str(result) - - sys.stdout.write(' - score {0}\n'.format(result_str)) - logging.info('Result was %s', result_str) - - return result + symbol_strings = [ + ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' + .format(sym=sym) for sym in trouble_symbols + ] + return test_makefile(args, makepath, symbol_strings) memoized_checker = memoize_strlist_func(bisect_symbol_build_and_check) From 419c247001970708be271ed1060a1a0fbcef2bb6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 16:55:48 -0600 Subject: [PATCH 048/196] Add pylint.rc file --- pylint.rc | 547 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 547 insertions(+) create mode 100644 pylint.rc diff --git a/pylint.rc b/pylint.rc new file mode 100644 index 00000000..8e47ce6f --- /dev/null +++ b/pylint.rc @@ -0,0 +1,547 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=CVS + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. +jobs=1 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=print-statement, + parameter-unpacking, + unpacking-in-except, + old-raise-syntax, + backtick, + long-suffix, + old-ne-operator, + old-octal-literal, + import-star-module-level, + non-ascii-bytes-literal, + invalid-unicode-literal, + raw-checker-failed, + bad-inline-option, + locally-disabled, + locally-enabled, + file-ignored, + suppressed-message, + useless-suppression, + deprecated-pragma, + apply-builtin, + basestring-builtin, + buffer-builtin, + cmp-builtin, + coerce-builtin, + execfile-builtin, + file-builtin, + long-builtin, + raw_input-builtin, + reduce-builtin, + standarderror-builtin, + unicode-builtin, + xrange-builtin, + coerce-method, + delslice-method, + getslice-method, + setslice-method, + no-absolute-import, + old-division, + dict-iter-method, + dict-view-method, + next-method-called, + metaclass-assignment, + indexing-exception, + raising-string, + reload-builtin, + oct-method, + hex-method, + nonzero-method, + cmp-method, + input-builtin, + round-builtin, + intern-builtin, + unichr-builtin, + map-builtin-not-iterating, + zip-builtin-not-iterating, + range-builtin-not-iterating, + filter-builtin-not-iterating, + using-cmp-argument, + eq-without-hash, + div-method, + idiv-method, + rdiv-method, + exception-message-attribute, + invalid-str-codec, + sys-max-int, + bad-python3-import, + deprecated-string-function, + deprecated-str-translate-call, + deprecated-itertools-function, + deprecated-types-field, + next-method-defined, + dict-items-not-iterating, + dict-keys-not-iterating, + dict-values-not-iterating, + deprecated-operator-function, + deprecated-urllib-function, + xreadlines-attribute, + deprecated-sys-function, + exception-escape, + comprehension-escape, + C1801 + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=optparse.Values,sys.exit + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins,io + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module +max-module-lines=1000 + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma, + dict-separator + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[BASIC] + +# Naming style matching correct argument names +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style +#argument-rgx= + +# Naming style matching correct attribute names +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style +#class-attribute-rgx= + +# Naming style matching correct class names +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming-style +#class-rgx= + +# Naming style matching correct constant names +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style +#const-rgx= + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma +good-names=i, + j, + k, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming style matching correct inline iteration names +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style +#inlinevar-rgx= + +# Naming style matching correct method names +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style +#method-rgx= + +# Naming style matching correct module names +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style +#variable-rgx= + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + +# Minimum lines number of a similarity. +min-similarity-lines=4 + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception From b21eec3a56f20743598849099ee43753acada375 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 23:45:08 -0600 Subject: [PATCH 049/196] bisect: move functions around for better organization --- scripts/flitcli/flit_bisect.py | 74 +++++++++++++++++----------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index ff682048..7e034426 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -903,6 +903,43 @@ def parse_args(arguments, prog=sys.argv[0]): return args +def test_makefile(args, makepath, testing_list): + ''' + Runs the compilation in the makefile and returns the generated comparison + result. + + @param args: parsed command-line arguments (see parse_args()) + @param makepath (str): absolute or relative path to the Makefile + @param testing_list (list(str)): list of items being tested (for logging + purposes) + + @return (float) generated comparison result + ''' + print(' Created {0} - compiling and running'.format(makepath), end='', + flush=True) + logging.info('Created %s', makepath) + logging.info('Checking:') + for src in testing_list: + logging.info(' %s', src) + + try: + build_bisect(makepath, args.directory, verbose=args.verbose, + jobs=args.jobs) + finally: + if args.delete: + build_bisect(makepath, args.directory, verbose=args.verbose, + jobs=args.jobs, target='bisect-smallclean') + resultfile = util.extract_make_var('BISECT_RESULT', makepath, + args.directory)[0] + resultpath = os.path.join(args.directory, resultfile) + result = get_comparison_result(resultpath) + result_str = str(result) + + sys.stdout.write(' - score {0}\n'.format(result_str)) + logging.info('Result was %s', result_str) + + return result + def search_for_linker_problems(args, bisect_path, replacements, sources, libs): ''' Performs the search over the space of statically linked libraries for @@ -958,43 +995,6 @@ def bisect_libs_build_and_check(trouble_libs): return libs return [] -def test_makefile(args, makepath, testing_list): - ''' - Runs the compilation in the makefile and returns the generated comparison - result. - - @param args: parsed command-line arguments (see parse_args()) - @param makepath (str): absolute or relative path to the Makefile - @param testing_list (list(str)): list of items being tested (for logging - purposes) - - @return (float) generated comparison result - ''' - print(' Created {0} - compiling and running'.format(makepath), end='', - flush=True) - logging.info('Created %s', makepath) - logging.info('Checking:') - for src in testing_list: - logging.info(' %s', src) - - try: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs) - finally: - if args.delete: - build_bisect(makepath, args.directory, verbose=args.verbose, - jobs=args.jobs, target='bisect-smallclean') - resultfile = util.extract_make_var('BISECT_RESULT', makepath, - args.directory)[0] - resultpath = os.path.join(args.directory, resultfile) - result = get_comparison_result(resultpath) - result_str = str(result) - - sys.stdout.write(' - score {0}\n'.format(result_str)) - logging.info('Result was %s', result_str) - - return result - def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. From 464ea576a5bffe4bb1191405d6e146b2e63cb5c4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 10 Aug 2018 23:45:38 -0600 Subject: [PATCH 050/196] bisect: add optional indent argument for test_makefile() --- scripts/flitcli/flit_bisect.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 7e034426..bb48e481 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -903,7 +903,7 @@ def parse_args(arguments, prog=sys.argv[0]): return args -def test_makefile(args, makepath, testing_list): +def test_makefile(args, makepath, testing_list, indent=' '): ''' Runs the compilation in the makefile and returns the generated comparison result. @@ -915,12 +915,12 @@ def test_makefile(args, makepath, testing_list): @return (float) generated comparison result ''' - print(' Created {0} - compiling and running'.format(makepath), end='', - flush=True) - logging.info('Created %s', makepath) - logging.info('Checking:') + print('{}Created {} - compiling and running'.format(indent, makepath), + end='', flush=True) + logging.info('%sCreated %s', indent, makepath) + logging.info('%sChecking:', indent) for src in testing_list: - logging.info(' %s', src) + logging.info(' %s%s', indent, src) try: build_bisect(makepath, args.directory, verbose=args.verbose, @@ -936,7 +936,7 @@ def test_makefile(args, makepath, testing_list): result_str = str(result) sys.stdout.write(' - score {0}\n'.format(result_str)) - logging.info('Result was %s', result_str) + logging.info('%sResult was %s', indent, result_str) return result From 33e9c3b7e490219d398e4380b15606c1b7d7567e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 11 Aug 2018 00:06:54 -0600 Subject: [PATCH 051/196] bisect: create test generators rather than local functions --- scripts/flitcli/flit_bisect.py | 178 +++++++++++++++++++-------------- 1 file changed, 104 insertions(+), 74 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index bb48e481..7eace5da 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -940,6 +940,104 @@ def test_makefile(args, makepath, testing_list, indent=' '): return result +def _gen_bisect_lib_checker(args, bisect_path, replacements, sources, + indent=' '): + ''' + Generates and returns the function that builds and check a list of + libraries for showing variability. The returned function is memoized, so + no need to be careful to not call it more than once with the same + arguments. + ''' + def builder_and_checker(libs): + ''' + Compiles all source files under the ground truth compilation and + statically links in the libs. + + @param libs: static libraries to compile in + + @return The comparison value between this mixed compilation and the + full baseline compilation. + ''' + repl_copy = dict(replacements) + repl_copy['link_flags'] = list(repl_copy['link_flags']) + repl_copy['link_flags'].extend(libs) + makefile = create_bisect_makefile(bisect_path, repl_copy, sources, + [], dict()) + makepath = os.path.join(bisect_path, makefile) + return test_makefile(args, makepath, libs, indent=indent) + + return memoize_strlist_func(builder_and_checker) + +def _gen_bisect_source_checker(args, bisect_path, replacements, sources, + indent=' '): + ''' + Generates and returns the function that builds and check a list of sources + for showing variability. The returned function is memoized, so no need to + be careful to not call it more than once with the same arguments. + ''' + def builder_and_checker(sources_to_optimize): + ''' + Compiles the compilation with sources_to_optimize compiled with the + optimized compilation and with everything else compiled with the + baseline compilation. + + @param sources_to_optimize: source files to compile with the + variability-inducing optimizations + + @return The comparison value between this mixed compilation and the + full baseline compilation. + ''' + gt_src = list(set(sources).difference(sources_to_optimize)) + makefile = create_bisect_makefile(bisect_path, replacements, gt_src, + sources_to_optimize, dict()) + makepath = os.path.join(bisect_path, makefile) + return test_makefile(args, makepath, sources_to_optimize, indent=indent) + + return memoize_strlist_func(builder_and_checker) + +def _gen_bisect_symbol_checker(args, bisect_path, replacements, sources, + symbols, indent=' '): + ''' + Generates and returns the function that builds and check a list of sources + for showing variability. The returned function is memoized, so no need to + be careful to not call it more than once with the same arguments. + ''' + def builder_and_checker(symbols_to_optimize): + ''' + Compiles the compilation with all files compiled under the ground truth + compilation except for the given symbols for the given files. + + In order to be able to isolate these symbols, the files will need to be + compiled with -fPIC, but that is handled by the generated Makefile. + + @param symbols_to_optimize: (list of SymbolTuple) symbols to use + from the variability-inducing optimization compilation + + @return The comparison value between this mixed compilation and the + full baseline compilation. + ''' + gt_symbols = list(set(symbols).difference(symbols_to_optimize)) + all_sources = list(sources) # copy the list of all source files + symbol_sources = [x.src for x in symbols_to_optimize + gt_symbols] + trouble_src = [] + gt_src = list(set(all_sources).difference(symbol_sources)) + symbol_map = {x: [ + [y.symbol for y in gt_symbols if y.src == x], + [z.symbol for z in symbols_to_optimize if z.src == x], + ] + for x in symbol_sources} + + makefile = create_bisect_makefile(bisect_path, replacements, gt_src, + trouble_src, symbol_map) + makepath = os.path.join(bisect_path, makefile) + symbol_strings = [ + ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' + .format(sym=sym) for sym in symbols_to_optimize + ] + return test_makefile(args, makepath, symbol_strings, indent=indent) + + return memoize_strlist_func(builder_and_checker) + def search_for_linker_problems(args, bisect_path, replacements, sources, libs): ''' Performs the search over the space of statically linked libraries for @@ -956,27 +1054,8 @@ def search_for_linker_problems(args, bisect_path, replacements, sources, libs): the libraries included, and checks to see if there are reproducibility problems. ''' - def bisect_libs_build_and_check(trouble_libs): - ''' - Compiles all source files under the ground truth compilation and - statically links in the trouble_libs. - - @param trouble_libs: static libraries to compile in - @param dummy_libs: static libraries to ignore and not include - This variable is not used, but necessary for the interface. - - @return True if the compilation has a non-zero comparison between this - mixed compilation and the full ground-truth compilation. - ''' - repl_copy = dict(replacements) - repl_copy['link_flags'] = list(repl_copy['link_flags']) - repl_copy['link_flags'].extend(trouble_libs) - makefile = create_bisect_makefile(bisect_path, repl_copy, sources, - [], dict()) - makepath = os.path.join(bisect_path, makefile) - return test_makefile(args, makepath, trouble_libs) - - memoized_checker = memoize_strlist_func(bisect_libs_build_and_check) + memoized_checker = _gen_bisect_lib_checker(args, bisect_path, replacements, + sources) print('Searching for bad intel static libraries:') logging.info('Searching for bad static libraries included by intel linker:') @@ -999,24 +1078,8 @@ def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. ''' - def bisect_build_and_check(trouble_src): - ''' - Compiles the compilation with trouble_src compiled with the trouble - compilation and with gt_src compiled with the ground truth compilation. - - @param trouble_src: source files to compile with trouble compilation - @param gt_src: source files to compile with ground truth compilation - - @return True if the compilation has a non-zero comparison between this - mixed compilation and the full ground truth compilation. - ''' - gt_src = list(set(sources).difference(trouble_src)) - makefile = create_bisect_makefile(bisect_path, replacements, gt_src, - trouble_src, dict()) - makepath = os.path.join(bisect_path, makefile) - return test_makefile(args, makepath, trouble_src) - - memoized_checker = memoize_strlist_func(bisect_build_and_check) + memoized_checker = _gen_bisect_source_checker(args, bisect_path, + replacements, sources) # TODO: make a callback that immediately starts the symbol search on the # TODO- first found file. Do this for when args.biggest is defined. @@ -1069,41 +1132,8 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, .format(sym=sym) logging.info('%s', message) - def bisect_symbol_build_and_check(trouble_symbols): - ''' - Compiles the compilation with all files compiled under the ground truth - compilation except for the given symbols for the given files. - - In order to be able to isolate these symbols, the files will need to be - compiled with -fPIC, but that is handled by the generated Makefile. - - @param trouble_symbols: (list of SymbolTuple) symbols to use - from the trouble compilation - - @return True if the compilation has a non-zero comparison between this - mixed compilation and the full ground truth compilation. - ''' - gt_symbols = list(set(symbol_tuples).difference(trouble_symbols)) - all_sources = list(sources) # copy the list of all source files - symbol_sources = [x.src for x in trouble_symbols + gt_symbols] - trouble_src = [] - gt_src = list(set(all_sources).difference(symbol_sources)) - symbol_map = {x: [ - [y.symbol for y in gt_symbols if y.src == x], - [z.symbol for z in trouble_symbols if z.src == x], - ] - for x in symbol_sources} - - makefile = create_bisect_makefile(bisect_path, replacements, gt_src, - trouble_src, symbol_map) - makepath = os.path.join(bisect_path, makefile) - symbol_strings = [ - ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' - .format(sym=sym) for sym in trouble_symbols - ] - return test_makefile(args, makepath, symbol_strings) - - memoized_checker = memoize_strlist_func(bisect_symbol_build_and_check) + memoized_checker = _gen_bisect_symbol_checker( + args, bisect_path, replacements, sources, symbol_tuples) # Check to see if -fPIC destroyed any chance of finding any bad symbols if not memoized_checker(symbol_tuples): From f493802765c1197ca2afeafcf1a5b2f2ea915ad1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 11 Aug 2018 10:58:01 -0600 Subject: [PATCH 052/196] bisect: good -> baseline, bad -> differing --- scripts/flitcli/flit_bisect.py | 307 +++++++++++++++++--------------- tests/flit_bisect/tst_bisect.py | 124 ++++++------- 2 files changed, 223 insertions(+), 208 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 7eace5da..81d3e220 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -175,9 +175,9 @@ def create_bisect_makefile(directory, replacements, gt_src, @param trouble_src: (list) which source files would be compiled with the trouble compilation within the resulting binary. @param split_symbol_map: - (dict fname -> list [list good symbols, list bad symbols]) - Files to compile as a split between good and bad, specifying good and - bad symbols for each file. + (dict fname -> list [list baseline symbols, list differing symbols]) + Files to compile as a split between baseline and differing, specifying + baseline and differing symbols for each file. Within replacements, there are some optional fields: - cpp_flags: (list) (optional) List of c++ compiler flags to give to @@ -351,9 +351,9 @@ def get_comparison_result(resultfile): val = row['comparison'] return float(val) if val != 'NULL' else None -def is_result_bad(resultfile): +def is_result_differing(resultfile): ''' - Returns True if the results from the resultfile is considered 'bad', + Returns True if the results from the resultfile is considered 'differing', meaning it is a different answer from the ground-truth. @param resultfile: path to the results csv file after comparison @@ -365,28 +365,28 @@ def is_result_bad(resultfile): ... _ = fout.write('name,host,compiler,...,comparison,...\\n' ... 'test,name,clang++,...,15.342,...\\n') ... fname = fout.name - >>> is_result_bad(fname) + >>> is_result_differing(fname) True Try out a value that is less than zero >>> with open(fname, 'w') as fout: ... _ = fout.write('comparison\\n' ... '-1e-34\\n') - >>> is_result_bad(fname) + >>> is_result_differing(fname) True Try out a value that is identically zero >>> with open(fname, 'w') as fout: ... _ = fout.write('comparison\\n' ... '0.0\\n') - >>> is_result_bad(fname) + >>> is_result_differing(fname) False Make sure NULL values are handled appropriately >>> with open(fname, 'w') as fout: ... _ = fout.write('comparison\\n' ... 'NULL\\n') - >>> is_result_bad(fname) + >>> is_result_differing(fname) Traceback (most recent call last): ... TypeError: float() argument must be a string or a number, not 'NoneType' @@ -395,7 +395,7 @@ def is_result_bad(resultfile): >>> with open(fname, 'w') as fout: ... _ = fout.write('comparison\\n' ... 'coconut\\n') - >>> is_result_bad(fname) + >>> is_result_differing(fname) Traceback (most recent call last): ... ValueError: could not convert string to float: 'coconut' @@ -538,29 +538,31 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): to the total number of offenders, then bisect_biggest() is more expensive than bisect_search(). - We do not want to call score_func() very much. We assume the score_func() is - is an expensive operation. We could go throught the list one at a time, + We do not want to call score_func() very much. We assume the score_func() + is is an expensive operation. We could go throught the list one at a time, but that would cause us to potentially call score_func() more than necessary. Note: The same assumption as bisect_search() is in place. That is that all - bad elements are independent. This means if an element contributes to a - bad score, then it would contribute to a bad score by itself as well. This - is not always true, and this function does not verify this assumption. - Instead, it will only return the largest singleton offenders. + differing elements are independent. This means if an element contributes + to a differing score, then it would contribute to a differing score by + itself as well. This is not always true, and this function does not verify + this assumption. Instead, it will only return the largest singleton + offenders. @param score_func: a function that takes one argument (to_test) and returns - a number greater than zero if the function is bad. This value returned - is used to compare the elements so that the largest k offenders are - found and returned. If all offenders return the same numerical value, + a number greater than zero if one of the elements in to_test causes the + result to be differing. This value returned is used to compare the + elements so that the largest k differing elements are found and + returned. If all differing elements return the same numerical value, then this will be less efficient than bisect_search. - Note: if the set of elements is good, then either return 0 or a - negative value. + Note: if the set of elements is not differing, then either return 0 or + a negative value. @param elements: the elements to search over. Subsets of this list will be given to score_func(). - @param found_callback: a callback function to be called on every found bad - element. Will be given two arguments, the element, and the score from - score_func(). + @param found_callback: a callback function to be called on every found + differing element. Will be given two arguments, the element, and the + score from score_func(). @param k: number of biggest elements to return. The default is to return the one biggest offender. If there are less than k elements that return positive scores, then only the found offenders will be returned. @@ -625,9 +627,9 @@ def bisect_search(score_func, elements, found_callback=None): ''' Performs the bisect search, attempting to find all elements contributing to a positive score. This score_func() function is intended to identify when - there are "bad" elements by returning a positive score. This is different - from bisect_biggest() in that we find all offenders and can therefore do - some optimization that bisect_biggest() cannot do. + there are "differing" elements by returning a positive score. This is + different from bisect_biggest() in that we find all offenders and can + therefore do some optimization that bisect_biggest() cannot do. We do not want to call score_func() very much. We assume the score_func() is an expensive operation. We could go throught the list one at a time, @@ -636,31 +638,33 @@ def bisect_search(score_func, elements, found_callback=None): This function has complexity O(k*log(n))*O(score_func) - where n is the size of the elements and k is the number of bad elements to - find. + where n is the size of the elements and k is the number of differing + elements to find. - Note: A key assumption to this algorithm is that all bad elements are + Note: A key assumption to this algorithm is that all differing elements are independent. That may not always be true, so there are redundant checks within the algorithm to verify that this assumption is not vialoated. If the assumption is found to be violated, then an AssertionError is raised. - @param score_func: a function that takes one argument, the list of elements to - test if they are bad. The function then returns a positive value if - the given list has a bad element. If the given list does not have a - bad element, this can return zero or a negative value. - Note: this function must be able to handle empty lists. An empty list - should instantly return a non-positive value, as there cannot possibly - be a bad element passed to it. + @param score_func: a function that takes one argument, the list of elements + to test if they are differing. The function then returns a positive + value if the given list has a differing element. If the given list + does not have a differing element, this can return zero or a negative + value. Note: this function must be able to handle empty lists. An + empty list should instantly return a non-positive value, as there + cannot possibly be a differing element passed to it. It is expected that this function is memoized because it may be called more than once on the same input during the execution of this algorithm. - @param elements: contains bad elements, but potentially good elements too - @param found_callback: a callback function to be called on every found bad - element. Will be given two arguments, the element, and the score from - score_func(). - - @return minimal bad list of all elements that cause score_func() to return - positive values, along with their scores, sorted descending by score. + @param elements: contains differing elements, but potentially non-differing + elements too + @param found_callback: a callback function to be called on every found + differing element. Will be given two arguments, the element, and the + score from score_func(). + + @return minimal differing list of all elements that cause score_func() to + return positive values, along with their scores, sorted descending by + score. [(elem, score), ...] Here's an example of finding all negative numbers in a list. Not very @@ -694,14 +698,14 @@ def bisect_search(score_func, elements, found_callback=None): See what happens when it has a pair that only show up together and not alone. Only if -6 and 5 are in the list, then score_func() returns a - positive value. The assumption of this algorithm is that bad elements are - independent, so this should throw an exception. + positive value. The assumption of this algorithm is that differing + elements are independent, so this should throw an exception. >>> def score_func(x): ... return max(x) - min(x) - 10 if x else 0 >>> bisect_search(score_func, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) Traceback (most recent call last): ... - AssertionError: Assumption that bad elements are independent was wrong + AssertionError: Assumption that differing elements are independent was wrong Check that the found_callback is not called on false positives. Here I expect no output since no single element can be found. @@ -717,10 +721,10 @@ def bisect_search(score_func, elements, found_callback=None): # copy the incoming list so that we don't modify it quest_list = list(elements) - bad_list = [] + differing_list = [] while len(quest_list) > 0 and score_func(quest_list) > 0: - # find one bad element + # find one differing element quest_copy = quest_list while len(quest_copy) > 1: half_1 = quest_copy[:len(quest_copy) // 2] @@ -733,29 +737,32 @@ def bisect_search(score_func, elements, found_callback=None): # update the local search quest_copy = quest_copy[len(half_1):] - # since we remove known good elements as we find them, the bad element - # will be at the beginning of quest_list. - bad_element = quest_list.pop(0) + # since we remove known non-differing elements as we find them, the + # differing element will be at the beginning of quest_list. + differing_element = quest_list.pop(0) - # double check that we found a bad element before declaring it bad - score = score_func([bad_element]) + # double check that we found a differing element before declaring it + # differing + score = score_func([differing_element]) if score > 0: - bad_list.append((bad_element, score)) - # inform caller that a bad element was found + differing_list.append((differing_element, score)) + # inform caller that a differing element was found if found_callback != None: - found_callback(bad_element, score) + found_callback(differing_element, score) - # Perform a sanity check. If we have found all of the bad items, then - # compiling with all but these bad items will cause a good build. + # Perform a sanity check. If we have found all of the differing items, then + # compiling with all but these differing items will cause a non-differing + # build. # This will fail if our hypothesis class is wrong - good_list = list(set(elements).difference(x[0] for x in bad_list)) - assert score_func(good_list) <= 0, \ - 'Assumption that bad elements are independent was wrong' + non_differing_list = \ + list(set(elements).difference(x[0] for x in differing_list)) + assert score_func(non_differing_list) <= 0, \ + 'Assumption that differing elements are independent was wrong' # sort descending by score - bad_list.sort(key=lambda x: -x[1]) + differing_list.sort(key=lambda x: -x[1]) - return bad_list + return differing_list def parse_args(arguments, prog=sys.argv[0]): ''' @@ -1057,19 +1064,20 @@ def search_for_linker_problems(args, bisect_path, replacements, sources, libs): memoized_checker = _gen_bisect_lib_checker(args, bisect_path, replacements, sources) - print('Searching for bad intel static libraries:') - logging.info('Searching for bad static libraries included by intel linker:') - #bas_library_msg = ' Found bad library {} (score {})' - #bad_library_callback = lambda filename, score: \ - # util.printlog(bad_library_msg.format(filename, score)) + print('Searching for differing intel static libraries:') + logging.info('Searching for differing static libraries included by intel ' + 'linker:') + #differing_library_msg = ' Found differing library {} (score {})' + #differing_library_callback = lambda filename, score: \ + # util.printlog(differing_library_msg.format(filename, score)) #if args.biggest is None: - # bad_libs = bisect_search(memoized_checker, libs, - # found_callback=bad_library_callback) + # differing_libs = bisect_search( + # memoized_checker, libs, found_callback=differing_library_callback) #else: - # bad_libs = bisect_biggest(memoized_checker, libs, - # found_callback=bad_library_callback, - # k=args.biggest) - #return bad_libs + # differing_libs = bisect_biggest( + # memoized_checker, libs, found_callback=differing_library_callback, + # k=args.biggest) + #return differing_libs if memoized_checker(libs): return libs return [] @@ -1091,41 +1099,43 @@ def search_for_source_problems(args, bisect_path, replacements, sources): # TODO- stop as soon as a symbol is less than the kth symbol (after # TODO- updating the list of k). - print('Searching for bad source files:') - logging.info('Searching for bad source files under the trouble' + print('Searching for differing source files:') + logging.info('Searching for differing source files under the trouble' ' compilation') - bad_source_msg = ' Found bad source file {}: score {}' - bad_source_callback = lambda filename, score: \ - util.printlog(bad_source_msg.format(filename, score)) + differing_source_msg = ' Found differing source file {}: score {}' + differing_source_callback = lambda filename, score: \ + util.printlog(differing_source_msg.format(filename, score)) if args.biggest is None: - bad_sources = bisect_search(memoized_checker, sources, - found_callback=bad_source_callback) + differing_sources = bisect_search( + memoized_checker, sources, + found_callback=differing_source_callback) else: - bad_sources = bisect_biggest(memoized_checker, sources, - found_callback=bad_source_callback, - k=args.biggest) - return bad_sources + differing_sources = bisect_biggest( + memoized_checker, sources, + found_callback=differing_source_callback, k=args.biggest) + return differing_sources def search_for_symbol_problems(args, bisect_path, replacements, sources, - bad_source): + differing_source): ''' - Performs the search over the space of symbols within bad source files for - problems. + Performs the search over the space of symbols within differing source files + for problems. @param args: parsed command-line arguments @param bisect_path: directory where bisect is being performed @param replacements: dictionary of values to use in generating the Makefile @param sources: all source files - @param bad_source: the one bad source file to search for bad symbols + @param differing_source: the one differing source file to search for + differing symbols - @return a list of identified bad symbols (if any) + @return a list of identified differing symbols (if any) ''' - print('Searching for bad symbols in:', bad_source) - logging.info('Searching for bad symbols in: %s', bad_source) + print('Searching for differing symbols in:', differing_source) + logging.info('Searching for differing symbols in: %s', differing_source) logging.info('Note: inlining disabled to isolate functions') logging.info('Note: only searching over globally exported functions') logging.debug('Symbols:') - symbol_tuples = extract_symbols(bad_source, + symbol_tuples = extract_symbols(differing_source, os.path.join(args.directory, 'obj')) for sym in symbol_tuples: message = ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' \ @@ -1135,7 +1145,8 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, memoized_checker = _gen_bisect_symbol_checker( args, bisect_path, replacements, sources, symbol_tuples) - # Check to see if -fPIC destroyed any chance of finding any bad symbols + # Check to see if -fPIC destroyed any chance of finding any differing + # symbols if not memoized_checker(symbol_tuples): message_1 = ' Warning: -fPIC compilation destroyed the optimization' message_2 = ' Cannot find any trouble symbols' @@ -1145,21 +1156,20 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, logging.warning('%s', message_2) return [] - bad_symbol_msg = \ - ' Found bad symbol on line {sym.lineno} -- ' \ + differing_symbol_msg = \ + ' Found differing symbol on line {sym.lineno} -- ' \ '{sym.demangled} (score {score})' - bad_symbol_callback = lambda sym, score: \ - util.printlog(bad_symbol_msg.format(sym=sym, score=score)) + differing_symbol_callback = lambda sym, score: \ + util.printlog(differing_symbol_msg.format(sym=sym, score=score)) if args.biggest is None: - bad_symbols = bisect_search(memoized_checker, - symbol_tuples, - found_callback=bad_symbol_callback) + differing_symbols = bisect_search( + memoized_checker, symbol_tuples, + found_callback=differing_symbol_callback) else: - bad_symbols = bisect_biggest(memoized_checker, - symbol_tuples, - found_callback=bad_symbol_callback, - k=args.biggest) - return bad_symbols + differing_symbols = bisect_biggest( + memoized_checker, symbol_tuples, + found_callback=differing_symbol_callback, k=args.biggest) + return differing_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, jobs=mp.cpu_count(), delete=True): @@ -1284,7 +1294,7 @@ def run_bisect(arguments, prog=sys.argv[0]): update_gt_results(args.directory, verbose=args.verbose, jobs=args.jobs) # Find out if the linker is to blame (e.g. intel linker linking mkl libs) - bad_libs = [] + differing_libs = [] if os.path.basename(args.compiler) in ('icc', 'icpc'): warning_message = 'Warning: The intel compiler may not work with bisect' logging.info('%s', warning_message) @@ -1314,26 +1324,27 @@ def run_bisect(arguments, prog=sys.argv[0]): os.path.join(intel_lib_dir, 'libsvml.a'), ] try: - bad_libs = search_for_linker_problems(args, bisect_path, - replacements, sources, libs) + differing_libs = search_for_linker_problems( + args, bisect_path, replacements, sources, libs) except subp.CalledProcessError: print() print(' Executable failed to run.') - print('Failed to search for bad libraries -- cannot continue.') + print('Failed to search for differing libraries' + ' -- cannot continue.') return bisect_num, None, None, None, 1 - print(' bad static libraries:') + print(' differing static libraries:') logging.info('BAD STATIC LIBRARIES:') - for lib in bad_libs: + for lib in differing_libs: print(' ' + lib) logging.info(' %s', lib) - if len(bad_libs) == 0: + if len(differing_libs) == 0: print(' None') logging.info(' None') # For now, if the linker was to blame, then say there may be nothing # else we can do. - if len(bad_libs) > 0: + if len(differing_libs) > 0: message = 'May not be able to search further, because of intel ' \ 'optimizations' print(message) @@ -1346,18 +1357,18 @@ def run_bisect(arguments, prog=sys.argv[0]): # If the libraries were a problem, then reset what the baseline # ground-truth is, especially since we updated the LINK_FLAGS in the # generated Makefiles. - if len(bad_libs) > 0: + if len(differing_libs) > 0: replacements['build_gt_local'] = 'true' try: - bad_sources = search_for_source_problems(args, bisect_path, - replacements, sources) + differing_sources = search_for_source_problems(args, bisect_path, + replacements, sources) except subp.CalledProcessError: print() print(' Executable failed to run.') - print('Failed to search for bad sources -- cannot continue.') - logging.exception('Failed to search for bad sources.') - return bisect_num, bad_libs, None, None, 1 + print('Failed to search for differing sources -- cannot continue.') + logging.exception('Failed to search for differing sources.') + return bisect_num, differing_libs, None, None, 1 if args.biggest is None: print(' all variability inducing source file(s):') @@ -1368,46 +1379,48 @@ def run_bisect(arguments, prog=sys.argv[0]): logging.info('%d HIGHEST VARIABILITY SOURCE FILE%s:', args.biggest, 'S' if args.biggest > 1 else '') - for src in bad_sources: + for src in differing_sources: print(' {} (score {})'.format(src[0], src[1])) logging.info(' %s', src) - if len(bad_sources) == 0: + if len(differing_sources) == 0: print(' None') logging.info(' None') - # Search for bad symbols one bad file at a time + # Search for differing symbols one differing file at a time # This will allow us to maybe find some symbols where crashes before would # cause problems and no symbols would be identified - bad_symbols = [] - for bad_source, _ in bad_sources: + differing_symbols = [] + for differing_source, _ in differing_sources: try: - file_bad_symbols = search_for_symbol_problems( - args, bisect_path, replacements, sources, bad_source) + file_differing_symbols = search_for_symbol_problems( + args, bisect_path, replacements, sources, differing_source) except subp.CalledProcessError: print() print(' Executable failed to run.') - print('Failed to search for bad symbols in {} -- cannot continue' \ - .format(bad_source)) - logging.exception('Failed to search for bad symbols in %s', - bad_source) - bad_symbols.extend(file_bad_symbols) - if len(file_bad_symbols) > 0: + print('Failed to search for differing symbols in {}' + '-- cannot continue'.format(differing_source)) + logging.exception('Failed to search for differing symbols in %s', + differing_source) + differing_symbols.extend(file_differing_symbols) + if len(file_differing_symbols) > 0: if args.biggest is None: - message = ' All bad symbols in {}:'.format(bad_source) + message = ' All differing symbols in {}:'\ + .format(differing_source) else: - message = ' {} bad symbol{} in {}:'.format( - args.biggest, 's' if args.biggest > 1 else '', bad_source) + message = ' {} differing symbol{} in {}:'.format( + args.biggest, 's' if args.biggest > 1 else '', + differing_source) print(message) logging.info(message) - for sym, score in file_bad_symbols: + for sym, score in file_differing_symbols: message = \ ' line {sym.lineno} -- {sym.demangled} (score {score})' \ .format(sym=sym, score=score) print(message) logging.info('%s', message) - bad_symbols.sort(key=lambda x: (-x[1], x[0])) + differing_symbols.sort(key=lambda x: (-x[1], x[0])) if args.biggest is None: print('All variability inducing symbols:') @@ -1416,20 +1429,20 @@ def run_bisect(arguments, prog=sys.argv[0]): print('{} highest variability symbol{} from each found source file:' .format(args.biggest, 's' if args.biggest > 1 else '')) logging.info( - '%d HIGHEST VARIABILITY INDUCING SYMBOL%s FROM EACH FOUND SOURCE FILE:', - args.biggest, 'S' if args.biggest > 1 else '') + '%d HIGHEST VARIABILITY INDUCING SYMBOL%s FROM EACH FOUND SOURCE ' + 'FILE:', args.biggest, 'S' if args.biggest > 1 else '') - for sym, score in bad_symbols: + for sym, score in differing_symbols: message = \ ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled} ' \ '(score {score})'.format(sym=sym, score=score) print(message) logging.info('%s', message) - if len(bad_symbols) == 0: + if len(differing_symbols) == 0: print(' None') logging.info(' None') - return bisect_num, bad_libs, bad_sources, bad_symbols, 0 + return bisect_num, differing_libs, differing_sources, differing_symbols, 0 def auto_bisect_worker(arg_queue, result_queue): ''' @@ -1451,9 +1464,9 @@ def auto_bisect_worker(arg_queue, result_queue): - compiler: (str) compiler used - optl: (str) optimization level - switches: (str) switches - - libs: (list of str) bad libraries found - - srcs: (list of str) bad source files found - - syms: (list of SymbolTuple) bad symbols found + - libs: (list of str) differing libraries found + - srcs: (list of str) differing source files found + - syms: (list of SymbolTuple) differing symbols found - ret: (int) return code of running @return None diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index a747d641..30599b21 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -125,27 +125,28 @@ Verify that all source files were found and output during the search >>> sorted([x.split(':')[0].split()[-1] for x in bisect_out -... if x.startswith(' Found bad source file')]) +... if x.startswith(' Found differing source file')]) ['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] -Verify that the three bad sources were output in the "bad sources:" section +Verify that the three differing sources were output in the "differing sources:" +section >>> idx = bisect_out.index(' all variability inducing source file(s):') >>> print('\\n'.join(bisect_out[idx+1:idx+4])) tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) tests/file3.cpp (score 4.0) ->>> bisect_out[idx+4].startswith('Searching for bad symbols in:') +>>> bisect_out[idx+4].startswith('Searching for differing symbols in:') True Verify that all three files were searched individually >>> sorted([x.split()[-1] for x in bisect_out -... if x.startswith('Searching for bad symbols in:')]) +... if x.startswith('Searching for differing symbols in:')]) ['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] Verify all functions were identified during the symbol searches >>> print('\\n'.join( ... sorted([' '.join(x.split()[-6:]) for x in bisect_out -... if x.startswith(' Found bad symbol on line')]))) +... if x.startswith(' Found differing symbol on line')]))) line 100 -- file1_func3_PROBLEM() (score 2.0) line 103 -- file3_func5_PROBLEM() (score 3.0) line 108 -- file1_func4_PROBLEM() (score 3.0) @@ -153,8 +154,8 @@ line 92 -- file1_func2_PROBLEM() (score 5.0) line 92 -- file3_func2_PROBLEM() (score 1.0) -Verify the bad symbols section for file1.cpp ->>> idx = bisect_out.index(' All bad symbols in tests/file1.cpp:') +Verify the differing symbols section for file1.cpp +>>> idx = bisect_out.index(' All differing symbols in tests/file1.cpp:') >>> print('\\n'.join(bisect_out[idx+1:idx+4])) line 92 -- file1_func2_PROBLEM() (score 5.0) line 108 -- file1_func4_PROBLEM() (score 3.0) @@ -162,22 +163,22 @@ >>> bisect_out[idx+4].startswith(' ') False -Verify the bad symbols section for file2.cpp ->>> idx = bisect_out.index(' All bad symbols in tests/file2.cpp:') +Verify the differing symbols section for file2.cpp +>>> idx = bisect_out.index(' All differing symbols in tests/file2.cpp:') >>> bisect_out[idx+1] ' line 91 -- file2_func1_PROBLEM() (score 7.0)' >>> bisect_out[idx+2].startswith(' ') False -Verify the bad symbols section for file3.cpp ->>> idx = bisect_out.index(' All bad symbols in tests/file3.cpp:') +Verify the differing symbols section for file3.cpp +>>> idx = bisect_out.index(' All differing symbols in tests/file3.cpp:') >>> print('\\n'.join(bisect_out[idx+1:idx+3])) line 103 -- file3_func5_PROBLEM() (score 3.0) line 92 -- file3_func2_PROBLEM() (score 1.0) >>> bisect_out[idx+3].startswith(' ') False -Test the All bad symbols section of the output +Test the All differing symbols section of the output >>> idx = bisect_out.index('All variability inducing symbols:') >>> print('\\n'.join(bisect_out[idx+1:])) # doctest:+ELLIPSIS /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() (score 7.0) @@ -188,78 +189,79 @@ /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) Example output to be expected: - Updating ground-truth results - ground-truth.csv - done -Searching for bad source files: +Searching for differing source files: Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 - Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 10.0 + Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 14.0 Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 0.0 Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 10.0 - Found bad source file tests/file1.cpp: score 10.0 + Found differing source file tests/file1.cpp: score 10.0 Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 11.0 Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 4.0 - Found bad source file tests/file3.cpp: score 4.0 - Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-08.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-09.mk - compiling and running - score 7.0 - Found bad source file tests/file2.cpp: score 7.0 - Created /.../bisect-01/bisect-make-10.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 4.0 + Found differing source file tests/file3.cpp: score 4.0 + Created /.../bisect-01/bisect-make-08.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-09.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-10.mk - compiling and running - score 7.0 + Found differing source file tests/file2.cpp: score 7.0 + Created /.../bisect-01/bisect-make-11.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-12.mk - compiling and running - score 0.0 all variability inducing source file(s): tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) tests/file3.cpp (score 4.0) -Searching for bad symbols in: tests/file1.cpp - Created /.../bisect-01/bisect-make-11.mk - compiling and running - score 10.0 - Created /.../bisect-01/bisect-make-12.mk - compiling and running - score 5.0 - Created /.../bisect-01/bisect-make-13.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-14.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-15.mk - compiling and running - score 5.0 - Found bad symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - Created /.../bisect-01/bisect-make-16.mk - compiling and running - score 5.0 +Searching for differing symbols in: tests/file1.cpp + Created /.../bisect-01/bisect-make-13.mk - compiling and running - score 10.0 + Created /.../bisect-01/bisect-make-14.mk - compiling and running - score 5.0 + Created /.../bisect-01/bisect-make-15.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-16.mk - compiling and running - score 0.0 Created /.../bisect-01/bisect-make-17.mk - compiling and running - score 5.0 - Created /.../bisect-01/bisect-make-18.mk - compiling and running - score 2.0 - Found bad symbol on line 100 -- file1_func3_PROBLEM() (score 2.0) - Created /.../bisect-01/bisect-make-19.mk - compiling and running - score 3.0 - Created /.../bisect-01/bisect-make-20.mk - compiling and running - score 3.0 - Found bad symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) - Created /.../bisect-01/bisect-make-21.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-22.mk - compiling and running - score 0.0 - All bad symbols in tests/file1.cpp: + Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) + Created /.../bisect-01/bisect-make-18.mk - compiling and running - score 5.0 + Created /.../bisect-01/bisect-make-19.mk - compiling and running - score 5.0 + Created /.../bisect-01/bisect-make-20.mk - compiling and running - score 2.0 + Found differing symbol on line 100 -- file1_func3_PROBLEM() (score 2.0) + Created /.../bisect-01/bisect-make-21.mk - compiling and running - score 3.0 + Created /.../bisect-01/bisect-make-22.mk - compiling and running - score 3.0 + Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) + Created /.../bisect-01/bisect-make-23.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-24.mk - compiling and running - score 0.0 + All differing symbols in tests/file1.cpp: line 92 -- file1_func2_PROBLEM() (score 5.0) line 108 -- file1_func4_PROBLEM() (score 3.0) line 100 -- file1_func3_PROBLEM() (score 2.0) -Searching for bad symbols in: tests/file2.cpp - Created /.../bisect-01/bisect-make-23.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-24.mk - compiling and running - score 0.0 +Searching for differing symbols in: tests/file2.cpp Created /.../bisect-01/bisect-make-25.mk - compiling and running - score 7.0 Created /.../bisect-01/bisect-make-26.mk - compiling and running - score 0.0 Created /.../bisect-01/bisect-make-27.mk - compiling and running - score 7.0 - Found bad symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) Created /.../bisect-01/bisect-make-28.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-29.mk - compiling and running - score 0.0 - All bad symbols in tests/file2.cpp: - line 91 -- file2_func1_PROBLEM() (score 7.0) -Searching for bad symbols in: tests/file3.cpp - Created /.../bisect-01/bisect-make-30.mk - compiling and running - score 4.0 + Created /.../bisect-01/bisect-make-29.mk - compiling and running - score 7.0 + Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Created /.../bisect-01/bisect-make-30.mk - compiling and running - score 0.0 Created /.../bisect-01/bisect-make-31.mk - compiling and running - score 0.0 + All differing symbols in tests/file2.cpp: + line 91 -- file2_func1_PROBLEM() (score 7.0) +Searching for differing symbols in: tests/file3.cpp Created /.../bisect-01/bisect-make-32.mk - compiling and running - score 4.0 - Created /.../bisect-01/bisect-make-33.mk - compiling and running - score 1.0 - Found bad symbol on line 92 -- file3_func2_PROBLEM() (score 1.0) - Created /.../bisect-01/bisect-make-34.mk - compiling and running - score 3.0 - Created /.../bisect-01/bisect-make-35.mk - compiling and running - score 3.0 - Found bad symbol on line 103 -- file3_func5_PROBLEM() (score 3.0) - Created /.../bisect-01/bisect-make-36.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-37.mk - compiling and running - score 0.0 - All bad symbols in tests/file3.cpp: + Created /.../bisect-01/bisect-make-33.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-34.mk - compiling and running - score 4.0 + Created /.../bisect-01/bisect-make-35.mk - compiling and running - score 1.0 + Found differing symbol on line 92 -- file3_func2_PROBLEM() (score 1.0) + Created /.../bisect-01/bisect-make-36.mk - compiling and running - score 3.0 + Created /.../bisect-01/bisect-make-37.mk - compiling and running - score 3.0 + Found differing symbol on line 103 -- file3_func5_PROBLEM() (score 3.0) + Created /.../bisect-01/bisect-make-38.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-39.mk - compiling and running - score 0.0 + All differing symbols in tests/file3.cpp: line 103 -- file3_func5_PROBLEM() (score 3.0) line 92 -- file3_func2_PROBLEM() (score 1.0) All variability inducing symbols: - /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() (score 7.0) - /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) - /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) - /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) - /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) - /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) + /.../tests/file2.cpp:91 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) + /.../tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) + /.../tests/file1.cpp:108 _Z19file1_func4_PROBLEMv -- file1_func4_PROBLEM() (score 3.0) + /.../tests/file3.cpp:103 _Z19file3_func5_PROBLEMv -- file3_func5_PROBLEM() (score 3.0) + /.../tests/file1.cpp:100 _Z19file1_func3_PROBLEMv -- file1_func3_PROBLEM() (score 2.0) + /.../tests/file3.cpp:92 _Z19file3_func2_PROBLEMv -- file3_func2_PROBLEM() (score 1.0) TODO: test the log_contents variable TODO: test the -k flag From f34ae4440a139c0cc0e805a79431e519469517c2 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 11 Aug 2018 14:24:27 -0600 Subject: [PATCH 053/196] bisect: finish implementing finding the k biggest --- scripts/flitcli/flit_bisect.py | 224 +++++++++++++++++++++++--------- tests/flit_bisect/tst_bisect.py | 8 +- 2 files changed, 166 insertions(+), 66 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 81d3e220..1681e50e 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1086,6 +1086,7 @@ def search_for_source_problems(args, bisect_path, replacements, sources): ''' Performs the search over the space of source files for problems. ''' + memoized_checker = _gen_bisect_source_checker(args, bisect_path, replacements, sources) @@ -1105,18 +1106,13 @@ def search_for_source_problems(args, bisect_path, replacements, sources): differing_source_msg = ' Found differing source file {}: score {}' differing_source_callback = lambda filename, score: \ util.printlog(differing_source_msg.format(filename, score)) - if args.biggest is None: - differing_sources = bisect_search( - memoized_checker, sources, - found_callback=differing_source_callback) - else: - differing_sources = bisect_biggest( - memoized_checker, sources, - found_callback=differing_source_callback, k=args.biggest) + differing_sources = bisect_search(memoized_checker, sources, + found_callback=differing_source_callback) return differing_sources def search_for_symbol_problems(args, bisect_path, replacements, sources, - differing_source): + differing_source, found_callback=None, + indent=''): ''' Performs the search over the space of symbols within differing source files for problems. @@ -1127,29 +1123,40 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, @param sources: all source files @param differing_source: the one differing source file to search for differing symbols - - @return a list of identified differing symbols (if any) + @param found_callback: (optional) a callback to be called on each found + symbol + @param indent: (optional) indentation to use for the logging and printing + messages + + @return a list of identified differing symbols (if any), with their + associated scores + [(symbol, score), ...] ''' - print('Searching for differing symbols in:', differing_source) - logging.info('Searching for differing symbols in: %s', differing_source) - logging.info('Note: inlining disabled to isolate functions') - logging.info('Note: only searching over globally exported functions') - logging.debug('Symbols:') + print('{}Searching for differing symbols in: {}'.format( + indent, differing_source)) + logging.info('%sSearching for differing symbols in: %s', differing_source, + indent) + logging.info('%sNote: inlining disabled to isolate functions', indent) + logging.info('%sNote: only searching over globally exported functions', + indent) + logging.debug('%sSymbols:', indent) symbol_tuples = extract_symbols(differing_source, os.path.join(args.directory, 'obj')) for sym in symbol_tuples: - message = ' {sym.fname}:{sym.lineno} {sym.symbol} -- {sym.demangled}' \ - .format(sym=sym) - logging.info('%s', message) + message = '{indent} {sym.fname}:{sym.lineno} {sym.symbol} ' \ + '-- {sym.demangled}'.format(indent=indent, sym=sym) + logging.debug('%s', message) memoized_checker = _gen_bisect_symbol_checker( - args, bisect_path, replacements, sources, symbol_tuples) + args, bisect_path, replacements, sources, symbol_tuples, + indent=indent + ' ') # Check to see if -fPIC destroyed any chance of finding any differing # symbols if not memoized_checker(symbol_tuples): - message_1 = ' Warning: -fPIC compilation destroyed the optimization' - message_2 = ' Cannot find any trouble symbols' + message_1 = '{} Warning: -fPIC compilation destroyed the ' \ + 'optimization'.format(indent) + message_2 = '{} Cannot find any trouble symbols'.format(indent) print(message_1) print(message_2) logging.warning('%s', message_1) @@ -1157,10 +1164,16 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, return [] differing_symbol_msg = \ - ' Found differing symbol on line {sym.lineno} -- ' \ + '{indent} Found differing symbol on line {sym.lineno} -- ' \ '{sym.demangled} (score {score})' - differing_symbol_callback = lambda sym, score: \ - util.printlog(differing_symbol_msg.format(sym=sym, score=score)) + + def differing_symbol_callback(sym, score): + 'Prints the finding and calls the registered callback' + util.printlog(differing_symbol_msg.format(sym=sym, score=score, + indent=indent)) + if found_callback is not None: + found_callback(sym, score) + if args.biggest is None: differing_symbols = bisect_search( memoized_checker, symbol_tuples, @@ -1171,6 +1184,86 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, found_callback=differing_symbol_callback, k=args.biggest) return differing_symbols +def search_for_k_most_diff_symbols(args, bisect_path, replacements, sources): + ''' + This function is similar to both search_for_source_problems() and + search_for_symbol_problems(). This function will search for source + problems AND also symbol problems such that the top k differing functions + between the baseline compilation and the variability-inducing optimized + compilation. + + @param args: parsed command-line arguments + @param bisect_path: directory where bisect is being performed + @param replacements: dictionary of values to use in generating the Makefile + @param sources: all source files + + @return a list of identified differing symbols (if any), with their + associated scores + [(symbol, score), ...] + ''' + assert args.biggest is not None + assert args.biggest > 0 + + util.printlog('Looking for the top {} different symbol(s) by starting with ' + 'files'.format(args.biggest)) + + differing_symbols = [] + differing_source_msg = ' Found differing source file {}: score {}' + differing_sources = [] + + class ExitEarlyException(Exception): + 'Exception used to exit early from bisect search' + pass + + def differing_symbol_callback(symbol, score): + 'captures the symbol and checks for early termination' + assert len(differing_symbols) <= args.biggest + assert score > 0 + + if len(differing_symbols) >= args.biggest and \ + score < differing_symbols[-1][1]: + # exit early because we're done with this file + raise ExitEarlyException + differing_symbols.append((symbol, score)) + differing_symbols[:] = sorted(differing_symbols[:args.biggest], + key=lambda x: -x[1]) + + symbol_search = lambda differing_source: \ + search_for_symbol_problems( + args, bisect_path, replacements, sources, differing_source, + found_callback=differing_symbol_callback, indent=' ') + + def differing_source_callback(filename, score): + ''' + prints and captures the found source file, and checks for early + termination. + ''' + assert len(differing_symbols) <= args.biggest + assert score > 0 + + util.printlog(differing_source_msg.format(filename, score)) + differing_sources.append((filename, score)) + if len(differing_symbols) >= args.biggest and \ + score < differing_symbols[-1][1]: + # exit early because we're done with this file + raise ExitEarlyException + + try: + symbol_search(filename) + except ExitEarlyException: + pass + + memoized_source_checker = _gen_bisect_source_checker( + args, bisect_path, replacements, sources) + try: + # Note: ignore return because we already capture found sources + bisect_biggest(memoized_source_checker, sources, k=len(sources), + found_callback=differing_source_callback) + except ExitEarlyException: + pass + + return differing_sources, differing_symbols + def compile_trouble(directory, compiler, optl, switches, verbose=False, jobs=mp.cpu_count(), delete=True): ''' @@ -1361,8 +1454,13 @@ def run_bisect(arguments, prog=sys.argv[0]): replacements['build_gt_local'] = 'true' try: - differing_sources = search_for_source_problems(args, bisect_path, - replacements, sources) + if args.biggest is not None: + differing_sources, differing_symbols = \ + search_for_k_most_diff_symbols(args, bisect_path, + replacements, sources) + else: + differing_sources = search_for_source_problems( + args, bisect_path, replacements, sources) except subp.CalledProcessError: print() print(' Executable failed to run.') @@ -1371,54 +1469,56 @@ def run_bisect(arguments, prog=sys.argv[0]): return bisect_num, differing_libs, None, None, 1 if args.biggest is None: - print(' all variability inducing source file(s):') + print('all variability inducing source file(s):') logging.info('ALL VARIABILITY INCUDING SOURCE FILE(S):') else: - print(' {} highest variability source file{}:'.format( - args.biggest, 's' if args.biggest > 1 else '')) + print('found highest variability inducing source file{}:'.format( + 's' if len(differing_sources) > 1 else '')) logging.info('%d HIGHEST VARIABILITY SOURCE FILE%s:', args.biggest, 'S' if args.biggest > 1 else '') for src in differing_sources: - print(' {} (score {})'.format(src[0], src[1])) - logging.info(' %s', src) + util.printlog(' {} (score {})'.format(src[0], src[1])) if len(differing_sources) == 0: - print(' None') - logging.info(' None') - + util.printlog(' None') # Search for differing symbols one differing file at a time # This will allow us to maybe find some symbols where crashes before would # cause problems and no symbols would be identified - differing_symbols = [] - for differing_source, _ in differing_sources: - try: - file_differing_symbols = search_for_symbol_problems( - args, bisect_path, replacements, sources, differing_source) - except subp.CalledProcessError: - print() - print(' Executable failed to run.') - print('Failed to search for differing symbols in {}' - '-- cannot continue'.format(differing_source)) - logging.exception('Failed to search for differing symbols in %s', - differing_source) - differing_symbols.extend(file_differing_symbols) - if len(file_differing_symbols) > 0: - if args.biggest is None: - message = ' All differing symbols in {}:'\ - .format(differing_source) - else: - message = ' {} differing symbol{} in {}:'.format( - args.biggest, 's' if args.biggest > 1 else '', + # + # Only do this if we didn't already perform the search above with + # search_for_k_most_diff_symbols() + if args.biggest is None: + differing_symbols = [] + for differing_source, _ in differing_sources: + try: + file_differing_symbols = search_for_symbol_problems( + args, bisect_path, replacements, sources, differing_source) + except subp.CalledProcessError: + print() + print(' Executable failed to run.') + print('Failed to search for differing symbols in {}' + '-- cannot continue'.format(differing_source)) + logging.exception( + 'Failed to search for differing symbols in %s', differing_source) - print(message) - logging.info(message) - for sym, score in file_differing_symbols: - message = \ - ' line {sym.lineno} -- {sym.demangled} (score {score})' \ - .format(sym=sym, score=score) + differing_symbols.extend(file_differing_symbols) + if len(file_differing_symbols) > 0: + if args.biggest is None: + message = ' All differing symbols in {}:'\ + .format(differing_source) + else: + message = ' {} differing symbol{} in {}:'.format( + args.biggest, 's' if args.biggest > 1 else '', + differing_source) print(message) - logging.info('%s', message) + logging.info(message) + for sym, score in file_differing_symbols: + message = \ + ' line {sym.lineno} -- {sym.demangled} ' \ + '(score {score})'.format(sym=sym, score=score) + print(message) + logging.info('%s', message) differing_symbols.sort(key=lambda x: (-x[1], x[0])) diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index 30599b21..60a73962 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -130,11 +130,11 @@ Verify that the three differing sources were output in the "differing sources:" section ->>> idx = bisect_out.index(' all variability inducing source file(s):') +>>> idx = bisect_out.index('all variability inducing source file(s):') >>> print('\\n'.join(bisect_out[idx+1:idx+4])) - tests/file1.cpp (score 10.0) - tests/file2.cpp (score 7.0) - tests/file3.cpp (score 4.0) + tests/file1.cpp (score 10.0) + tests/file2.cpp (score 7.0) + tests/file3.cpp (score 4.0) >>> bisect_out[idx+4].startswith('Searching for differing symbols in:') True From 02bedd5248f49842893ddc1c232c3f535baf3ac7 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 11 Aug 2018 14:30:45 -0600 Subject: [PATCH 054/196] bisect: clarify help docs for --biggest --- scripts/flitcli/flit_bisect.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 1681e50e..9f88cfec 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -886,14 +886,28 @@ def parse_args(arguments, prog=sys.argv[0]): ''') parser.add_argument('-k', '--biggest', metavar='K', type=int, default=None, help=''' - Instead of returning all of the offenders of - variability, only return the largest K offenders, - with their contribution to variability. If K is - close to the total number of offenders, then this - is a much slower approach than the full algorithm. + Instead of finding and returning all symbols that + cause variability, only return the largest K + contributors, with their contribution to + variability. If K is close to the total number of + total contributing functions, then this is a much + slower approach in general than the full algorithm. It is best if K is small. This value used comes from the custom comparison function you provide for your flit test. + + Note: many files (perhaps more than K, although + possibly less than K) may be found during the + search. This is done to ensure that the symbols + identified are the largest contributors that are + identifiable through this approach. + + Also note that using the --biggest flag, you + restrict the search space to only singleton + contributors. That means that if there is a pair + of contributors that only contribute when they are + both compiled with the given compilation, then they + produce a measurable variation. ''') args = parser.parse_args(arguments) From 0d6dde04cc7db1e1933b7e9045972d32cb3e1cc4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 11 Aug 2018 16:16:48 -0600 Subject: [PATCH 055/196] bisect: fix the --biggest implementation and create unit tests --- scripts/flitcli/flit_bisect.py | 13 +- tests/flit_bisect/tst_bisect_biggest.py | 249 ++++++++++++++++++++++++ 2 files changed, 255 insertions(+), 7 deletions(-) create mode 100644 tests/flit_bisect/tst_bisect_biggest.py diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 9f88cfec..3b2fba2a 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1239,8 +1239,8 @@ def differing_symbol_callback(symbol, score): # exit early because we're done with this file raise ExitEarlyException differing_symbols.append((symbol, score)) - differing_symbols[:] = sorted(differing_symbols[:args.biggest], - key=lambda x: -x[1]) + differing_symbols.sort(key=lambda x: -x[1]) + differing_symbols[:] = differing_symbols[:args.biggest] symbol_search = lambda differing_source: \ search_for_symbol_problems( @@ -1486,7 +1486,7 @@ def run_bisect(arguments, prog=sys.argv[0]): print('all variability inducing source file(s):') logging.info('ALL VARIABILITY INCUDING SOURCE FILE(S):') else: - print('found highest variability inducing source file{}:'.format( + print('The found highest variability inducing source file{}:'.format( 's' if len(differing_sources) > 1 else '')) logging.info('%d HIGHEST VARIABILITY SOURCE FILE%s:', args.biggest, 'S' if args.biggest > 1 else '') @@ -1540,11 +1540,10 @@ def run_bisect(arguments, prog=sys.argv[0]): print('All variability inducing symbols:') logging.info('ALL VARIABILITY INCUDING SYMBOLS:') else: - print('{} highest variability symbol{} from each found source file:' + print('The {} highest variability symbol{}:' .format(args.biggest, 's' if args.biggest > 1 else '')) - logging.info( - '%d HIGHEST VARIABILITY INDUCING SYMBOL%s FROM EACH FOUND SOURCE ' - 'FILE:', args.biggest, 'S' if args.biggest > 1 else '') + logging.info('THE %d HIGHEST VARIABILITY INDUCING SYMBOL%s:', + args.biggest, 'S' if args.biggest > 1 else '') for sym, score in differing_symbols: message = \ diff --git a/tests/flit_bisect/tst_bisect_biggest.py b/tests/flit_bisect/tst_bisect_biggest.py new file mode 100644 index 00000000..31998f24 --- /dev/null +++ b/tests/flit_bisect/tst_bisect_biggest.py @@ -0,0 +1,249 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests FLiT's capabilities to run bisect and identify the problem files and +functions + +The tests are below using doctest + +Let's now make a temporary directory and test that we can successfully compile +and run FLiT bisect + +>>> import glob +>>> import os +>>> import shutil +>>> import subprocess as subp +>>> from io import StringIO + +>>> with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... shutil.rmtree(os.path.join(temp_dir, 'tests')) +... _ = shutil.copytree(os.path.join('data', 'tests'), +... os.path.join(temp_dir, 'tests')) +... with StringIO() as ostream: +... _ = th.flit.main(['bisect', '-C', temp_dir, +... '--precision', 'double', +... 'g++ -O3', 'BisectTest', +... '--biggest', '1'], +... outstream=ostream) +... bisect_out_1 = ostream.getvalue().splitlines() +... with StringIO() as ostream: +... _ = th.flit.main(['bisect', '-C', temp_dir, +... '--precision', 'double', +... 'g++ -O3', 'BisectTest', +... '--biggest', '2'], +... outstream=ostream) +... bisect_out_2 = ostream.getvalue().splitlines() +... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: +... log_contents = fin.readlines() + +Verify the output of flit init +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating /.../flit-config.toml +Creating /.../custom.mk +Creating /.../main.cpp +Creating /.../tests/Empty.cpp +Creating /.../Makefile + +>>> print('\\n'.join(bisect_out_1)) # doctest:+ELLIPSIS +Updating ground-truth results - ground-truth.csv - done +Looking for the top 1 different symbol(s) by starting with files + Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 + Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 14.0 + Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 14.0 + Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 10.0 + Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 4.0 + Found differing source file tests/file1.cpp: score 10.0 + Searching for differing symbols in: tests/file1.cpp + Created ... + ... + Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) + Created /.../bisect-01/bisect-make-15.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-16.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-17.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-18.mk - compiling and running - score 0.0 + Found differing source file tests/file2.cpp: score 7.0 + Searching for differing symbols in: tests/file2.cpp + Created ... + ... + Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Found differing source file tests/file3.cpp: score 4.0 +found highest variability inducing source files: + tests/file1.cpp (score 10.0) + tests/file2.cpp (score 7.0) + tests/file3.cpp (score 4.0) +1 highest variability symbol from each found source file: + /.../tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) + + +>>> print('\\n'.join(bisect_out_1)) # doctest:+ELLIPSIS +Updating ground-truth results - ground-truth.csv - done +Looking for the top 1 different symbol(s) by starting with files + Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 + Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 14.0 + Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 14.0 + Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 10.0 + Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 4.0 + Found differing source file tests/file1.cpp: score 10.0 + Searching for differing symbols in: tests/file1.cpp + Created ... + ... + Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) + Created /.../bisect-01/bisect-make-...mk - compiling and running - score 0.0 + Created /.../bisect-01/bisect-make-...mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-...mk - compiling and running - score 7.0 + Created /.../bisect-01/bisect-make-...mk - compiling and running - score 0.0 + Found differing source file tests/file2.cpp: score 7.0 + Searching for differing symbols in: tests/file2.cpp + Created ... + ... + Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Found differing source file tests/file3.cpp: score 4.0 +The found highest variability inducing source files: + tests/file1.cpp (score 10.0) + tests/file2.cpp (score 7.0) + tests/file3.cpp (score 4.0) +The 1 highest variability symbol: + /.../tests/file2.cpp:91 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) + +>>> print('\\n'.join(bisect_out_2)) # doctest:+ELLIPSIS +Updating ground-truth results - ground-truth.csv - done +Looking for the top 2 different symbol(s) by starting with files + Created /.../bisect-02/bisect-make-01.mk - compiling and running - score 21.0 + Created /.../bisect-02/bisect-make-02.mk - compiling and running - score 14.0 + Created /.../bisect-02/bisect-make-03.mk - compiling and running - score 7.0 + Created /.../bisect-02/bisect-make-04.mk - compiling and running - score 0.0 + Created /.../bisect-02/bisect-make-05.mk - compiling and running - score 14.0 + Created /.../bisect-02/bisect-make-06.mk - compiling and running - score 10.0 + Created /.../bisect-02/bisect-make-07.mk - compiling and running - score 4.0 + Found differing source file tests/file1.cpp: score 10.0 + Searching for differing symbols in: tests/file1.cpp + Created ... + ... + Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) + Created ... + ... + Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) + Created /.../bisect-02/bisect-make-...mk - compiling and running - score 0.0 + Created /.../bisect-02/bisect-make-...mk - compiling and running - score 7.0 + Created /.../bisect-02/bisect-make-...mk - compiling and running - score 7.0 + Created /.../bisect-02/bisect-make-...mk - compiling and running - score 0.0 + Found differing source file tests/file2.cpp: score 7.0 + Searching for differing symbols in: tests/file2.cpp + Created ... + ... + Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Found differing source file tests/file3.cpp: score 4.0 +The found highest variability inducing source files: + tests/file1.cpp (score 10.0) + tests/file2.cpp (score 7.0) + tests/file3.cpp (score 4.0) +The 2 highest variability symbols: + /.../tests/file2.cpp:91 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) + /.../tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) + +TODO: Test the log_contents variable + +TODO: This test takes about a whole minute on my laptop. Let's create mocks +TODO- and stubs to eliminate the dependence on the compiler. The interaction +TODO- with the real compiler is already tested in tst_bisect.py, so we can +TODO- safely stub it out here. +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From 991506f71fa35f132b306d5cc6dce850e280a998 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 11 Aug 2018 23:34:52 -0600 Subject: [PATCH 056/196] tst_bisect_biggest: stub out actual compilations This improves the performance of the test from about 40 seconds to about 5 seconds. --- tests/flit_bisect/tst_bisect_biggest.py | 110 +++++++++++++++++++++--- 1 file changed, 100 insertions(+), 10 deletions(-) diff --git a/tests/flit_bisect/tst_bisect_biggest.py b/tests/flit_bisect/tst_bisect_biggest.py index 31998f24..b9d42ddf 100644 --- a/tests/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_bisect/tst_bisect_biggest.py @@ -95,6 +95,88 @@ >>> import subprocess as subp >>> from io import StringIO +let's stub out some functions that actually confer with the compiler. These +make the test take way too long and that interaction has already been tested in +tst_bisect.py. + +>>> flit_bisect = th._path_import(th._script_dir, 'flit_bisect') +>>> util = th._path_import(th._script_dir, 'flitutil') +>>> Sym = flit_bisect.SymbolTuple +>>> def create_symbol(fileno, funcno, lineno, isproblem): +... prob_str = '_PROBLEM' if isproblem else '' +... filename = 'tests/file{}.cpp'.format(fileno) +... funcname = 'file{}_func{}{}'.format(fileno, funcno, prob_str) +... return Sym(filename, +... '_Z19{}z'.format(funcname), +... funcname + '()', +... filename, +... lineno) + +>>> all_file_scores = { +... 'main.cpp': 0.0, +... 'tests/BisectTest.cpp': 0.0, +... 'tests/file1.cpp': 10.0, +... 'tests/file2.cpp': 7.0, +... 'tests/file3.cpp': 4.0, +... } + +>>> all_symbol_scores = { +... create_symbol(1, 1, 90, False): 0.0, +... create_symbol(1, 2, 92, True): 5.0, +... create_symbol(1, 3, 100, True): 2.0, +... create_symbol(1, 4, 108, True): 3.0, +... create_symbol(1, 5, 116, False): 5.0, +... create_symbol(2, 1, 90, True): 7.0, +... create_symbol(2, 2, 98, False): 0.0, +... create_symbol(2, 3, 99, False): 0.0, +... create_symbol(2, 4, 100, False): 0.0, +... create_symbol(2, 5, 101, False): 0.0, +... create_symbol(3, 1, 90, False): 0.0, +... create_symbol(3, 2, 92, True): 1.0, +... create_symbol(3, 3, 100, False): 0.0, +... create_symbol(3, 4, 101, False): 0.0, +... create_symbol(3, 5, 103, True): 3.0, +... } + +>>> def build_bisect_stub(makepath, directory, target='bisect', verbose=False, +... jobs=None): +... assert target == 'bisect' +... assert verbose == False +... # Get the files being tested out of the makepath, and the BISECT_RESULT +... # variable, and generate the expected results. +... sources = util.extract_make_var('TROUBLE_SRC', makepath) +... symbol_files = util.extract_make_var('TROUBLE_SYMBOLS', makepath) +... symbols = [] +... if symbol_files: +... with open(os.path.join(directory, symbol_files[0]), 'r') as fin: +... symbols = [x.strip() for x in fin.readlines()] +... source_score = sum([all_file_scores[x] for x in sources]) +... symbol_score = sum([score for symbol, score in all_symbol_scores.items() +... if symbol.symbol in symbols]) +... result_file = util.extract_make_var('BISECT_RESULT', makepath)[0] +... with open(os.path.join(directory, result_file), 'w') as rout: +... rout.write('comparison\\n') +... rout.write('{}\\n'.format(source_score + symbol_score)) + +>>> def update_gt_results_stub(directory, verbose=False, jobs=4): +... # do nothing +... pass + +>>> def extract_symbols_stub(file_or_filelist, objdir): +... symbol_tuples = [] +... if not isinstance(file_or_filelist, str): +... for fname in file_or_filelist: +... symbol_tuples.extend(extract_symbols_stub(fname, objdir)) +... return symbol_tuples +... +... return [x for x in all_symbol_scores if x.fname == file_or_filelist] + +>>> flit_bisect.build_bisect = build_bisect_stub +>>> flit_bisect.update_gt_results = update_gt_results_stub +>>> flit_bisect.extract_symbols = extract_symbols_stub + +Now for the test after we stubbed a single file + >>> with th.tempdir() as temp_dir: ... with StringIO() as ostream: ... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) @@ -103,18 +185,26 @@ ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) ... with StringIO() as ostream: -... _ = th.flit.main(['bisect', '-C', temp_dir, -... '--precision', 'double', -... 'g++ -O3', 'BisectTest', -... '--biggest', '1'], -... outstream=ostream) +... try: +... oldout = sys.stdout +... sys.stdout = ostream +... _ = flit_bisect.main(['--directory', temp_dir, +... '--precision', 'double', +... 'g++ -O3', 'BisectTest', +... '--biggest', '1']) +... finally: +... sys.stdout = oldout ... bisect_out_1 = ostream.getvalue().splitlines() ... with StringIO() as ostream: -... _ = th.flit.main(['bisect', '-C', temp_dir, -... '--precision', 'double', -... 'g++ -O3', 'BisectTest', -... '--biggest', '2'], -... outstream=ostream) +... try: +... oldout = sys.stdout +... sys.stdout = ostream +... _ = flit_bisect.main(['--directory', temp_dir, +... '--precision', 'double', +... 'g++ -O3', 'BisectTest', +... '--biggest', '2']) +... finally: +... sys.stdout = oldout ... bisect_out_2 = ostream.getvalue().splitlines() ... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: ... log_contents = fin.readlines() From e5cc650d654547f1357254d3c4e00d402ece0d9e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 13 Aug 2018 18:09:09 -0600 Subject: [PATCH 057/196] Distributivity: remove long double test values None of them provided variability anyway. We will want another issue to track to find and add values back in for long double for DistributivityOfMultiplication. --- .../tests/DistributivityOfMultiplication.cpp | 49 +------------------ 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/litmus-tests/tests/DistributivityOfMultiplication.cpp b/litmus-tests/tests/DistributivityOfMultiplication.cpp index 90686a66..e80714f1 100644 --- a/litmus-tests/tests/DistributivityOfMultiplication.cpp +++ b/litmus-tests/tests/DistributivityOfMultiplication.cpp @@ -243,53 +243,8 @@ DistributivityOfMultiplication::getDefaultInput() { return flit::as_float(val); }; - // Put in canned values of previously found diverging inputs - // These are entered as hex values to maintain the exact value instead of trying - // to specify enough decimal digits to get the same floating-point value - std::vector ti = { - // 0x663B40322A41D3AE972B - convert(0x2B97, 0xAED3412A32403B66), // 3.586714e-1573 - convert(0x7257, 0xA605064F0279F445), // 6.131032e+3879 - convert(0x0759, 0xBC91B5B4C128340B), // 4.278225e-4366 - - convert(0x3408, 0xD9877B209C448671), // 1.497721e-922 - convert(0x7DA3, 0xCB6A9713AF8B33A1), // 2.847787e+4750 - convert(0x376A, 0xFA52E8978C6C9B9C), // 8.479921e-662 - - convert(0x2355, 0xB32CA7EC5E694CA3), // 1.541551e-2209 - convert(0x7336, 0x90ABC4405309DE21), // 7.201858e+3946 - convert(0x736A, 0xAC4F344252296368), // 3.863064e+3962 - - convert(0x4727, 0x9C8F926F9D81F76F), // 3.753403e+551 - convert(0x02E5, 0xEDD4EED5EB8D326F), // 3.612998e-4709 - convert(0x485B, 0xEAE81D2B24F2F2D4), // 2.936812e+644 - - convert(0x1B91, 0x9E18DE75A88B8EFF), // 4.852600e-2808 - convert(0x205E, 0xB156306D61A021F2), // 5.031688e-2438 - convert(0x4A47, 0xDC5062844DCD1D50), // 3.521930e+792 - - convert(0x4178, 0xD2CEE24A186FAE99), // 5.069741e+113 - convert(0x3563, 0xB080DC1B4056BCFC), // 3.483973e-818 - convert(0x150A, 0x92CDDFF068A532AC), // 4.292064e-3311 - - convert(0x1964, 0xC6108B7B0B1846FF), // 1.288694e-2975 - convert(0x004B, 0xDC569B288F230CA5), // 1.093228e-4909 - convert(0x380F, 0x92B14C59FBC79205), // 2.324058e-612 - - convert(0x4492, 0x870E87461590FB53), // 3.384007e+352 - convert(0x71DA, 0xAC9981EE164A3F4A), // 1.498527e+3842 - convert(0x586A, 0xFC38E006060C3819), // 1.079136e+1882 - - convert(0x240D, 0xAE736174E4368DE7), // 3.680220e-2154 - convert(0x2A67, 0x89B932A8729137A3), // 8.669256e-1665 - convert(0x2461, 0xF3A041588E81E4FA), // 9.941326e-2129 - - convert(0x6702, 0xC8ABA8F1D29CA39F), // 3.818039e+3006 - convert(0x1F76, 0xE16EB83CE645D0EF), // 9.267715e-2508 - convert(0x4AB2, 0x9FEA8F04FC4E664D), // 4.148019e+824 - }; - - return ti; + /// TODO: find values that demonstrate variability with long double + return {}; } REGISTER_TYPE(DistributivityOfMultiplication) From a2343fb1b8c48b192cfb9ea153f290862075b2e1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 13 Aug 2018 23:32:02 -0600 Subject: [PATCH 058/196] Fix tst_bisect_biggest.py --- tests/flit_bisect/tst_bisect_biggest.py | 79 ++++++------------------- 1 file changed, 17 insertions(+), 62 deletions(-) diff --git a/tests/flit_bisect/tst_bisect_biggest.py b/tests/flit_bisect/tst_bisect_biggest.py index b9d42ddf..128ab9a2 100644 --- a/tests/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_bisect/tst_bisect_biggest.py @@ -107,7 +107,7 @@ ... filename = 'tests/file{}.cpp'.format(fileno) ... funcname = 'file{}_func{}{}'.format(fileno, funcno, prob_str) ... return Sym(filename, -... '_Z19{}z'.format(funcname), +... '_Z19{}v'.format(funcname), ... funcname + '()', ... filename, ... lineno) @@ -125,7 +125,7 @@ ... create_symbol(1, 2, 92, True): 5.0, ... create_symbol(1, 3, 100, True): 2.0, ... create_symbol(1, 4, 108, True): 3.0, -... create_symbol(1, 5, 116, False): 5.0, +... create_symbol(1, 5, 116, False): 0.0, ... create_symbol(2, 1, 90, True): 7.0, ... create_symbol(2, 2, 98, False): 0.0, ... create_symbol(2, 3, 99, False): 0.0, @@ -160,6 +160,7 @@ >>> def update_gt_results_stub(directory, verbose=False, jobs=4): ... # do nothing +... print('Updating ground-truth results - ground-truth.csv - done') ... pass >>> def extract_symbols_stub(file_or_filelist, objdir): @@ -169,7 +170,9 @@ ... symbol_tuples.extend(extract_symbols_stub(fname, objdir)) ... return symbol_tuples ... -... return [x for x in all_symbol_scores if x.fname == file_or_filelist] +... return sorted([x for x in all_symbol_scores +... if x.fname == file_or_filelist], +... key=lambda x: x.symbol) >>> flit_bisect.build_bisect = build_bisect_stub >>> flit_bisect.update_gt_results = update_gt_results_stub @@ -221,102 +224,54 @@ Updating ground-truth results - ground-truth.csv - done Looking for the top 1 different symbol(s) by starting with files Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 - Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 14.0 - Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 14.0 - Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 10.0 - Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 4.0 + ... Found differing source file tests/file1.cpp: score 10.0 Searching for differing symbols in: tests/file1.cpp Created ... ... Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - Created /.../bisect-01/bisect-make-15.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-16.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-17.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-18.mk - compiling and running - score 0.0 + Created ... + ... Found differing source file tests/file2.cpp: score 7.0 Searching for differing symbols in: tests/file2.cpp Created ... ... - Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) - Found differing source file tests/file3.cpp: score 4.0 -found highest variability inducing source files: - tests/file1.cpp (score 10.0) - tests/file2.cpp (score 7.0) - tests/file3.cpp (score 4.0) -1 highest variability symbol from each found source file: - /.../tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) - - ->>> print('\\n'.join(bisect_out_1)) # doctest:+ELLIPSIS -Updating ground-truth results - ground-truth.csv - done -Looking for the top 1 different symbol(s) by starting with files - Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 - Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 14.0 - Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 14.0 - Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 10.0 - Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 4.0 - Found differing source file tests/file1.cpp: score 10.0 - Searching for differing symbols in: tests/file1.cpp - Created ... - ... - Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - Created /.../bisect-01/bisect-make-...mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-...mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-...mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-...mk - compiling and running - score 0.0 - Found differing source file tests/file2.cpp: score 7.0 - Searching for differing symbols in: tests/file2.cpp - Created ... - ... - Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Found differing symbol on line 90 -- file2_func1_PROBLEM() (score 7.0) Found differing source file tests/file3.cpp: score 4.0 The found highest variability inducing source files: tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) tests/file3.cpp (score 4.0) The 1 highest variability symbol: - /.../tests/file2.cpp:91 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) + tests/file2.cpp:90 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) >>> print('\\n'.join(bisect_out_2)) # doctest:+ELLIPSIS Updating ground-truth results - ground-truth.csv - done Looking for the top 2 different symbol(s) by starting with files Created /.../bisect-02/bisect-make-01.mk - compiling and running - score 21.0 - Created /.../bisect-02/bisect-make-02.mk - compiling and running - score 14.0 - Created /.../bisect-02/bisect-make-03.mk - compiling and running - score 7.0 - Created /.../bisect-02/bisect-make-04.mk - compiling and running - score 0.0 - Created /.../bisect-02/bisect-make-05.mk - compiling and running - score 14.0 - Created /.../bisect-02/bisect-make-06.mk - compiling and running - score 10.0 - Created /.../bisect-02/bisect-make-07.mk - compiling and running - score 4.0 + ... Found differing source file tests/file1.cpp: score 10.0 Searching for differing symbols in: tests/file1.cpp Created ... ... Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - Created ... ... Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) - Created /.../bisect-02/bisect-make-...mk - compiling and running - score 0.0 - Created /.../bisect-02/bisect-make-...mk - compiling and running - score 7.0 - Created /.../bisect-02/bisect-make-...mk - compiling and running - score 7.0 - Created /.../bisect-02/bisect-make-...mk - compiling and running - score 0.0 + Created ... + ... Found differing source file tests/file2.cpp: score 7.0 Searching for differing symbols in: tests/file2.cpp Created ... ... - Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) + Found differing symbol on line 90 -- file2_func1_PROBLEM() (score 7.0) Found differing source file tests/file3.cpp: score 4.0 The found highest variability inducing source files: tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) tests/file3.cpp (score 4.0) The 2 highest variability symbols: - /.../tests/file2.cpp:91 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) - /.../tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) + tests/file2.cpp:90 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) + tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) TODO: Test the log_contents variable From 2e59fe60d050526f59c15a8100236c714e0063cb Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 13 Aug 2018 23:35:35 -0600 Subject: [PATCH 059/196] tst_bisect_biggest: try to make more robust --- tests/flit_bisect/tst_bisect_biggest.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/flit_bisect/tst_bisect_biggest.py b/tests/flit_bisect/tst_bisect_biggest.py index 128ab9a2..e4b44d55 100644 --- a/tests/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_bisect/tst_bisect_biggest.py @@ -230,7 +230,6 @@ Created ... ... Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - Created ... ... Found differing source file tests/file2.cpp: score 7.0 Searching for differing symbols in: tests/file2.cpp @@ -257,7 +256,6 @@ Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) ... Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) - Created ... ... Found differing source file tests/file2.cpp: score 7.0 Searching for differing symbols in: tests/file2.cpp From f472c31ed72fa408f69135c198c88a550292b4fe Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 13 Aug 2018 23:39:34 -0600 Subject: [PATCH 060/196] tst_bisect_biggest: try to make more robust... again --- tests/flit_bisect/tst_bisect_biggest.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tests/flit_bisect/tst_bisect_biggest.py b/tests/flit_bisect/tst_bisect_biggest.py index e4b44d55..f6b90438 100644 --- a/tests/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_bisect/tst_bisect_biggest.py @@ -230,8 +230,7 @@ Created ... ... Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - ... - Found differing source file tests/file2.cpp: score 7.0 + ...Found differing source file tests/file2.cpp: score 7.0 Searching for differing symbols in: tests/file2.cpp Created ... ... @@ -254,10 +253,8 @@ Created ... ... Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - ... - Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) - ... - Found differing source file tests/file2.cpp: score 7.0 + ... Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) + ...Found differing source file tests/file2.cpp: score 7.0 Searching for differing symbols in: tests/file2.cpp Created ... ... From eb685ea83b21f2e3134a27d27ce2506f2b2b69b7 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 15 Aug 2018 12:04:28 -0600 Subject: [PATCH 061/196] bisect: remove implicit conversions to bool --- scripts/flitcli/flit_bisect.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index fa498af3..63136c2c 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -605,14 +605,14 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): >>> bisect_biggest(score_func, []) [] ''' - if not elements: + if len(elements) == 0: return [] found_list = [] frontier = [] push = lambda x: heapq.heappush(frontier, (-score_func(x), x)) pop = lambda: heapq.heappop(frontier) push(elements) - while frontier and frontier[0][0] < 0 and len(found_list) < k: + while len(frontier) > 0 and frontier[0][0] < 0 and len(found_list) < k: score, elems = pop() if len(elems) == 1: found_list.append((elems[0], -score)) @@ -715,7 +715,7 @@ def bisect_search(score_func, elements, found_callback=None): ... except AssertionError: ... pass ''' - if not elements: + if len(elements) == 0: return [] # copy the incoming list so that we don't modify it @@ -1167,7 +1167,7 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, # Check to see if -fPIC destroyed any chance of finding any differing # symbols - if not memoized_checker(symbol_tuples): + if memoized_checker(symbol_tuples) <= 0.0: message_1 = '{} Warning: -fPIC compilation destroyed the ' \ 'optimization'.format(indent) message_2 = '{} Cannot find any trouble symbols'.format(indent) From 83a15174b95913b2a71256d3bcfb5b3bd5e6e642 Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Thu, 16 Aug 2018 13:04:14 -0600 Subject: [PATCH 062/196] skip weak symbols --- scripts/flitcli/flit_bisect.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index a0cc9594..0d4a4d73 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -401,7 +401,9 @@ def extract_symbols(file_or_filelist, objdir): # generate the symbol tuples for symbol_string, demangled_string in zip(symbol_strings, demangled_symbol_strings): - symbol = symbol_string.split(maxsplit=2)[2] + symbol_type, symbol = symbol_string.split(maxsplit=2)[1:] + if symbol_type == "W": # skip weak symbols + continue demangled = demangled_string.split(maxsplit=2)[2] try: deffile, defline = symbol_line_mapping[symbol] From 2e8ade0676755f305f517f35ea1be32391bc0924 Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Thu, 16 Aug 2018 13:04:50 -0600 Subject: [PATCH 063/196] test for ignoring weak symbols --- tests/flit_bisect/data/tests/BisectTest.cpp | 3 +- tests/flit_bisect/data/tests/file4.cpp | 114 ++++++++++++++++++++ tests/flit_bisect/data/tests/file4.h | 95 ++++++++++++++++ tests/flit_bisect/tst_bisect.py | 37 +++++-- 4 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 tests/flit_bisect/data/tests/file4.cpp create mode 100644 tests/flit_bisect/data/tests/file4.h diff --git a/tests/flit_bisect/data/tests/BisectTest.cpp b/tests/flit_bisect/data/tests/BisectTest.cpp index f59d1b65..75292167 100644 --- a/tests/flit_bisect/data/tests/BisectTest.cpp +++ b/tests/flit_bisect/data/tests/BisectTest.cpp @@ -84,6 +84,7 @@ #include "file1.h" #include "file2.h" #include "file3.h" +#include "file4.h" #include @@ -105,7 +106,7 @@ class BisectTest : public flit::TestBase { protected: virtual flit::Variant run_impl(const std::vector &ti) override { FLIT_UNUSED(ti); - return file1_all() + file2_all() + file3_all(); + return file1_all() + file2_all() + file3_all() + file4_all(); } protected: diff --git a/tests/flit_bisect/data/tests/file4.cpp b/tests/flit_bisect/data/tests/file4.cpp new file mode 100644 index 00000000..c9acb952 --- /dev/null +++ b/tests/flit_bisect/data/tests/file4.cpp @@ -0,0 +1,114 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + +#include "file4.h" + +#include + +#include + +int file4_func1() { return 1; } +int file4_func2() { return 2; } +int file4_func3() { return 3; } +int file4_func4() { return 4; } + +template +int file4_func5_TEMPLATE_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 5 + 10; // variability introduced = 10 + } else { + return 5; + } +} + + + +int file4_all() { + return file4_func1() + + file4_func2() + + file4_func3() + + file4_func4() + + file4_func5_TEMPLATE_PROBLEM<0>() + + file4_func5_TEMPLATE_PROBLEM<1>() + + file4_func5_TEMPLATE_PROBLEM<2>(); +} diff --git a/tests/flit_bisect/data/tests/file4.h b/tests/flit_bisect/data/tests/file4.h new file mode 100644 index 00000000..fc9baf15 --- /dev/null +++ b/tests/flit_bisect/data/tests/file4.h @@ -0,0 +1,95 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + +#ifndef FILE4_H +#define FILE4_H + +int file4_func1(); +int file4_func2(); +int file4_func3(); +int file4_func4(); +template +int file4_func5_TEMPLATE_PTOBLEM(); // variability = 10 +int file4_all(); + +#endif // FILE4_H diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index b181fa57..54741790 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -109,7 +109,10 @@ ... outstream=ostream) ... bisect_out = ostream.getvalue().splitlines() ... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: -... log_contents = fin.readlines() +... raw_log = fin.readlines() +... stripped_log = [line[line.index(' bisect:')+8:].rstrip() +... for line in raw_log] +... log_contents = [line for line in stripped_log if line.strip() != ''] Verify the output of flit init >>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS @@ -126,21 +129,21 @@ Verify that all source files were found and output during the search >>> sorted([x.split()[-1] for x in bisect_out ... if x.startswith(' Found bad source file')]) -['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] +['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp', 'tests/file4.cpp'] -Verify that the three bad sources were output in the "bad sources:" section +Verify that the four bad sources were output in the "bad sources:" section >>> idx = bisect_out.index(' bad sources:') ->>> sorted(bisect_out[idx+1:idx+4]) -[' tests/file1.cpp', ' tests/file2.cpp', ' tests/file3.cpp'] ->>> bisect_out[idx+4].startswith('Searching for bad symbols in:') +>>> sorted(bisect_out[idx+1:idx+5]) +[' tests/file1.cpp', ' tests/file2.cpp', ' tests/file3.cpp', ' tests/file4.cpp'] +>>> bisect_out[idx+5].startswith('Searching for bad symbols in:') True -Verify that all three files were searched individually +Verify that all four files were searched individually >>> sorted([x.split()[-1] for x in bisect_out ... if x.startswith('Searching for bad symbols in:')]) -['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp'] +['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp', 'tests/file4.cpp'] -Verify all functions were identified during the symbol searches +Verify all non-templated functions were identified during the symbol searches >>> print('\\n'.join( ... sorted([' '.join(x.split()[-4:]) for x in bisect_out ... if x.startswith(' Found bad symbol on line')]))) @@ -175,6 +178,13 @@ >>> bisect_out[idx+3].startswith(' ') False +This should be a weak symbol error... But how can that be determined? +Allow it to say fPIC destroyed the opt even though it is because the weak +symbols from the ground truth compile were chosen +>>> idx = bisect_out.index('Searching for bad symbols in: tests/file4.cpp') +>>> print(bisect_out[idx+2]) + Warning: -fPIC compilation destroyed the optimization + Test the All bad symbols section of the output >>> idx = bisect_out.index('All bad symbols:') >>> print('\\n'.join(sorted(bisect_out[idx+1:]))) # doctest:+ELLIPSIS @@ -258,6 +268,15 @@ /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() +Look for the symbols picked up for file4 in the log +>>> idx = log_contents.index(' Searching for bad symbols in: tests/file4.cpp') +>>> print('\\n'.join(log_contents[idx+4 : idx+9])) # doctest:+ELLIPSIS + None:None ... -- file4_func1() + /.../tests/file4.cpp:91 ... -- file4_func2() + /.../tests/file4.cpp:92 ... -- file4_func3() + /.../tests/file4.cpp:93 ... -- file4_func4() + /.../tests/file4.cpp:106 ... -- file4_all() + TODO: test the log_contents variable ''' From 702e54c011ebcdcbef38b6591601b810a1f6e24b Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Thu, 16 Aug 2018 13:55:53 -0600 Subject: [PATCH 064/196] matching test to travis build --- tests/flit_bisect/tst_bisect.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_bisect/tst_bisect.py index 54741790..5aca3738 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_bisect/tst_bisect.py @@ -149,6 +149,7 @@ ... if x.startswith(' Found bad symbol on line')]))) line 100 -- file1_func3_PROBLEM() line 103 -- file3_func5_PROBLEM() +line 106 -- file4_all() line 108 -- file1_func4_PROBLEM() line 91 -- file2_func1_PROBLEM() line 92 -- file1_func2_PROBLEM() @@ -178,12 +179,12 @@ >>> bisect_out[idx+3].startswith(' ') False -This should be a weak symbol error... But how can that be determined? -Allow it to say fPIC destroyed the opt even though it is because the weak -symbols from the ground truth compile were chosen ->>> idx = bisect_out.index('Searching for bad symbols in: tests/file4.cpp') ->>> print(bisect_out[idx+2]) - Warning: -fPIC compilation destroyed the optimization +Verify the bad symbols section for file4.cpp +>>> idx = bisect_out.index(' bad symbols in tests/file4.cpp:') +>>> print('\\n'.join(sorted(bisect_out[idx+1:idx+2]))) + line 106 -- file4_all() +>>> bisect_out[idx+2].startswitch' ') +True Test the All bad symbols section of the output >>> idx = bisect_out.index('All bad symbols:') @@ -194,6 +195,7 @@ /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() + /.../tests/file4.cpp:106 ... -- file4_all() Example output to be expected: From e19ad2158c920916f064c1eec33f37f91a1337d5 Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Fri, 17 Aug 2018 13:58:24 -0600 Subject: [PATCH 065/196] bisect-biggest: "less" -> "greater" --- scripts/flitcli/flit_bisect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 63136c2c..55e3f4c0 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -17,7 +17,7 @@ # All rights reserved. # # This file is part of FLiT. For details, see -# https://pruners.github.io/flit +# https://pruners.github.io/flitK # Please also read # https://github.com/PRUNERS/FLiT/blob/master/LICENSE # @@ -534,7 +534,7 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): ''' Performs the bisect search, attempting to find the biggest offenders. This is different from bisect_search() in that this function only tries to - identify the top k offenders, not all of them. If k is less than or equal + identify the top k offenders, not all of them. If k is greater than or equal to the total number of offenders, then bisect_biggest() is more expensive than bisect_search(). From 83ccaaae13a0094c5fe514f343ee05c16a685b43 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 21 Aug 2018 15:21:59 -0700 Subject: [PATCH 066/196] flit.cpp: Improve csv parsing to include quoted fields --- src/flit.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 71 insertions(+), 17 deletions(-) diff --git a/src/flit.cpp b/src/flit.cpp index f70543c6..0a7bdbdd 100644 --- a/src/flit.cpp +++ b/src/flit.cpp @@ -101,7 +101,7 @@ namespace { -/** Helper class for Csv. +/** Helper class for CsvReader. * * Represents a single row either indexed by number or by column name. */ @@ -133,14 +133,14 @@ class CsvRow : public std::vector { }; /** Class for parsing csv files */ -class Csv { +class CsvReader { public: - Csv(std::istream &in) : m_header(Csv::parseRow(in)), m_in(in) { + CsvReader(std::istream &in) : m_header(CsvReader::parseRow(in)), m_in(in) { m_header.setHeader(&m_header); } - Csv& operator>> (CsvRow& row) { - row = Csv::parseRow(m_in); + CsvReader& operator>> (CsvRow& row) { + row = CsvReader::parseRow(m_in); row.setHeader(&m_header); return *this; } @@ -149,23 +149,77 @@ class Csv { private: static CsvRow parseRow(std::istream &in) { - std::string line; - std::getline(in, line); + enum class State { + DEFAULT, + IN_STRING, + }; + State state = State::DEFAULT; - std::stringstream lineStream(line); - std::string token; + char quote_char = '"'; + char separator = ','; + char line_end = '\n'; - // tokenize on ',' CsvRow row; - while(std::getline(lineStream, token, ',')) { - row.emplace_back(token); + char current; + std::ostringstream running; + int running_size = 0; + while (in >> current) { + if (state == State::DEFAULT) { + if (running_size == 0 && current == quote_char) { + state = State::IN_STRING; + } else if (current == separator) { + row.emplace_back(running.str()); + running.str(""); + running_size = 0; + } else if (current == line_end) { + row.emplace_back(running.str()); + running.str(""); + running_size = 0; + break; // break out of the while loop + } else { + running << current; + running_size++; + } + } else if (state == State::IN_STRING) { + if (current == quote_char) { + state = State::DEFAULT; + } else { + running << current; + running_size++; + } + } else { + throw std::runtime_error( + "Please contact Michael Bentley, this shouldn't happen..."); + } + } + + // We should not be within a STRING when we exit the while loop + if (state != State::DEFAULT) { + throw std::runtime_error("Error parsing CSV file"); } - // check for trailing comma with no data after it - if (!lineStream && token.empty()) { - row.emplace_back(""); + // If we stopped because we reached the end of file... + if (!in) { + row.emplace_back(running.str()); } + //std::string line; + //std::getline(in, line); + + //std::stringstream lineStream(line); + //std::string token; + + //// tokenize on ',' + //CsvRow row; + //while(std::getline(lineStream, token, ',')) { + // row.emplace_back(token); + //} + + //// check for trailing comma with no data after it + //if (!lineStream && token.empty()) { + // row.emplace_back(""); + //} + return row; } @@ -466,7 +520,7 @@ std::string readFile(const std::string &filename) { std::vector parseResults(std::istream &in) { std::vector results; - Csv csv(in); + CsvReader csv(in); CsvRow row; while (csv >> row) { auto nanosec = std::stol(row["nanosec"]); @@ -501,7 +555,7 @@ std::unordered_map parseMetadata(std::istream &in) { "file" }; - Csv csv(in); + CsvReader csv(in); CsvRow row; if (csv >> row) { for (auto key : metadataKeys) { From bc281b8c2bb169a59c56127fec3a9e8da2eb58ea Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 21 Aug 2018 16:45:02 -0700 Subject: [PATCH 067/196] flit: Generate correct CsvWriter and CsvReader classes --- src/FlitCsv.cpp | 98 +++++++++++++++++++++++++++++++++++++ src/FlitCsv.h | 124 +++++++++++++++++++++++++++++++++++++++++++++++ src/flit.cpp | 126 ------------------------------------------------ src/flit.h | 82 ++++++++++++++++--------------- 4 files changed, 265 insertions(+), 165 deletions(-) create mode 100644 src/FlitCsv.cpp create mode 100644 src/FlitCsv.h diff --git a/src/FlitCsv.cpp b/src/FlitCsv.cpp new file mode 100644 index 00000000..feebf49c --- /dev/null +++ b/src/FlitCsv.cpp @@ -0,0 +1,98 @@ +#include "FlitCsv.h" + +#include +#include +#include + +namespace flit { + +std::string const& CsvRow::operator[](std::string col) const { + if (m_header == nullptr) { + throw std::logic_error("No header defined"); + } + auto iter = std::find(m_header->begin(), m_header->end(), col); + if (iter == m_header->end()) { + std::stringstream message; + message << "No column named " << col; + throw std::invalid_argument(message.str()); + } + auto idx = iter - m_header->begin(); + return this->at(idx); +} + +CsvRow CsvReader::parseRow(std::istream &in) { + enum class State { + DEFAULT, + IN_STRING, + }; + State state = State::DEFAULT; + + char quote_char = '"'; + char separator = ','; + char line_end = '\n'; + + CsvRow row; + char current; + std::ostringstream running; + int running_size = 0; + while (in >> current) { + if (state == State::DEFAULT) { + if (running_size == 0 && current == quote_char) { + state = State::IN_STRING; + } else if (current == separator) { + row.emplace_back(running.str()); + running.str(""); + running_size = 0; + } else if (current == line_end) { + row.emplace_back(running.str()); + running.str(""); + running_size = 0; + break; // break out of the while loop + } else { + running << current; + running_size++; + } + } else if (state == State::IN_STRING) { + if (current == quote_char) { + state = State::DEFAULT; + } else { + running << current; + running_size++; + } + } else { + throw std::runtime_error( + "Please contact Michael Bentley, this shouldn't happen..."); + } + } + + // We should not be within a STRING when we exit the while loop + if (state != State::DEFAULT) { + throw std::runtime_error("Error parsing CSV file"); + } + + // If we stopped because we reached the end of file... + if (!in) { + row.emplace_back(running.str()); + } + + //std::string line; + //std::getline(in, line); + + //std::stringstream lineStream(line); + //std::string token; + + //// tokenize on ',' + //CsvRow row; + //while(std::getline(lineStream, token, ',')) { + // row.emplace_back(token); + //} + + //// check for trailing comma with no data after it + //if (!lineStream && token.empty()) { + // row.emplace_back(""); + //} + + return row; +} + +} // end of namespace flit diff --git a/src/FlitCsv.h b/src/FlitCsv.h new file mode 100644 index 00000000..62ca3eb2 --- /dev/null +++ b/src/FlitCsv.h @@ -0,0 +1,124 @@ +#ifndef FLIT_CSV_H +#define FLIT_CSV_H + +#include "flitHelpers.h" + +#include +#include +#include + +namespace flit { + +/** Helper class for CsvReader. + * + * Represents a single row either indexed by number or by column name. + */ +class CsvRow : public std::vector { +public: + // Inherit base class constructors + using std::vector::vector; + + const CsvRow* header() const { return m_header; } + void setHeader(CsvRow* head) { m_header = head; } + + using std::vector::operator[]; + std::string const& operator[](std::string col) const; + +private: + CsvRow* m_header {nullptr}; // not owned by this class +}; + +/** Class for parsing csv files */ +class CsvReader { +public: + CsvReader(std::istream &in) + : m_header(CsvReader::parseRow(in)) + , m_in(in) + { + m_header.setHeader(&m_header); + } + + operator bool() const { return static_cast(m_in); } + CsvRow header() { return m_header; } + std::istream& stream() { return m_in; } + + CsvReader& operator>> (CsvRow& row) { + row = CsvReader::parseRow(m_in); + row.setHeader(&m_header); + return *this; + } + +private: + static CsvRow parseRow(std::istream &in); + +private: + CsvRow m_header; + std::istream &m_in; +}; + +class CsvWriter { +public: + CsvWriter(std::ostream &out) : m_out(out), m_is_line_beginning(true) {} + + template + CsvWriter& operator<< (const T &val) { + this->write_val(val); + return *this; + } + + template <> + CsvWriter& operator<< (const std::vector &row) { + this->write_row(row); + return *this; + } + + template + void write_val (const T val) { + if (!this->m_is_line_beginning) { + this->m_out << ','; + } + this->m_is_line_beginning = false; + this->m_out << val; + } + + template <> + void write_val (const char* val) { write_val(val); } + + template <> + void write_val (const std::string &val) { + if (!this->m_is_line_beginning) { + this->m_out << ','; + } + this->m_is_line_beginning = false; + // if there are offending characters in val, then quote the field + if (val.find_first_of(",\r\n") != std::string::npos) { + this->m_out << '"' << val << '"'; + } else { + this->m_out << val; + } + } + + void new_row() { + this->m_out << std::endl; + this->m_is_line_beginning = true; + } + + void write_row (const std::vector& row) { + if (!this->m_is_line_beginning) { + throw std::runtime_error("Cannot write a row to a partially created " + "row. Call CsvWriter::new_row() first"); + } + for (auto &elem : row) { + this->write_val(elem); + } + this->new_row(); + } + +private: + std::ostream &m_out; + bool m_is_line_beginning; +}; + +} // end of namespace flit + +#endif // FLIT_CSV_H diff --git a/src/flit.cpp b/src/flit.cpp index 0a7bdbdd..d0297193 100644 --- a/src/flit.cpp +++ b/src/flit.cpp @@ -101,132 +101,6 @@ namespace { -/** Helper class for CsvReader. - * - * Represents a single row either indexed by number or by column name. - */ -class CsvRow : public std::vector { -public: - // Inherit base class constructors - using std::vector::vector; - - const CsvRow* header() const { return m_header; } - void setHeader(CsvRow* head) { m_header = head; } - - using std::vector::operator[]; - std::string const& operator[](std::string col) const { - if (m_header == nullptr) { - throw std::logic_error("No header defined"); - } - auto iter = std::find(m_header->begin(), m_header->end(), col); - if (iter == m_header->end()) { - std::stringstream message; - message << "No column named " << col; - throw std::invalid_argument(message.str()); - } - auto idx = iter - m_header->begin(); - return this->at(idx); - } - -private: - CsvRow* m_header {nullptr}; // not owned by this class -}; - -/** Class for parsing csv files */ -class CsvReader { -public: - CsvReader(std::istream &in) : m_header(CsvReader::parseRow(in)), m_in(in) { - m_header.setHeader(&m_header); - } - - CsvReader& operator>> (CsvRow& row) { - row = CsvReader::parseRow(m_in); - row.setHeader(&m_header); - return *this; - } - - operator bool() const { return static_cast(m_in); } - -private: - static CsvRow parseRow(std::istream &in) { - enum class State { - DEFAULT, - IN_STRING, - }; - State state = State::DEFAULT; - - char quote_char = '"'; - char separator = ','; - char line_end = '\n'; - - CsvRow row; - char current; - std::ostringstream running; - int running_size = 0; - while (in >> current) { - if (state == State::DEFAULT) { - if (running_size == 0 && current == quote_char) { - state = State::IN_STRING; - } else if (current == separator) { - row.emplace_back(running.str()); - running.str(""); - running_size = 0; - } else if (current == line_end) { - row.emplace_back(running.str()); - running.str(""); - running_size = 0; - break; // break out of the while loop - } else { - running << current; - running_size++; - } - } else if (state == State::IN_STRING) { - if (current == quote_char) { - state = State::DEFAULT; - } else { - running << current; - running_size++; - } - } else { - throw std::runtime_error( - "Please contact Michael Bentley, this shouldn't happen..."); - } - } - - // We should not be within a STRING when we exit the while loop - if (state != State::DEFAULT) { - throw std::runtime_error("Error parsing CSV file"); - } - - // If we stopped because we reached the end of file... - if (!in) { - row.emplace_back(running.str()); - } - - //std::string line; - //std::getline(in, line); - - //std::stringstream lineStream(line); - //std::string token; - - //// tokenize on ',' - //CsvRow row; - //while(std::getline(lineStream, token, ',')) { - // row.emplace_back(token); - //} - - //// check for trailing comma with no data after it - //if (!lineStream && token.empty()) { - // row.emplace_back(""); - //} - - return row; - } - -private: - CsvRow m_header; - std::istream &m_in; -}; /** Returns true if the element is in the container */ template diff --git a/src/flit.h b/src/flit.h index bb668bd4..22f11ba6 100644 --- a/src/flit.h +++ b/src/flit.h @@ -87,6 +87,7 @@ #ifndef FLIT_H #define FLIT_H 0 +#include "FlitCsv.h" #include "MpiEnvironment.h" #include "TestBase.h" #include "flitHelpers.h" @@ -287,64 +288,67 @@ inline void outputResults ( std::string executableFilename = FLIT_FILENAME) { // Output the column headers - out << "name," - "host," - "compiler," - "optl," - "switches," - "precision," - "score_hex," - "score," - "resultfile," - "comparison_hex," - "comparison," - "file," - "nanosec" - << std::endl; - for(const auto& result: results){ - out - << result.name() << "," // test case name - << hostname << "," // hostname - << compiler << "," // compiler - << optimization_level << "," // optimization level - << switches << "," // compiler flags - << result.precision() << "," // precision + CsvWriter writer(out); + writer + << "name" + << "host" + << "compiler" + << "optl" + << "switches" + << "precision" + << "score_hex" + << "score" + << "resultfile" + << "comparison_hex" + << "comparison" + << "file" + << "nanosec"; + writer.new_row(); + for (const auto& result: results) { + writer + << result.name() // test case name + << hostname // hostname + << compiler // compiler + << optimization_level // optimization level + << switches // compiler flags + << result.precision() // precision ; if (result.result().type() == Variant::Type::LongDouble) { - out - << as_int(result.result().longDouble()) << "," // score_hex - << result.result().longDouble() << "," // score + writer + << as_int(result.result().longDouble()) // score_hex + << result.result().longDouble() // score ; } else { - out - << FLIT_NULL << "," // score_hex - << FLIT_NULL << "," // score + writer + << FLIT_NULL // score_hex + << FLIT_NULL // score ; } if (result.resultfile().empty()) { - out << FLIT_NULL << ","; // resultfile + writer << FLIT_NULL; // resultfile } else { - out << result.resultfile() << ","; // resultfile + writer << result.resultfile(); // resultfile } if (result.is_comparison_null()) { - out - << FLIT_NULL << "," // comparison_hex - << FLIT_NULL << "," // comparison + writer + << FLIT_NULL // comparison_hex + << FLIT_NULL // comparison ; } else { - out - << as_int(result.comparison()) << "," // comparison_hex - << result.comparison() << "," // comparison + writer + << as_int(result.comparison()) // comparison_hex + << result.comparison() // comparison ; } - out - << executableFilename << "," // executable filename + writer + << executableFilename // executable filename << result.nanosecs() // nanoseconds - << std::endl; + ; + writer.new_row(); } } From f16f26b14aa9860b18caa0b04378257b3e7764da Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 09:28:24 -0600 Subject: [PATCH 068/196] Get FlitCsv to compile under gcc --- src/FlitCsv.h | 76 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/FlitCsv.h b/src/FlitCsv.h index 62ca3eb2..4382ab9d 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -58,7 +58,9 @@ class CsvReader { class CsvWriter { public: - CsvWriter(std::ostream &out) : m_out(out), m_is_line_beginning(true) {} + explicit CsvWriter(std::ostream &out) + : m_out(out), m_is_line_beginning(true) {} + virtual ~CsvWriter() {} template CsvWriter& operator<< (const T &val) { @@ -66,37 +68,8 @@ class CsvWriter { return *this; } - template <> - CsvWriter& operator<< (const std::vector &row) { - this->write_row(row); - return *this; - } - template - void write_val (const T val) { - if (!this->m_is_line_beginning) { - this->m_out << ','; - } - this->m_is_line_beginning = false; - this->m_out << val; - } - - template <> - void write_val (const char* val) { write_val(val); } - - template <> - void write_val (const std::string &val) { - if (!this->m_is_line_beginning) { - this->m_out << ','; - } - this->m_is_line_beginning = false; - // if there are offending characters in val, then quote the field - if (val.find_first_of(",\r\n") != std::string::npos) { - this->m_out << '"' << val << '"'; - } else { - this->m_out << val; - } - } + void write_val (const T val) { append(val); } void new_row() { this->m_out << std::endl; @@ -114,11 +87,52 @@ class CsvWriter { this->new_row(); } +private: + template + CsvWriter& append(const T &val) { + if (!this->m_is_line_beginning) { + this->m_out << ','; + } + this->m_is_line_beginning = false; + this->m_out << val; + return *this; + } + private: std::ostream &m_out; bool m_is_line_beginning; }; +#define CSVWRITER_OPERATOR(type) \ + inline CsvWriter& operator<< (CsvWriter& out, const type val) { \ + out.write_val(val); \ + return out; \ + } + +CSVWRITER_OPERATOR(int); +CSVWRITER_OPERATOR(long); +CSVWRITER_OPERATOR(long long); +CSVWRITER_OPERATOR(unsigned int); +CSVWRITER_OPERATOR(unsigned long); +CSVWRITER_OPERATOR(unsigned long long); +CSVWRITER_OPERATOR(unsigned __int128); +CSVWRITER_OPERATOR(float); +CSVWRITER_OPERATOR(double); +CSVWRITER_OPERATOR(long double); + +#undef CSVWRITER_OPERATOR + +// handle std::string separately +inline CsvWriter& operator<< (CsvWriter& out, const std::string &val) { + // if there are offending characters in val, then quote the field + if (val.find_first_of(",\r\n") != std::string::npos) { + out.write_val('"' + val + '"'); + } else { + out.write_val(val); + } + return out; +} + } // end of namespace flit #endif // FLIT_CSV_H From dcaee39dd48419468a6f9afefca070b75a62fb3b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 09:28:53 -0600 Subject: [PATCH 069/196] InfoStream: use rdbuf instead of init --- src/InfoStream.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/InfoStream.cpp b/src/InfoStream.cpp index 0b5c90fc..03c9b936 100644 --- a/src/InfoStream.cpp +++ b/src/InfoStream.cpp @@ -95,8 +95,8 @@ namespace { public: InfoStreamBackend() : std::ostream(), _null() { hide(); } ~InfoStreamBackend() { hide(); } - void show() { init(std::cout.rdbuf()); } - void hide() { init(&_null); } + void show() { rdbuf(std::cout.rdbuf()); } + void hide() { rdbuf(&_null); } private: NullBuffer _null; @@ -110,7 +110,7 @@ InfoStream::InfoStream() : std::ostream() , _threadbuf() { - init(_threadbuf.rdbuf()); + rdbuf(_threadbuf.rdbuf()); } InfoStream::~InfoStream() { From 2ac12a26e358e71ca26c73f4ebad5d563227e909 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 09:56:02 -0600 Subject: [PATCH 070/196] test flit_src: improve Makefile dependency checking --- tests/flit_src/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/flit_src/Makefile b/tests/flit_src/Makefile index 1ab42844..37a27867 100644 --- a/tests/flit_src/Makefile +++ b/tests/flit_src/Makefile @@ -14,6 +14,9 @@ HARNESS := ../test_harness.h CFLAGS += $(addprefix -I,$(dir $(HARNESS))) CFLAGS += -I../../src +DEPFLAGS = -MD -MF $*.d + + .PHONY: build check help clean run_% build: $(TARGETS) @@ -33,7 +36,10 @@ run_% : % @./$< --quiet % : %.cpp $(HARNESS) Makefile - $(CC) $(CFLAGS) $< -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) $(DEPFLAGS) $< -o $@ $(LDFLAGS) + +.PRECIOUS: %.d +-include $(SRC:%.cpp=%.d) $(TARGETS): $(FLITLIB) From 4fdf8f553f9e29f47ddd39445178a5a5de3c68a2 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 10:13:51 -0600 Subject: [PATCH 071/196] tests: fix FlitCsv tests --- src/FlitCsv.cpp | 18 ++++- tests/flit_src/tst_FlitCsv_h.cpp | 116 +++++++++++++++++++++++++++++++ tests/flit_src/tst_flit_cpp.cpp | 52 -------------- 3 files changed, 131 insertions(+), 55 deletions(-) create mode 100644 tests/flit_src/tst_FlitCsv_h.cpp diff --git a/src/FlitCsv.cpp b/src/FlitCsv.cpp index feebf49c..67b1f47e 100644 --- a/src/FlitCsv.cpp +++ b/src/FlitCsv.cpp @@ -31,14 +31,26 @@ CsvRow CsvReader::parseRow(std::istream &in) { char separator = ','; char line_end = '\n'; + auto transition_state = [&state](State newstate) { + //std::cout << "State transitioned from " + // << static_cast(state) + // << " to " + // << static_cast(newstate) + // << std::endl; + state = newstate; + }; + CsvRow row; char current; std::ostringstream running; int running_size = 0; - while (in >> current) { + while (in.get(current)) { + //std::cout << "parsing csv, current char: " << current + // << ", state = " << static_cast(state) + // << std::endl; if (state == State::DEFAULT) { if (running_size == 0 && current == quote_char) { - state = State::IN_STRING; + transition_state(State::IN_STRING); } else if (current == separator) { row.emplace_back(running.str()); running.str(""); @@ -54,7 +66,7 @@ CsvRow CsvReader::parseRow(std::istream &in) { } } else if (state == State::IN_STRING) { if (current == quote_char) { - state = State::DEFAULT; + transition_state(State::DEFAULT); } else { running << current; running_size++; diff --git a/tests/flit_src/tst_FlitCsv_h.cpp b/tests/flit_src/tst_FlitCsv_h.cpp new file mode 100644 index 00000000..f467d5e9 --- /dev/null +++ b/tests/flit_src/tst_FlitCsv_h.cpp @@ -0,0 +1,116 @@ +#include "test_harness.h" + +#include "FlitCsv.h" + +namespace { + +std::ostream& operator<<(std::ostream& out, std::vector vec) { + bool first = true; + out << "["; + for (std::string &val : vec) { + if (!first) { + out << ", "; + } + first = false; + out << '"' << val << '"'; + } + out << "]"; + return out; +} + +std::ostream& operator<<(std::ostream& out, flit::CsvRow& row) { + out << "CsvRow:\n"; + if (row.header() == nullptr) { + out << " Header: NULL\n"; + } else { + out << " Header: " + << static_cast>(*row.header()) + << std::endl; + } + out << " Values: " << static_cast>(row) + << std::endl; + return out; +} + +} // end of unnamed namespace + +namespace tst_CsvRow { +void tst_CsvRow_header() { + flit::CsvRow row {"1", "2", "3", "4"}; + TH_EQUAL(row.header(), nullptr); + row.setHeader(&row); + TH_EQUAL(row.header(), &row); +} +TH_REGISTER(tst_CsvRow_header); + +void tst_CsvRow_operator_brackets_string() { + flit::CsvRow row {"1", "2", "3", "4"}; + flit::CsvRow header {"a", "b", "c", "d"}; + row.setHeader(&header); + TH_EQUAL(row["a"], "1"); + TH_EQUAL(row["b"], "2"); + TH_EQUAL(row["c"], "3"); + TH_EQUAL(row["d"], "4"); + TH_THROWS(row["Mike"], std::invalid_argument); + + // Row missing elements + header.emplace_back("e"); + TH_THROWS(row["e"], std::out_of_range); + + // null header + row.setHeader(nullptr); + TH_THROWS(row["a"], std::logic_error); +} +TH_REGISTER(tst_CsvRow_operator_brackets_string); + +void tst_CsvRow_operator_brackets_int() { + flit::CsvRow row {"1", "2", "3", "4"}; + flit::CsvRow header {"a", "b", "c", "d"}; + row.setHeader(&header); + TH_EQUAL(row[0], "1"); + TH_EQUAL(row[1], "2"); + TH_EQUAL(row[2], "3"); + TH_EQUAL(row[3], "4"); + TH_THROWS(row.at(4), std::out_of_range); + + // Row missing elements + header.emplace_back("e"); + TH_EQUAL(row.at(3), "4"); + TH_THROWS(row.at(4), std::out_of_range); + + // null header + row.setHeader(nullptr); + TH_EQUAL(row.at(2), "3"); + TH_THROWS(row.at(4), std::out_of_range); +} +TH_REGISTER(tst_CsvRow_operator_brackets_int); +} // end of namespace tst_CsvRow + +namespace tst_CsvReader { +void tst_Csv() { + std::istringstream in( + "first,second,third,fourth\n" + "a, b,c,\n" + "1,2,3,4,5,6,7\n" + "\n" + ); + flit::CsvReader csv(in); + flit::CsvRow row; + csv >> row; + auto &header = *row.header(); + TH_EQUAL(header, flit::CsvRow({"first", "second", "third", "fourth"})); + TH_EQUAL(row, flit::CsvRow({"a", " b", "c", ""})); + + csv >> row; + TH_EQUAL(row, flit::CsvRow({"1", "2", "3", "4", "5", "6", "7"})); + + csv >> row; + TH_EQUAL(row, flit::CsvRow({""})); +} +TH_REGISTER(tst_Csv); +} // end of namespace tst_CsvReader + +namespace tst_CsvWriter { + +} // end of namespace tst_CsvWriter + diff --git a/tests/flit_src/tst_flit_cpp.cpp b/tests/flit_src/tst_flit_cpp.cpp index 1a720904..1ca81d3f 100644 --- a/tests/flit_src/tst_flit_cpp.cpp +++ b/tests/flit_src/tst_flit_cpp.cpp @@ -134,58 +134,6 @@ std::ostream& operator<<(std::ostream& out, const std::vector &v) { } } // end of unnamed namespace -namespace tst_CsvRow { -void tst_CsvRow_header() { - CsvRow row {"1", "2", "3", "4"}; - TH_EQUAL(row.header(), nullptr); - row.setHeader(&row); - TH_EQUAL(row.header(), &row); -} -TH_REGISTER(tst_CsvRow_header); - -void tst_CsvRow_operator_brackets() { - CsvRow row {"1", "2", "3", "4"}; - CsvRow header {"a", "b", "c", "d"}; - row.setHeader(&header); - TH_EQUAL(row["a"], "1"); - TH_EQUAL(row["b"], "2"); - TH_EQUAL(row["c"], "3"); - TH_EQUAL(row["d"], "4"); - TH_THROWS(row["Mike"], std::invalid_argument); - - // Row missing elements - header.emplace_back("e"); - TH_THROWS(row["e"], std::out_of_range); - - // null header - row.setHeader(nullptr); - TH_THROWS(row["a"], std::logic_error); -} -TH_REGISTER(tst_CsvRow_operator_brackets); -} // end of namespace tst_CsvRow - -void tst_Csv() { - std::istringstream in( - "first,second,third,fourth\n" - "a, b,c,\n" - "1,2,3,4,5,6,7\n" - "\n" - ); - Csv csv(in); - CsvRow row; - csv >> row; - auto &header = *row.header(); - TH_EQUAL(header, CsvRow({"first", "second", "third", "fourth"})); - TH_EQUAL(row, CsvRow({"a", " b", "c", ""})); - - csv >> row; - TH_EQUAL(row, CsvRow({"1", "2", "3", "4", "5", "6", "7"})); - - csv >> row; - TH_EQUAL(row, CsvRow({""})); -} -TH_REGISTER(tst_Csv); - void tst_isIn() { // an empty vector TH_VERIFY(!isIn(std::vector{}, "")); From c5e77ae729d8542e1bacc98142497040947db320 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 10:20:46 -0600 Subject: [PATCH 072/196] test_harness.h: add filename to error message --- tests/test_harness.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/tests/test_harness.h b/tests/test_harness.h index 0a03ab7c..77c37ad6 100644 --- a/tests/test_harness.h +++ b/tests/test_harness.h @@ -130,14 +130,14 @@ // Assertion definitions #define TH_VERIFY_MSG(x, msg) \ if (!(x)) { \ - throw th::AssertionError(__func__, __LINE__, msg);\ + throw th::AssertionError(__FILE__, __func__, __LINE__, msg);\ } #define TH_VERIFY(x) TH_VERIFY_MSG(x, "TH_VERIFY("#x")") #define TH_EQUAL(a, b) TH_VERIFY_MSG((a) == (b), "TH_EQUAL("#a", "#b")") #define TH_NOT_EQUAL(a, b) TH_VERIFY_MSG((a) != (b), "TH_NOT_EQUAL("#a", "#b")") #define TH_FAIL(msg) \ TH_VERIFY_MSG(false, std::string("TH_FAIL(\"") + msg + "\")") -#define TH_SKIP(msg) throw th::SkipError(__func__, __LINE__, msg) +#define TH_SKIP(msg) throw th::SkipError(__FILE__, __func__, __LINE__, msg) #define TH_THROWS(exp, exception) \ try { \ exp; \ @@ -170,18 +170,21 @@ namespace th { // Signals an assertion failure class AssertionError : public std::exception { public: - AssertionError(std::string func, long line, std::string msg) - : _func(func), _line(line), _msg(msg) + AssertionError(std::string file, std::string func, long line, + std::string msg) + : _file(file), _func(func), _line(line), _msg(msg) { std::ostringstream msg_stream; msg_stream - << "Assertion failure: " << _func << ":" << _line << " - " << _msg; + << "Assertion failure: " << _file << ":" + << _line << " in " << _func << " - " << _msg; _what = msg_stream.str(); } virtual const char* what() const noexcept override { return _what.c_str(); } protected: + std::string _file; std::string _func; long _line; std::string _msg; @@ -191,12 +194,13 @@ namespace th { // Signals a test that is skipped class SkipError : public AssertionError { public: - SkipError(std::string func, long line, std::string msg) - : AssertionError(func, line, msg) + SkipError(std::string file, std::string func, long line, std::string msg) + : AssertionError(file, func, line, msg) { std::ostringstream msg_stream; msg_stream - << "Test skipped: " << _func << ":" << _line << " - " << _msg; + << "Test skipped: " << _file << ":" + << _line << " in " << _func << " - " << _msg; _what = msg_stream.str(); } }; @@ -226,10 +230,10 @@ int main(int argCount, char *argList[]) { } skipped_tests.emplace_back(test_name); } catch (const th::AssertionError &err) { - std::cout << test_name << ": " << err.what() << "\n"; + std::cout << test_name << ":\n " << err.what() << "\n"; failed_tests.emplace_back(test_name); } catch (const std::exception &err) { - std::cout << test_name << ": Uncought exception - " + std::cout << test_name << ": Uncought exception\n " << typeid(err).name() << ": " << err.what() << "\n"; failed_tests.emplace_back(test_name); } catch (...) { @@ -272,4 +276,3 @@ int main(int argCount, char *argList[]) { } #endif // TEST_HARNESS_H - From 333b31e6f7601b3f02ecd0a42351a4a58f08599a Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 10:39:04 -0600 Subject: [PATCH 073/196] FlitCsv: make tests pass and fix found problems --- src/FlitCsv.cpp | 2 +- src/flit.cpp | 6 +++++- tests/flit_src/tst_FlitCsv_h.cpp | 15 ++++++++++++--- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/FlitCsv.cpp b/src/FlitCsv.cpp index 67b1f47e..5104517c 100644 --- a/src/FlitCsv.cpp +++ b/src/FlitCsv.cpp @@ -83,7 +83,7 @@ CsvRow CsvReader::parseRow(std::istream &in) { } // If we stopped because we reached the end of file... - if (!in) { + if (!in && running_size > 0) { row.emplace_back(running.str()); } diff --git a/src/flit.cpp b/src/flit.cpp index d0297193..7eeb809d 100644 --- a/src/flit.cpp +++ b/src/flit.cpp @@ -396,7 +396,11 @@ std::vector parseResults(std::istream &in) { CsvReader csv(in); CsvRow row; - while (csv >> row) { + while (csv) { + csv >> row; + if (row.empty()) { + break; + } auto nanosec = std::stol(row["nanosec"]); Variant value; std::string resultfile; diff --git a/tests/flit_src/tst_FlitCsv_h.cpp b/tests/flit_src/tst_FlitCsv_h.cpp index f467d5e9..6fc1a35d 100644 --- a/tests/flit_src/tst_FlitCsv_h.cpp +++ b/tests/flit_src/tst_FlitCsv_h.cpp @@ -89,23 +89,32 @@ TH_REGISTER(tst_CsvRow_operator_brackets_int); namespace tst_CsvReader { void tst_Csv() { std::istringstream in( - "first,second,third,fourth\n" + "first,second,third,fourth\n" // header row "a, b,c,\n" "1,2,3,4,5,6,7\n" "\n" + "hello,\"there,my\",friends,\"newline \n" + "in quotes\"" ); flit::CsvReader csv(in); flit::CsvRow row; csv >> row; - auto &header = *row.header(); - TH_EQUAL(header, flit::CsvRow({"first", "second", "third", "fourth"})); + flit::CsvRow expected_header {"first", "second", "third", "fourth"}; + TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({"a", " b", "c", ""})); csv >> row; + TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({"1", "2", "3", "4", "5", "6", "7"})); csv >> row; + TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({""})); + + csv >> row; + TH_EQUAL(*row.header(), expected_header); + TH_EQUAL(row, flit::CsvRow({"hello", "there,my", "friends", + "newline \nin quotes"})); } TH_REGISTER(tst_Csv); } // end of namespace tst_CsvReader From 19776f947158163a6b12b0c81fe0d05183246f23 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 11:53:34 -0600 Subject: [PATCH 074/196] rename tst_FlitCsv_h.cpp -> tst_FlitCsv.cpp --- tests/flit_src/{tst_FlitCsv_h.cpp => tst_FlitCsv.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/flit_src/{tst_FlitCsv_h.cpp => tst_FlitCsv.cpp} (100%) diff --git a/tests/flit_src/tst_FlitCsv_h.cpp b/tests/flit_src/tst_FlitCsv.cpp similarity index 100% rename from tests/flit_src/tst_FlitCsv_h.cpp rename to tests/flit_src/tst_FlitCsv.cpp From f82e4fdcb5c558c932e2f4aa039f9f25d839e46f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 11:55:11 -0600 Subject: [PATCH 075/196] FlitCsv: add support for range based for loops Use the new range-based for loop and test it --- src/FlitCsv.cpp | 3 +- src/FlitCsv.h | 41 +++++++++++-- src/flit.cpp | 9 +-- tests/flit_src/tst_FlitCsv.cpp | 104 +++++++++++++++++++++++++++++---- 4 files changed, 134 insertions(+), 23 deletions(-) diff --git a/src/FlitCsv.cpp b/src/FlitCsv.cpp index 5104517c..8209a21e 100644 --- a/src/FlitCsv.cpp +++ b/src/FlitCsv.cpp @@ -83,7 +83,8 @@ CsvRow CsvReader::parseRow(std::istream &in) { } // If we stopped because we reached the end of file... - if (!in && running_size > 0) { + // (i.e. ignore empty last rows) + if (!in && !row.empty()) { row.emplace_back(running.str()); } diff --git a/src/FlitCsv.h b/src/FlitCsv.h index 4382ab9d..431598b9 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -39,15 +39,45 @@ class CsvReader { } operator bool() const { return static_cast(m_in); } - CsvRow header() { return m_header; } + CsvRow* header() { return &m_header; } std::istream& stream() { return m_in; } CsvReader& operator>> (CsvRow& row) { row = CsvReader::parseRow(m_in); - row.setHeader(&m_header); + row.setHeader(this->header()); return *this; } + class Iterator { + public: + Iterator() : m_reader(nullptr) {} + Iterator(CsvReader* reader) : m_reader(reader) { *reader >> row; } + + Iterator& operator++() { + if (m_reader == nullptr) { + throw std::out_of_range("Went beyond the CSV file"); + } + *m_reader >> row; + if (row.empty()) { + m_reader = nullptr; // mark the iterator as reaching the end + } + return *this; + } + + bool operator != (const Iterator& other) const { + return this->m_reader != other.m_reader; + } + + CsvRow& operator*() { return row; } + + private: + CsvReader *m_reader; + CsvRow row; + }; + + CsvReader::Iterator begin() { return Iterator(this); }; + CsvReader::Iterator end() { return Iterator(); }; + private: static CsvRow parseRow(std::istream &in); @@ -76,13 +106,14 @@ class CsvWriter { this->m_is_line_beginning = true; } - void write_row (const std::vector& row) { + template + void write_row (const std::vector& row) { if (!this->m_is_line_beginning) { throw std::runtime_error("Cannot write a row to a partially created " "row. Call CsvWriter::new_row() first"); } - for (auto &elem : row) { - this->write_val(elem); + for (const T &elem : row) { + *this << elem; } this->new_row(); } diff --git a/src/flit.cpp b/src/flit.cpp index 7eeb809d..bdadee39 100644 --- a/src/flit.cpp +++ b/src/flit.cpp @@ -394,13 +394,8 @@ std::string readFile(const std::string &filename) { std::vector parseResults(std::istream &in) { std::vector results; - CsvReader csv(in); - CsvRow row; - while (csv) { - csv >> row; - if (row.empty()) { - break; - } + CsvReader reader(in); + for (auto &row : reader) { auto nanosec = std::stol(row["nanosec"]); Variant value; std::string resultfile; diff --git a/tests/flit_src/tst_FlitCsv.cpp b/tests/flit_src/tst_FlitCsv.cpp index 6fc1a35d..02d49f91 100644 --- a/tests/flit_src/tst_FlitCsv.cpp +++ b/tests/flit_src/tst_FlitCsv.cpp @@ -87,39 +87,123 @@ TH_REGISTER(tst_CsvRow_operator_brackets_int); } // end of namespace tst_CsvRow namespace tst_CsvReader { -void tst_Csv() { +void tst_CsvReader_general() { std::istringstream in( "first,second,third,fourth\n" // header row "a, b,c,\n" "1,2,3,4,5,6,7\n" "\n" "hello,\"there,my\",friends,\"newline \n" - "in quotes\"" + "in quotes\"," ); - flit::CsvReader csv(in); - flit::CsvRow row; - csv >> row; + + flit::CsvReader reader(in); flit::CsvRow expected_header {"first", "second", "third", "fourth"}; + TH_EQUAL(*reader.header(), expected_header); + + flit::CsvRow row; + reader >> row; TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({"a", " b", "c", ""})); + TH_VERIFY(reader); - csv >> row; + reader >> row; TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({"1", "2", "3", "4", "5", "6", "7"})); + TH_VERIFY(reader); - csv >> row; + reader >> row; TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({""})); + TH_VERIFY(reader); - csv >> row; + reader >> row; TH_EQUAL(*row.header(), expected_header); TH_EQUAL(row, flit::CsvRow({"hello", "there,my", "friends", - "newline \nin quotes"})); + "newline \nin quotes", ""})); + TH_VERIFY(!reader); } -TH_REGISTER(tst_Csv); +TH_REGISTER(tst_CsvReader_general); } // end of namespace tst_CsvReader + namespace tst_CsvWriter { +/// Tests that the CsvWriter will end the file in a newline (if writing rows) +void tst_CsvWriter_write_row_addsNewline() { + std::istringstream in( + "first,second,third,fourth\n" // header row + "a, b,c," + ); + std::ostringstream out; + + flit::CsvReader reader(in); + flit::CsvWriter writer(out); + + writer.write_row(*reader.header()); + while (reader) { + flit::CsvRow row; + reader >> row; + if (row.empty()) { + break; + } + writer.write_row(row); + } + + TH_EQUAL(out.str().back(), '\n'); + TH_EQUAL(in.str() + '\n', out.str()); + + // Try the range-based for loop + std::istringstream in2(in.str()); + out.str(""); + flit::CsvReader reader2(in2); + + writer.write_row(*reader2.header()); + for (auto &row : reader2) { writer.write_row(row); } + + TH_EQUAL(out.str().back(), '\n'); + TH_EQUAL(in2.str() + '\n', out.str()); +} +TH_REGISTER(tst_CsvWriter_write_row_addsNewline); + +/// Tests that CsvWriter can write out the exact same csv read in +void tst_CsvWriter_write_row_exactly() { + std::istringstream in( + "first,second,third,fourth\n" // header row + "a, b,c,\n" + "1,2,3,4,5,6,7\n" + "\n" + "hello,\"there,my\",friends,\"newline \n" + "in quotes\",\n" + ); + std::ostringstream out; + + flit::CsvReader reader(in); + flit::CsvWriter writer(out); + + writer.write_row(*reader.header()); + while (reader) { + flit::CsvRow row; + reader >> row; + if (row.empty()) { + break; + } + writer.write_row(row); + } + + TH_EQUAL(in.str(), out.str()); + + // Try the range-based for loop + std::istringstream in2(in.str()); + out.str(""); + flit::CsvReader reader2(in2); + + writer.write_row(*reader2.header()); + for (auto &row : reader2) { writer.write_row(row); } + + TH_EQUAL(in.str(), out.str()); +} +TH_REGISTER(tst_CsvWriter_write_row_exactly); + } // end of namespace tst_CsvWriter From 2f46d4ab4a631ab3f79fec29db478e35902b8a80 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 12:24:58 -0600 Subject: [PATCH 076/196] CsvRow: implement == and != --- src/FlitCsv.h | 37 ++++++++++++++++++++++++++++------ tests/flit_src/tst_FlitCsv.cpp | 32 +++++++++++++++++++---------- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/FlitCsv.h b/src/FlitCsv.h index 431598b9..74dfc3f1 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -24,6 +24,36 @@ class CsvRow : public std::vector { using std::vector::operator[]; std::string const& operator[](std::string col) const; + bool operator!=(const CsvRow &other) { + // Check the header + if (this->header() == nullptr && other.header() != nullptr) { + return true; + } + if (this->header() != nullptr && other.header() == nullptr) { + return true; + } + if (this->header() != nullptr && + other.header() != nullptr && + *this->header() != *other.header()) + { + return true; + } + + // Check row contents + if (this->size() != other.size()) { + return true; + } + for (CsvRow::size_type i = 0; i < this->size(); i++) { + if (this->at(i) != other.at(i)) { + return true; + } + } + + return false; + } + + bool operator==(const CsvRow &other) { return !(*this != other); } + private: CsvRow* m_header {nullptr}; // not owned by this class }; @@ -31,12 +61,7 @@ class CsvRow : public std::vector { /** Class for parsing csv files */ class CsvReader { public: - CsvReader(std::istream &in) - : m_header(CsvReader::parseRow(in)) - , m_in(in) - { - m_header.setHeader(&m_header); - } + CsvReader(std::istream &in) : m_header(CsvReader::parseRow(in)), m_in(in) {} operator bool() const { return static_cast(m_in); } CsvRow* header() { return &m_header; } diff --git a/tests/flit_src/tst_FlitCsv.cpp b/tests/flit_src/tst_FlitCsv.cpp index 02d49f91..e6d3f3eb 100644 --- a/tests/flit_src/tst_FlitCsv.cpp +++ b/tests/flit_src/tst_FlitCsv.cpp @@ -87,7 +87,7 @@ TH_REGISTER(tst_CsvRow_operator_brackets_int); } // end of namespace tst_CsvRow namespace tst_CsvReader { -void tst_CsvReader_general() { +void tst_CsvReader_oneRowAtATime() { std::istringstream in( "first,second,third,fourth\n" // header row "a, b,c,\n" @@ -103,27 +103,37 @@ void tst_CsvReader_general() { flit::CsvRow row; reader >> row; - TH_EQUAL(*row.header(), expected_header); - TH_EQUAL(row, flit::CsvRow({"a", " b", "c", ""})); + flit::CsvRow expected_row; + expected_row = {"a", " b", "c", ""}; + expected_row.setHeader(&expected_header); + TH_EQUAL(row, expected_row); TH_VERIFY(reader); reader >> row; - TH_EQUAL(*row.header(), expected_header); - TH_EQUAL(row, flit::CsvRow({"1", "2", "3", "4", "5", "6", "7"})); + expected_row = {"1", "2", "3", "4", "5", "6", "7"}; + expected_row.setHeader(&expected_header); + TH_EQUAL(row, expected_row); TH_VERIFY(reader); reader >> row; - TH_EQUAL(*row.header(), expected_header); - TH_EQUAL(row, flit::CsvRow({""})); + expected_row = {""}; + expected_row.setHeader(&expected_header); + TH_EQUAL(row, expected_row); TH_VERIFY(reader); reader >> row; - TH_EQUAL(*row.header(), expected_header); - TH_EQUAL(row, flit::CsvRow({"hello", "there,my", "friends", - "newline \nin quotes", ""})); + expected_row = {"hello", "there,my", "friends", "newline \nin quotes", ""}; + expected_row.setHeader(&expected_header); + TH_EQUAL(row, expected_row); TH_VERIFY(!reader); + + reader >> row; + expected_row = {}; + expected_row.setHeader(&expected_header); + TH_VERIFY(row.empty()); + TH_EQUAL(row, expected_row); } -TH_REGISTER(tst_CsvReader_general); +TH_REGISTER(tst_CsvReader_oneRowAtATime); } // end of namespace tst_CsvReader From 497338c7bd5aff6f886593e9573720ad6a91efe9 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 12:57:44 -0600 Subject: [PATCH 077/196] CsvReader: make its iterator a proper InputIterator --- src/FlitCsv.h | 15 +++++++-- tests/flit_src/tst_FlitCsv.cpp | 57 ++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/FlitCsv.h b/src/FlitCsv.h index 74dfc3f1..c153803f 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -75,8 +75,18 @@ class CsvReader { class Iterator { public: + using difference_type = long; + using value_type = std::string; + using reference = std::string&; + using pointer = std::string*; + using iterator_category = std::input_iterator_tag; + Iterator() : m_reader(nullptr) {} Iterator(CsvReader* reader) : m_reader(reader) { *reader >> row; } + Iterator(const Iterator &other) = default; + Iterator(Iterator &&other) = default; + Iterator& operator= (const Iterator &other) = default; + Iterator& operator= (Iterator &&other) = default; Iterator& operator++() { if (m_reader == nullptr) { @@ -89,9 +99,10 @@ class CsvReader { return *this; } - bool operator != (const Iterator& other) const { - return this->m_reader != other.m_reader; + bool operator == (const Iterator& other) const { + return this->m_reader == other.m_reader; } + bool operator != (const Iterator& other) const { return !(*this == other); } CsvRow& operator*() { return row; } diff --git a/tests/flit_src/tst_FlitCsv.cpp b/tests/flit_src/tst_FlitCsv.cpp index e6d3f3eb..c15c2cc9 100644 --- a/tests/flit_src/tst_FlitCsv.cpp +++ b/tests/flit_src/tst_FlitCsv.cpp @@ -134,6 +134,63 @@ void tst_CsvReader_oneRowAtATime() { TH_EQUAL(row, expected_row); } TH_REGISTER(tst_CsvReader_oneRowAtATime); + +void tst_CsvReader_rangeBasedFor() { + std::istringstream in( + "first,second,third,fourth\n" // header row + "a, b,c,\n" + "1,2,3,4,5,6,7\n" + "\n" + "hello,\"there,my\",friends,\"newline \n" + "in quotes\"," + ); + + flit::CsvReader reader(in); + flit::CsvRow expected_header {"first", "second", "third", "fourth"}; + TH_EQUAL(*reader.header(), expected_header); + + std::vector expected_rows = { + {"a", " b", "c", ""}, + {"1", "2", "3", "4", "5", "6", "7"}, + {""}, + {"hello", "there,my", "friends", "newline \nin quotes", ""}, + }; + for (auto &row : expected_rows) { row.setHeader(&expected_header); } + decltype(expected_rows) rows; + auto it = expected_rows.begin(); + for (flit::CsvRow &row : reader) { + TH_EQUAL(row, *it++); + rows.push_back(row); + } + TH_EQUAL(rows, expected_rows); +} +TH_REGISTER(tst_CsvReader_rangeBasedFor); + +void tst_CsvReader_createRowVector() { + std::istringstream in( + "first,second,third,fourth\n" // header row + "a, b,c,\n" + "1,2,3,4,5,6,7\n" + "\n" + "hello,\"there,my\",friends,\"newline \n" + "in quotes\"," + ); + + flit::CsvReader reader(in); + flit::CsvRow expected_header {"first", "second", "third", "fourth"}; + TH_EQUAL(*reader.header(), expected_header); + + std::vector expected_rows = { + {"a", " b", "c", ""}, + {"1", "2", "3", "4", "5", "6", "7"}, + {""}, + {"hello", "there,my", "friends", "newline \nin quotes", ""}, + }; + for (auto &row : expected_rows) { row.setHeader(&expected_header); } + decltype(expected_rows) rows (reader.begin(), reader.end()); + TH_EQUAL(rows, expected_rows); +} + } // end of namespace tst_CsvReader From 861829fee1f1a37676494e300cbc82d8e05705fe Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 13:06:34 -0600 Subject: [PATCH 078/196] CsvWriter: remove write_val() function --- src/FlitCsv.cpp | 20 --------------- src/FlitCsv.h | 67 ++++++++++++++++++++++--------------------------- 2 files changed, 30 insertions(+), 57 deletions(-) diff --git a/src/FlitCsv.cpp b/src/FlitCsv.cpp index 8209a21e..288e2226 100644 --- a/src/FlitCsv.cpp +++ b/src/FlitCsv.cpp @@ -45,9 +45,6 @@ CsvRow CsvReader::parseRow(std::istream &in) { std::ostringstream running; int running_size = 0; while (in.get(current)) { - //std::cout << "parsing csv, current char: " << current - // << ", state = " << static_cast(state) - // << std::endl; if (state == State::DEFAULT) { if (running_size == 0 && current == quote_char) { transition_state(State::IN_STRING); @@ -88,23 +85,6 @@ CsvRow CsvReader::parseRow(std::istream &in) { row.emplace_back(running.str()); } - //std::string line; - //std::getline(in, line); - - //std::stringstream lineStream(line); - //std::string token; - - //// tokenize on ',' - //CsvRow row; - //while(std::getline(lineStream, token, ',')) { - // row.emplace_back(token); - //} - - //// check for trailing comma with no data after it - //if (!lineStream && token.empty()) { - // row.emplace_back(""); - //} - return row; } diff --git a/src/FlitCsv.h b/src/FlitCsv.h index c153803f..cefe5a1c 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -128,15 +128,6 @@ class CsvWriter { : m_out(out), m_is_line_beginning(true) {} virtual ~CsvWriter() {} - template - CsvWriter& operator<< (const T &val) { - this->write_val(val); - return *this; - } - - template - void write_val (const T val) { append(val); } - void new_row() { this->m_out << std::endl; this->m_is_line_beginning = true; @@ -154,6 +145,36 @@ class CsvWriter { this->new_row(); } +#define FLIT_CSVWRITER_OPERATOR(type) \ + CsvWriter& operator<< (const type val) { \ + this->append(val); \ + return *this; \ + } + + FLIT_CSVWRITER_OPERATOR(int); + FLIT_CSVWRITER_OPERATOR(long); + FLIT_CSVWRITER_OPERATOR(long long); + FLIT_CSVWRITER_OPERATOR(unsigned int); + FLIT_CSVWRITER_OPERATOR(unsigned long); + FLIT_CSVWRITER_OPERATOR(unsigned long long); + FLIT_CSVWRITER_OPERATOR(unsigned __int128); + FLIT_CSVWRITER_OPERATOR(float); + FLIT_CSVWRITER_OPERATOR(double); + FLIT_CSVWRITER_OPERATOR(long double); + +#undef FLIT_CSVWRITER_OPERATOR + + // handle std::string separately + CsvWriter& operator<< (const std::string &val) { + // if there are offending characters in val, then quote the field + if (val.find_first_of(",\r\n") != std::string::npos) { + this->append('"' + val + '"'); + } else { + this->append(val); + } + return *this; + } + private: template CsvWriter& append(const T &val) { @@ -170,35 +191,7 @@ class CsvWriter { bool m_is_line_beginning; }; -#define CSVWRITER_OPERATOR(type) \ - inline CsvWriter& operator<< (CsvWriter& out, const type val) { \ - out.write_val(val); \ - return out; \ - } -CSVWRITER_OPERATOR(int); -CSVWRITER_OPERATOR(long); -CSVWRITER_OPERATOR(long long); -CSVWRITER_OPERATOR(unsigned int); -CSVWRITER_OPERATOR(unsigned long); -CSVWRITER_OPERATOR(unsigned long long); -CSVWRITER_OPERATOR(unsigned __int128); -CSVWRITER_OPERATOR(float); -CSVWRITER_OPERATOR(double); -CSVWRITER_OPERATOR(long double); - -#undef CSVWRITER_OPERATOR - -// handle std::string separately -inline CsvWriter& operator<< (CsvWriter& out, const std::string &val) { - // if there are offending characters in val, then quote the field - if (val.find_first_of(",\r\n") != std::string::npos) { - out.write_val('"' + val + '"'); - } else { - out.write_val(val); - } - return out; -} } // end of namespace flit From d1563b93889247d06a651c54d47485bec8e17251 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 13:08:21 -0600 Subject: [PATCH 079/196] small change --- src/FlitCsv.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/FlitCsv.h b/src/FlitCsv.h index cefe5a1c..2564d899 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -177,13 +177,12 @@ class CsvWriter { private: template - CsvWriter& append(const T &val) { + void append(const T &val) { if (!this->m_is_line_beginning) { this->m_out << ','; } this->m_is_line_beginning = false; this->m_out << val; - return *this; } private: From 20759966e71283ab89f4689a4a48e1444bf2f801 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 13:13:51 -0600 Subject: [PATCH 080/196] Add license headers for new files --- src/FlitCsv.cpp | 83 ++++++++++++++++++++++++++++++++++ src/FlitCsv.h | 83 ++++++++++++++++++++++++++++++++++ tests/flit_src/tst_FlitCsv.cpp | 83 ++++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+) diff --git a/src/FlitCsv.cpp b/src/FlitCsv.cpp index 288e2226..f6da743e 100644 --- a/src/FlitCsv.cpp +++ b/src/FlitCsv.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "FlitCsv.h" #include diff --git a/src/FlitCsv.h b/src/FlitCsv.h index 2564d899..2a5d546f 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #ifndef FLIT_CSV_H #define FLIT_CSV_H diff --git a/tests/flit_src/tst_FlitCsv.cpp b/tests/flit_src/tst_FlitCsv.cpp index c15c2cc9..5ee40c31 100644 --- a/tests/flit_src/tst_FlitCsv.cpp +++ b/tests/flit_src/tst_FlitCsv.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "test_harness.h" #include "FlitCsv.h" From 80fe6e4d9ed9e742d60c9cf955ffc6d24c455516 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 13:31:18 -0600 Subject: [PATCH 081/196] flit.cpp: update use of CsvReader in parseMetadata() --- src/flit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flit.cpp b/src/flit.cpp index bdadee39..37421931 100644 --- a/src/flit.cpp +++ b/src/flit.cpp @@ -430,7 +430,8 @@ std::unordered_map parseMetadata(std::istream &in) { CsvReader csv(in); CsvRow row; - if (csv >> row) { + csv >> row; + if (!row.empty()) { for (auto key : metadataKeys) { metadata.emplace(key, row[key]); } From 1cf01c3bb3b5c08d09c731e34ddc70fce72cef1b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 14:40:39 -0600 Subject: [PATCH 082/196] CsvReader: get working the bool correctly --- src/FlitCsv.h | 11 ++++++++--- tests/flit_src/tst_FlitCsv.cpp | 23 ++++++----------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/FlitCsv.h b/src/FlitCsv.h index 2a5d546f..b2fb63cd 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -144,15 +144,19 @@ class CsvRow : public std::vector { /** Class for parsing csv files */ class CsvReader { public: - CsvReader(std::istream &in) : m_header(CsvReader::parseRow(in)), m_in(in) {} + CsvReader(std::istream &in) + : m_header(CsvReader::parseRow(in)), m_in(in), m_is_done(!bool(in)) {} - operator bool() const { return static_cast(m_in); } + operator bool() const { return !m_is_done; } CsvRow* header() { return &m_header; } std::istream& stream() { return m_in; } CsvReader& operator>> (CsvRow& row) { row = CsvReader::parseRow(m_in); row.setHeader(this->header()); + if (row.empty()) { + m_is_done = true; + } return *this; } @@ -176,7 +180,7 @@ class CsvReader { throw std::out_of_range("Went beyond the CSV file"); } *m_reader >> row; - if (row.empty()) { + if (!*m_reader) { m_reader = nullptr; // mark the iterator as reaching the end } return *this; @@ -203,6 +207,7 @@ class CsvReader { private: CsvRow m_header; std::istream &m_in; + bool m_is_done; }; class CsvWriter { diff --git a/tests/flit_src/tst_FlitCsv.cpp b/tests/flit_src/tst_FlitCsv.cpp index 5ee40c31..8ad7e57e 100644 --- a/tests/flit_src/tst_FlitCsv.cpp +++ b/tests/flit_src/tst_FlitCsv.cpp @@ -208,13 +208,14 @@ void tst_CsvReader_oneRowAtATime() { expected_row = {"hello", "there,my", "friends", "newline \nin quotes", ""}; expected_row.setHeader(&expected_header); TH_EQUAL(row, expected_row); - TH_VERIFY(!reader); + TH_VERIFY(reader); reader >> row; expected_row = {}; expected_row.setHeader(&expected_header); TH_VERIFY(row.empty()); TH_EQUAL(row, expected_row); + TH_VERIFY(!reader); } TH_REGISTER(tst_CsvReader_oneRowAtATime); @@ -291,14 +292,8 @@ void tst_CsvWriter_write_row_addsNewline() { flit::CsvWriter writer(out); writer.write_row(*reader.header()); - while (reader) { - flit::CsvRow row; - reader >> row; - if (row.empty()) { - break; - } - writer.write_row(row); - } + flit::CsvRow row; + while (reader >> row) { writer.write_row(row); } TH_EQUAL(out.str().back(), '\n'); TH_EQUAL(in.str() + '\n', out.str()); @@ -332,14 +327,8 @@ void tst_CsvWriter_write_row_exactly() { flit::CsvWriter writer(out); writer.write_row(*reader.header()); - while (reader) { - flit::CsvRow row; - reader >> row; - if (row.empty()) { - break; - } - writer.write_row(row); - } + flit::CsvRow row; + while (reader >> row) { writer.write_row(row); } TH_EQUAL(in.str(), out.str()); From b703dace4fb850521371f06e914d6a7ddc0600d3 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 22 Aug 2018 14:44:39 -0600 Subject: [PATCH 083/196] CsvReader: remove iterator for simplicity --- src/FlitCsv.h | 41 ------------------------- src/flit.cpp | 3 +- tests/flit_src/tst_FlitCsv.cpp | 55 ++-------------------------------- 3 files changed, 4 insertions(+), 95 deletions(-) diff --git a/src/FlitCsv.h b/src/FlitCsv.h index b2fb63cd..dcb1ade4 100644 --- a/src/FlitCsv.h +++ b/src/FlitCsv.h @@ -160,47 +160,6 @@ class CsvReader { return *this; } - class Iterator { - public: - using difference_type = long; - using value_type = std::string; - using reference = std::string&; - using pointer = std::string*; - using iterator_category = std::input_iterator_tag; - - Iterator() : m_reader(nullptr) {} - Iterator(CsvReader* reader) : m_reader(reader) { *reader >> row; } - Iterator(const Iterator &other) = default; - Iterator(Iterator &&other) = default; - Iterator& operator= (const Iterator &other) = default; - Iterator& operator= (Iterator &&other) = default; - - Iterator& operator++() { - if (m_reader == nullptr) { - throw std::out_of_range("Went beyond the CSV file"); - } - *m_reader >> row; - if (!*m_reader) { - m_reader = nullptr; // mark the iterator as reaching the end - } - return *this; - } - - bool operator == (const Iterator& other) const { - return this->m_reader == other.m_reader; - } - bool operator != (const Iterator& other) const { return !(*this == other); } - - CsvRow& operator*() { return row; } - - private: - CsvReader *m_reader; - CsvRow row; - }; - - CsvReader::Iterator begin() { return Iterator(this); }; - CsvReader::Iterator end() { return Iterator(); }; - private: static CsvRow parseRow(std::istream &in); diff --git a/src/flit.cpp b/src/flit.cpp index 37421931..019e138d 100644 --- a/src/flit.cpp +++ b/src/flit.cpp @@ -395,7 +395,8 @@ std::vector parseResults(std::istream &in) { std::vector results; CsvReader reader(in); - for (auto &row : reader) { + CsvRow row; + for (CsvRow row; reader >> row; ) { auto nanosec = std::stol(row["nanosec"]); Variant value; std::string resultfile; diff --git a/tests/flit_src/tst_FlitCsv.cpp b/tests/flit_src/tst_FlitCsv.cpp index 8ad7e57e..167a0b4d 100644 --- a/tests/flit_src/tst_FlitCsv.cpp +++ b/tests/flit_src/tst_FlitCsv.cpp @@ -219,37 +219,6 @@ void tst_CsvReader_oneRowAtATime() { } TH_REGISTER(tst_CsvReader_oneRowAtATime); -void tst_CsvReader_rangeBasedFor() { - std::istringstream in( - "first,second,third,fourth\n" // header row - "a, b,c,\n" - "1,2,3,4,5,6,7\n" - "\n" - "hello,\"there,my\",friends,\"newline \n" - "in quotes\"," - ); - - flit::CsvReader reader(in); - flit::CsvRow expected_header {"first", "second", "third", "fourth"}; - TH_EQUAL(*reader.header(), expected_header); - - std::vector expected_rows = { - {"a", " b", "c", ""}, - {"1", "2", "3", "4", "5", "6", "7"}, - {""}, - {"hello", "there,my", "friends", "newline \nin quotes", ""}, - }; - for (auto &row : expected_rows) { row.setHeader(&expected_header); } - decltype(expected_rows) rows; - auto it = expected_rows.begin(); - for (flit::CsvRow &row : reader) { - TH_EQUAL(row, *it++); - rows.push_back(row); - } - TH_EQUAL(rows, expected_rows); -} -TH_REGISTER(tst_CsvReader_rangeBasedFor); - void tst_CsvReader_createRowVector() { std::istringstream in( "first,second,third,fourth\n" // header row @@ -271,7 +240,8 @@ void tst_CsvReader_createRowVector() { {"hello", "there,my", "friends", "newline \nin quotes", ""}, }; for (auto &row : expected_rows) { row.setHeader(&expected_header); } - decltype(expected_rows) rows (reader.begin(), reader.end()); + decltype(expected_rows) rows; + for (flit::CsvRow row; reader >> row;) { rows.emplace_back(row); } TH_EQUAL(rows, expected_rows); } @@ -297,17 +267,6 @@ void tst_CsvWriter_write_row_addsNewline() { TH_EQUAL(out.str().back(), '\n'); TH_EQUAL(in.str() + '\n', out.str()); - - // Try the range-based for loop - std::istringstream in2(in.str()); - out.str(""); - flit::CsvReader reader2(in2); - - writer.write_row(*reader2.header()); - for (auto &row : reader2) { writer.write_row(row); } - - TH_EQUAL(out.str().back(), '\n'); - TH_EQUAL(in2.str() + '\n', out.str()); } TH_REGISTER(tst_CsvWriter_write_row_addsNewline); @@ -331,16 +290,6 @@ void tst_CsvWriter_write_row_exactly() { while (reader >> row) { writer.write_row(row); } TH_EQUAL(in.str(), out.str()); - - // Try the range-based for loop - std::istringstream in2(in.str()); - out.str(""); - flit::CsvReader reader2(in2); - - writer.write_row(*reader2.header()); - for (auto &row : reader2) { writer.write_row(row); } - - TH_EQUAL(in.str(), out.str()); } TH_REGISTER(tst_CsvWriter_write_row_exactly); From dd6a5be1d824af7c6a459b2f66686ab9f6b334b7 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 4 Sep 2018 10:56:22 -0600 Subject: [PATCH 084/196] first attempt to implement custom compiler location --- data/Makefile.in | 22 +++++---- scripts/flitcli/config/flit-default.toml.in | 29 +++++++++--- scripts/flitcli/flit_update.py | 51 +++++++++++++-------- 3 files changed, 68 insertions(+), 34 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 3a85f741..979ea561 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -89,6 +89,11 @@ GT_OUT := ground-truth.csv UNAME_S := $(shell uname -s) +# will be None if not specified in flit-config.toml +CLANG := {clang_compiler} +INTEL := {intel_compiler} +GCC := {gcc_compiler} + FLIT_INC_DIR := {flit_include_dir} FLIT_LIB_DIR := {flit_lib_dir} FLIT_DATA_DIR := {flit_data_dir} @@ -220,16 +225,17 @@ DEV_DEPS = $(DEV_OBJ:%.o=%.d) GT_OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_gt.o))) GT_DEPS = $(GT_OBJ:%.o=%.d) -CLANG := clang++ -INTEL := icpc -GCC := g++ +# checks for string equality between $1 and $2 +# note: will return false if both $1 and $2 are empty +equal = $(and $(findstring $1,$2),$(findstring $2,$1)) +not_equal = $(if $(call equal,$1,$2),,good) -ifdef CLANG_ONLY -COMPILERS := CLANG -else +# keep only the compilers that are not None and are in the path COMPILERS := $(foreach c, GCC INTEL CLANG, \ - $(if $(shell which $($(c)) 2>/dev/null), $c,)) -endif + $(if \ + $(and \ + $(call not_equal,None,$($(c))),\ + $(shell which $($(c)) 2>/dev/null), $c,))) HOSTNAME := $(shell hostname) diff --git a/scripts/flitcli/config/flit-default.toml.in b/scripts/flitcli/config/flit-default.toml.in index c7c5d054..a6e16b10 100644 --- a/scripts/flitcli/config/flit-default.toml.in +++ b/scripts/flitcli/config/flit-default.toml.in @@ -140,13 +140,30 @@ optimization_level = '-O0' switches = '' # This host's list of compilers. - # For now, only used for hosts.ground_truth and hosts.dev_build. - # TODO: use this list to generate the Makefile - [[hosts.compilers]] + # - binary: can be an absolute path, relative path, or binary name (found in + # PATH). If you want to specify a compiler in the same directory as this + # config file, prepend with a "./" (e.g. "./my-compiler") + # - name: can be any string. Used to recognize in the other options such as + # dev_build and ground_truth + # - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') + # Currently, only one of each type may be specified. + # Note that these are all defaulted to use g++, clang++, and icpc from the + # PATH. + # If you specify any one compiler, then these defaults are erased. If you + # specify no compiler, then these defaults take effect. - # binary can be an absolute path, relative path, or binary name (found in - # PATH). If you want to specify a compiler in the same directory as this - # config file, prepend with a "./" (e.g. "./my-compiler") + [[hosts.compilers]] binary = 'g++' name = 'g++' + type = 'gcc' + + [[hosts.compilers]] + binary = 'clang++' + name = 'clang++' + type = 'clang' + + [[hosts.compilers]] + binary = 'icpc' + name = 'icpc' + type = 'intel' diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index f3582db3..e4d9c179 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -152,6 +152,15 @@ def main(arguments, prog=sys.argv[0]): if '/' in dev_compiler_bin: gt_compiler_bin = os.path.realpath(gt_compiler_bin) + supported_compiler_types = ('clang', 'gcc', 'intel') + base_compilers = {x: None for x in supported_compiler_types} + for compiler in host['compilers']: + assert compiler['type'] in supported_compiler_types, \ + 'Unsupported compiler type: {}'.format(brand) + assert base_compilers[compiler['type']] is None, \ + 'You can only specify one of each type of compiler.' + base_compilers[compiler['type']] = compiler['binary'] + test_run_args = '' if not projconf['run']['timing']: test_run_args = '--no-timing' @@ -160,26 +169,28 @@ def main(arguments, prog=sys.argv[0]): '--timing-loops', str(projconf['run']['timing_loops']), '--timing-repeats', str(projconf['run']['timing_repeats']), ]) - flitutil.process_in_file( - os.path.join(conf.data_dir, 'Makefile.in'), - makefile, - { - 'dev_compiler': dev_compiler_bin, - 'dev_optl': dev_optl, - 'dev_switches': dev_switches, - 'ground_truth_compiler': gt_compiler_bin, - 'ground_truth_optl': gt_optl, - 'ground_truth_switches': gt_switches, - 'flit_include_dir': conf.include_dir, - 'flit_lib_dir': conf.lib_dir, - 'flit_data_dir': conf.data_dir, - 'flit_script_dir': conf.script_dir, - 'flit_version': conf.version, - 'test_run_args': test_run_args, - 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', - 'mpirun_args': projconf['run']['mpirun_args'], - }, - overwrite=True) + + replacements = { + 'dev_compiler': dev_compiler_bin, + 'dev_optl': dev_optl, + 'dev_switches': dev_switches, + 'ground_truth_compiler': gt_compiler_bin, + 'ground_truth_optl': gt_optl, + 'ground_truth_switches': gt_switches, + 'flit_include_dir': conf.include_dir, + 'flit_lib_dir': conf.lib_dir, + 'flit_data_dir': conf.data_dir, + 'flit_script_dir': conf.script_dir, + 'flit_version': conf.version, + 'test_run_args': test_run_args, + 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', + 'mpirun_args': projconf['run']['mpirun_args'], + } + replacements.update({key + '_compiler': val + for key, val in base_compilers.items()}) + + flitutil.process_in_file(os.path.join(conf.data_dir, 'Makefile.in'), + makefile, replacements, overwrite=True) if __name__ == '__main__': sys.exit(main(sys.argv[1:])) From e1bb9cb5ac13de80848a56d96b921632e7063824 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 4 Sep 2018 11:32:26 -0600 Subject: [PATCH 085/196] Makefile.in: create warnings for bad compiler paths --- data/Makefile.in | 10 ++++++++-- scripts/flitcli/flit_update.py | 8 ++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 979ea561..ed37531e 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -235,7 +235,10 @@ COMPILERS := $(foreach c, GCC INTEL CLANG, \ $(if \ $(and \ $(call not_equal,None,$($(c))),\ - $(shell which $($(c)) 2>/dev/null), $c,))) + $(shell which $($(c)) 2>/dev/null)), $c,)) +$(foreach c, $(filter-out $(COMPILERS),GCC INTEL CLANG), \ + $(if $(call not_equal,None,$($(c))), \ + $(warning Warning: Could not find compiler $($(c)) of type $(c)),)) HOSTNAME := $(shell hostname) @@ -243,8 +246,11 @@ RESULTS_DIR := results # on systems with non-standard gcc installations (such as module), clang may # be unable to determine the correct gcc toolchain +CLANG_REQUIRED := +ifeq ($(findstring GCC,$(COMPILERS)),GCC) GCC_TOOLCHAIN := $(dir $(shell which $(GCC) 2>/dev/null))/.. -CLANG_REQUIRED := --gcc-toolchain=$(GCC_TOOLCHAIN) +CLANG_REQUIRED += --gcc-toolchain=$(GCC_TOOLCHAIN) +endif # Compiler setting targets # taken from: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index e4d9c179..20d8e5d8 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -134,8 +134,8 @@ def main(arguments, prog=sys.argv[0]): assert len(matching_dev_compilers) < 2, \ 'Multiple compilers with name {0} found'.format(dev_compiler_name) dev_compiler_bin = matching_dev_compilers[0]['binary'] - if '/' in dev_compiler_bin: - dev_compiler_bin = os.path.realpath(dev_compiler_bin) + #if '/' in dev_compiler_bin: + # dev_compiler_bin = os.path.realpath(dev_compiler_bin) ground_truth = host['ground_truth'] gt_compiler_name = ground_truth['compiler_name'] @@ -149,8 +149,8 @@ def main(arguments, prog=sys.argv[0]): 'Multiple compilers with name {0} found'.format(gt_compiler_names) # TODO: use the compiler mnemonic rather than the path gt_compiler_bin = matching_gt_compilers[0]['binary'] - if '/' in dev_compiler_bin: - gt_compiler_bin = os.path.realpath(gt_compiler_bin) + #if '/' in dev_compiler_bin: + # gt_compiler_bin = os.path.realpath(gt_compiler_bin) supported_compiler_types = ('clang', 'gcc', 'intel') base_compilers = {x: None for x in supported_compiler_types} From 64b16a200be7c03175f29b870bbf31053bd4547f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 4 Sep 2018 12:23:21 -0600 Subject: [PATCH 086/196] Makefile.in: calculate included compilers in python --- data/Makefile.in | 13 +++---------- scripts/flitcli/flit_update.py | 3 +++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index ed37531e..95b1e642 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -94,6 +94,9 @@ CLANG := {clang_compiler} INTEL := {intel_compiler} GCC := {gcc_compiler} +# keep only the compilers that are not None and are in the path +COMPILERS := {compilers} + FLIT_INC_DIR := {flit_include_dir} FLIT_LIB_DIR := {flit_lib_dir} FLIT_DATA_DIR := {flit_data_dir} @@ -230,16 +233,6 @@ GT_DEPS = $(GT_OBJ:%.o=%.d) equal = $(and $(findstring $1,$2),$(findstring $2,$1)) not_equal = $(if $(call equal,$1,$2),,good) -# keep only the compilers that are not None and are in the path -COMPILERS := $(foreach c, GCC INTEL CLANG, \ - $(if \ - $(and \ - $(call not_equal,None,$($(c))),\ - $(shell which $($(c)) 2>/dev/null)), $c,)) -$(foreach c, $(filter-out $(COMPILERS),GCC INTEL CLANG), \ - $(if $(call not_equal,None,$($(c))), \ - $(warning Warning: Could not find compiler $($(c)) of type $(c)),)) - HOSTNAME := $(shell hostname) RESULTS_DIR := results diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 20d8e5d8..f1f84c5b 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -170,6 +170,8 @@ def main(arguments, prog=sys.argv[0]): '--timing-repeats', str(projconf['run']['timing_repeats']), ]) + given_compilers = [key.upper() for key, val in base_compilers.items() + if val is not None] replacements = { 'dev_compiler': dev_compiler_bin, 'dev_optl': dev_optl, @@ -185,6 +187,7 @@ def main(arguments, prog=sys.argv[0]): 'test_run_args': test_run_args, 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', 'mpirun_args': projconf['run']['mpirun_args'], + 'compilers': ' '.join(given_compilers), } replacements.update({key + '_compiler': val for key, val in base_compilers.items()}) From 9abeb217a0889efc7e38d29c0f73dbbb50ef3b4b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 4 Sep 2018 12:32:36 -0600 Subject: [PATCH 087/196] Makefile.in: remove equal and not_equal (were not used) --- data/Makefile.in | 5 ----- 1 file changed, 5 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 95b1e642..1188b1c3 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -228,11 +228,6 @@ DEV_DEPS = $(DEV_OBJ:%.o=%.d) GT_OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_gt.o))) GT_DEPS = $(GT_OBJ:%.o=%.d) -# checks for string equality between $1 and $2 -# note: will return false if both $1 and $2 are empty -equal = $(and $(findstring $1,$2),$(findstring $2,$1)) -not_equal = $(if $(call equal,$1,$2),,good) - HOSTNAME := $(shell hostname) RESULTS_DIR := results From ecb8522eebabda06ffbc4d732f2b93b3156024ec Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 5 Sep 2018 14:58:07 -0600 Subject: [PATCH 088/196] fix pylint identified errors --- scripts/flitcli/flit_import.py | 2 +- scripts/flitcli/flit_update.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/flitcli/flit_import.py b/scripts/flitcli/flit_import.py index 4b078dbc..61dd4e19 100644 --- a/scripts/flitcli/flit_import.py +++ b/scripts/flitcli/flit_import.py @@ -147,7 +147,7 @@ def main(arguments, prog=sys.argv[0]): try: projconf = toml.load('flit-config.toml') except FileNotFoundError: - print('Error: {0} not found. Run "flit init"'.format(tomlfile), + print('Error: flit-config.toml not found. Run "flit init"', file=sys.stderr) return 1 util.fill_defaults(projconf) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index f1f84c5b..14d782b6 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -146,7 +146,7 @@ def main(arguments, prog=sys.argv[0]): assert len(matching_dev_compilers) > 0, \ 'Compiler name {0} not found'.format(gt_compiler_name) assert len(matching_dev_compilers) < 2, \ - 'Multiple compilers with name {0} found'.format(gt_compiler_names) + 'Multiple compilers with name {0} found'.format(gt_compiler_name) # TODO: use the compiler mnemonic rather than the path gt_compiler_bin = matching_gt_compilers[0]['binary'] #if '/' in dev_compiler_bin: @@ -156,7 +156,7 @@ def main(arguments, prog=sys.argv[0]): base_compilers = {x: None for x in supported_compiler_types} for compiler in host['compilers']: assert compiler['type'] in supported_compiler_types, \ - 'Unsupported compiler type: {}'.format(brand) + 'Unsupported compiler type: {}'.format(compiler['type']) assert base_compilers[compiler['type']] is None, \ 'You can only specify one of each type of compiler.' base_compilers[compiler['type']] = compiler['binary'] From 5ce44ad3ba3e2482c19ec0fdede7721289db4019 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 5 Sep 2018 15:03:51 -0600 Subject: [PATCH 089/196] flit_bisect: fix problem when symbol bisect errors out --- scripts/flitcli/flit_bisect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 55e3f4c0..652f09bf 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1516,6 +1516,7 @@ def run_bisect(arguments, prog=sys.argv[0]): logging.exception( 'Failed to search for differing symbols in %s', differing_source) + return bisect_num, differing_libs, differing_sources, None, 1 differing_symbols.extend(file_differing_symbols) if len(file_differing_symbols) > 0: if args.biggest is None: @@ -1543,7 +1544,7 @@ def run_bisect(arguments, prog=sys.argv[0]): print('The {} highest variability symbol{}:' .format(args.biggest, 's' if args.biggest > 1 else '')) logging.info('THE %d HIGHEST VARIABILITY INDUCING SYMBOL%s:', - args.biggest, 'S' if args.biggest > 1 else '') + args.biggest, 'S' if args.biggest > 1 else '') for sym, score in differing_symbols: message = \ From 363fd4ee68f8156e60a7fe441f6629fb8e2a72dc Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 6 Sep 2018 15:20:25 -0600 Subject: [PATCH 090/196] flit-bisect: add --compile-only and --precompile-fpit flags --- data/Makefile.in | 12 +++++++++++- data/Makefile_bisect_binary.in | 33 ++++++++++++++++++++++++++------- scripts/flitcli/flit_bisect.py | 31 +++++++++++++++++++++++++++---- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 1188b1c3..7714d896 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -227,6 +227,7 @@ DEV_OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_dev.o))) DEV_DEPS = $(DEV_OBJ:%.o=%.d) GT_OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_gt.o))) GT_DEPS = $(GT_OBJ:%.o=%.d) +GT_OBJ_FPIC = $(GT_OBJ:%.o=%_fPIC.o) HOSTNAME := $(shell hostname) @@ -488,9 +489,10 @@ TARGET_RESULTS := $(TARGET_OUTS:%=%-comparison.csv) OBJ_CLEAN = $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_*.o))) DEP_CLEAN += $(OBJ_CLEAN:%.o=%.d) -.PHONY: dev gt groundtruth run runbuild +.PHONY: dev gt gt-fpic groundtruth run runbuild dev: $(DEV_TARGET) gt: groundtruth +gt-fpic: $(GT_OBJ_FPIC) groundtruth: $(GT_TARGET) run: $(TARGET_RESULTS) $(TARGET_OUTS) @@ -584,5 +586,13 @@ $(OBJ_DIR)/%_gt.o: %.cpp Makefile custom.mk | $(OBJ_DIR) -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"' +$(OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(OBJ_DIR) + $(GT_CC) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + -DFLIT_HOST='"$(HOSTNAME)"' \ + -DFLIT_COMPILER='"$(GT_CC)"' \ + -DFLIT_OPTL='"$(GT_OPTL)"' \ + -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ + -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"' + endif # end of ifdef R_IS_RECURSED diff --git a/data/Makefile_bisect_binary.in b/data/Makefile_bisect_binary.in index 58c403d3..7fcde77e 100644 --- a/data/Makefile_bisect_binary.in +++ b/data/Makefile_bisect_binary.in @@ -135,6 +135,7 @@ BUILD_GT_LOCAL := {build_gt_local} TROUBLE_TARGET_OBJ := $(addprefix \ $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_bisect_$(TROUBLE_ID).o))) +ALL_TROUBLE_FPIC := $(TROUBLE_TARGET_OBJ:%.o=%_fPIC.o) BISECT_GT_OBJ := $(addprefix \ $(OBJ_DIR)/,$(notdir $(BISECT_GT_SRC:%.cpp=%_gt.o))) TROUBLE_OBJ := $(addprefix \ @@ -216,9 +217,10 @@ $(BISECT_TARGET): $(BISECT_OBJ) $(SPLIT_OBJ) Makefile custom.mk | $(BISECT_DIR) $(TROUBLE_TARGET): $(TROUBLE_TARGET_OBJ) Makefile custom.mk | $(BISECT_DIR) $(TROUBLE_CC) $(CC_REQUIRED) -o $@ $(TROUBLE_TARGET_OBJ) $(LD_REQUIRED) $(TROUBLE_LDFLAGS) -.PHONY: trouble trouble-out +.PHONY: trouble trouble-out trouble-fpic trouble: $(TROUBLE_TARGET) trouble-out: $(TROUBLE_TARGET_RESULT) $(TROUBLE_TARGET_OUT) +trouble-fpic: $(ALL_TROUBLE_FPIC) .PHONY: bisect bisect: $(BISECT_TARGET) $(GT_TARGET) @@ -265,12 +267,16 @@ $(BISECT_OBJ_DIR): # ground-truth files are already specified in Makefile # but need to specify how to do the fPIC variant $(BISECT_OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(BISECT_OBJ_DIR) - $(GT_CC) $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ - -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(GT_CC)"' \ - -DFLIT_OPTL='"$(GT_OPTL)"' \ - -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ - -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"' + if [ -f "$(OBJ_DIR)/$*_gt_fPIC.o" ]; then \ + ln -s "../../$(OBJ_DIR)/$*_gt_fPIC.o" "$@"; \ + else \ + $(GT_CC) $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + -DFLIT_HOST='"$(HOSTNAME)"' \ + -DFLIT_COMPILER='"$(GT_CC)"' \ + -DFLIT_OPTL='"$(GT_OPTL)"' \ + -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ + -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"'; \ + fi # specify how to build the troublesome ones @@ -284,6 +290,19 @@ $(OBJ_DIR)/%_bisect_$(TROUBLE_ID).o: %.cpp Makefile custom.mk | $(OBJ_DIR) # and the fPIC variant $(BISECT_OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(BISECT_OBJ_DIR) + if [ -f "$(OBJ_DIR)/$*_bisect_$(TROUBLE_ID)_fPIC.o" ]; then \ + ln -s "../../$(OBJ_DIR)/$*_bisect_$(TROUBLE_ID)_fPIC.o" "$@"; \ + else \ + $(TROUBLE_CC) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + -DFLIT_HOST='"$(HOSTNAME)"' \ + -DFLIT_COMPILER='"$(TROUBLE_CC)"' \ + -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ + -DFLIT_SWITCHES='"$(TROUBLE_SWITCHES)"' \ + -DFLIT_FILENAME='"bisect-default-out"'; \ + fi + +# and the fPIC variant +$(OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(OBJ_DIR) $(TROUBLE_CC) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(TROUBLE_CC)"' \ diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 652f09bf..bdfa63e0 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -288,7 +288,7 @@ def build_bisect(makefilename, directory, **kwargs) def update_gt_results(directory, verbose=False, - jobs=mp.cpu_count()): + jobs=mp.cpu_count(), fpic=False): ''' Update the ground-truth.csv results file for FLiT tests within the given directory. @@ -306,6 +306,9 @@ def update_gt_results(directory, verbose=False, print('Updating ground-truth results -', gt_resultfile, end='', flush=True) subp.check_call( ['make', '-j', str(jobs), '-C', directory, gt_resultfile], **kwargs) + if fpic: + subp.check_call( + ['make', '-j', str(jobs), '-C', directory, 'gt-fpic'], **kwargs) print(' - done') logging.info('Finished Updating ground-truth results') @@ -909,6 +912,18 @@ def parse_args(arguments, prog=sys.argv[0]): both compiled with the given compilation, then they produce a measurable variation. ''') + parser.add_argument('--compile-only', action='store_true', + help=''' + Only applicable with the --auto-sqlite-run option. + Only goes through the precompile step and then + exits. + ''') + parser.add_argument('--precompile-fpic', action='store_true', + help=''' + Only applicable with the --auto-sqlite-run option. + In the precompile phase, also precompiles the fPIC + object files into the top-level obj directory. + ''') args = parser.parse_args(arguments) @@ -1279,7 +1294,7 @@ def differing_source_callback(filename, score): return differing_sources, differing_symbols def compile_trouble(directory, compiler, optl, switches, verbose=False, - jobs=mp.cpu_count(), delete=True): + jobs=mp.cpu_count(), delete=True, fpic=False): ''' Compiles the trouble executable for the given arguments. This is useful to compile the trouble executable as it will force the creation of all needed @@ -1321,6 +1336,9 @@ def compile_trouble(directory, compiler, optl, switches, verbose=False, # Compile the trouble executable simply so that we have the object files build_bisect(makepath, directory, verbose=verbose, jobs=jobs, target='trouble') + if fpic: + build_bisect(makepath, directory, verbose=verbose, + jobs=jobs, target='trouble-fpic') # Remove this prebuild temporary directory now if delete: @@ -1698,11 +1716,16 @@ def parallel_auto_bisect(arguments, prog=sys.argv[0]): flush=True) compile_trouble(args.directory, compiler, optl, switches, verbose=args.verbose, jobs=args.jobs, - delete=args.delete) + delete=args.delete, fpic=args.precompile_fpic) print(' done', flush=True) # Update ground-truth results before launching workers - update_gt_results(args.directory, verbose=args.verbose, jobs=args.jobs) + update_gt_results(args.directory, verbose=args.verbose, jobs=args.jobs, + fpic=args.precompile_fpic) + + if args.compile_only: + print('Done with precompilation -- exiting') + return 0 # Generate the worker queue arg_queue = mp.Queue() From 548056a21a9f73dd501e9d69f712b20e243835fa Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 23 Aug 2018 00:05:59 -0600 Subject: [PATCH 091/196] flit_import: add -D flag for specified database --- scripts/flitcli/flit_import.py | 42 ++++++++++++++++++++++++---------- scripts/flitcli/flitutil.py | 2 +- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/scripts/flitcli/flit_import.py b/scripts/flitcli/flit_import.py index 61dd4e19..036f2e85 100644 --- a/scripts/flitcli/flit_import.py +++ b/scripts/flitcli/flit_import.py @@ -84,8 +84,6 @@ import flitutil as util -import toml - import argparse import csv import datetime @@ -96,10 +94,26 @@ brief_description = 'Import flit results into the configured database' def _file_check(filename): + 'Check that a file exists or raise an exception' if not os.path.isfile(filename): raise argparse.ArgumentTypeError('File does not exist: {0}'.format(filename)) return filename +def get_dbfile_from_toml(tomlfile): + 'get and return the database.filepath field' + import toml + try: + projconf = toml.load(tomlfile) + except FileNotFoundError: + print('Error: {0} not found. Run "flit init"'.format(tomlfile), + file=sys.stderr) + return 1 + util.fill_defaults(projconf) + + assert projconf['database']['type'] == 'sqlite', \ + 'Only sqlite database supported' + return projconf['database']['filepath'] + def main(arguments, prog=sys.argv[0]): parser = argparse.ArgumentParser( prog=prog, @@ -142,19 +156,23 @@ def main(arguments, prog=sys.argv[0]): call this program multiple times, each one with --run specified to the next run you want to import. ''') + parser.add_argument('-D', '--dbfile', default=None, + help=''' + Use this database file rather than the one + specified in flit-config.toml. This option is + especially useful when you want to import results + but do not have the flit-config.toml file + available, as that is currently the only reason for + flit-config.toml to be read by this command. It + can also be used when you do not have the toml + python package installed (goodie!). + ''') args = parser.parse_args(arguments) - try: - projconf = toml.load('flit-config.toml') - except FileNotFoundError: - print('Error: flit-config.toml not found. Run "flit init"', - file=sys.stderr) - return 1 - util.fill_defaults(projconf) + if args.dbfile is None: + args.dbfile = get_dbfile_from_toml('flit-config.toml') - assert projconf['database']['type'] == 'sqlite', \ - 'Only sqlite database supported' - db = util.sqlite_open(projconf['database']['filepath']) + db = util.sqlite_open(args.dbfile) # create a new run and set the args.append run id if args.append is None: diff --git a/scripts/flitcli/flitutil.py b/scripts/flitcli/flitutil.py index 69eeeaf2..2bc35a90 100644 --- a/scripts/flitcli/flitutil.py +++ b/scripts/flitcli/flitutil.py @@ -94,7 +94,6 @@ import subprocess as subp import sys import tempfile -import toml # cached values _default_toml = None @@ -121,6 +120,7 @@ def get_default_toml(): Gets the default toml configuration file for FLIT and returns the configuration object. ''' + import toml global _default_toml if _default_toml is None: _default_toml = toml.loads(get_default_toml_string()) From c071b23ccaae42c5c003503704872c2e052884f5 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 23 Aug 2018 21:42:21 -0700 Subject: [PATCH 092/196] flit_bisect: on Makefile error, output make output to the log --- scripts/flitcli/flit_bisect.py | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index bdfa63e0..cf53efac 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -86,6 +86,7 @@ ''' from collections import namedtuple +from tempfile import NamedTemporaryFile import argparse import csv import datetime @@ -280,12 +281,32 @@ def build_bisect(makefilename, directory, if jobs is None: jobs = mp.cpu_count() kwargs = dict() - if not verbose: - kwargs['stdout'] = subp.DEVNULL - kwargs['stderr'] = subp.DEVNULL - subp.check_call( - ['make', '-C', directory, '-f', makefilename, '-j', str(jobs), target], - **kwargs) + + command = [ + 'make', + '-C', directory, + '-f', makefilename, + '-j', str(jobs), + target, + ] + + with NamedTemporaryFile() as tmpout: + try: + if not verbose: + kwargs['stdout'] = tmpout + kwargs['stderr'] = tmpout + subp.check_call(command, stdout=tmpout, stderr=subp.STDOUT) + else: + ps = subp.Popen(command, stdout=subp.PIPE, stderr=subp.STDOUT) + command = ['tee'] + subp.check_call(['tee', tmpout.name], stdin=ps.stdout) + except: + tmpout.flush() + with open(tmpout.name, 'r') as tmpin: + logging.error('make error occurred. Here is the output:\n' + + tmpin.read()) + raise + def update_gt_results(directory, verbose=False, jobs=mp.cpu_count(), fpic=False): From 3d888a0fb24da773d19624b919cc4c11586d6530 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 18:22:51 -0600 Subject: [PATCH 093/196] flit import: add docs for --dbfile flag --- documentation/flit-command-line.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/documentation/flit-command-line.md b/documentation/flit-command-line.md index 75a895b6..5c7cae5e 100644 --- a/documentation/flit-command-line.md +++ b/documentation/flit-command-line.md @@ -119,6 +119,21 @@ the created `litmus-test-run` directory. You are free to examine the results using the `sqlite3` interactive tool or any other method you have for running queries on an SQLite3 database. +There is an option to specify a different database file than the one in +`flit-config.toml`. Here are three reasons you may want to use this option: + +1. run `flit import` outside of an initialized flit test directory +2. create a database file different from the one in `flit-config.toml` +3. use the import functionality on a system that does not have the python + `toml` package installed + +If one of those applies to you, then you can use the `--dbfile` argument to +`flit import`. + +```bash +flit import --dbfile temporary.sqlite backup/results/*.csv +``` + ## flit bisect When FLiT runs identify compilations that cause some tests to exhibit From e04e0527615b6a7aab6d86092568d034fefae1de Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 18:56:24 -0600 Subject: [PATCH 094/196] tests: move bisect and version tests under flit_cli --- tests/flit_cli/Makefile | 30 ++++-- tests/{ => flit_cli}/flit_bisect/Makefile | 0 .../flit_bisect/data/tests/BisectTest.cpp | 0 .../flit_bisect/data/tests/file1.cpp | 0 .../flit_bisect/data/tests/file1.h | 0 .../flit_bisect/data/tests/file2.cpp | 0 .../flit_bisect/data/tests/file2.h | 0 .../flit_bisect/data/tests/file3.cpp | 0 .../flit_bisect/data/tests/file3.h | 0 .../{ => flit_cli}/flit_bisect/tst_bisect.py | 2 +- .../flit_bisect/tst_bisect_biggest.py | 2 +- tests/flit_cli/flit_version/Makefile | 19 ++++ .../{ => flit_version}/tst_version.py | 2 +- tests/flit_cli/tst_bisect.py | 97 ------------------- tests/flit_mpi/Makefile | 16 +-- 15 files changed, 45 insertions(+), 123 deletions(-) rename tests/{ => flit_cli}/flit_bisect/Makefile (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/BisectTest.cpp (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file1.cpp (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file1.h (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file2.cpp (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file2.h (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file3.cpp (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file3.h (100%) rename tests/{ => flit_cli}/flit_bisect/tst_bisect.py (99%) rename tests/{ => flit_cli}/flit_bisect/tst_bisect_biggest.py (99%) create mode 100644 tests/flit_cli/flit_version/Makefile rename tests/flit_cli/{ => flit_version}/tst_version.py (99%) delete mode 100644 tests/flit_cli/tst_bisect.py diff --git a/tests/flit_cli/Makefile b/tests/flit_cli/Makefile index 242995ab..2edb693f 100644 --- a/tests/flit_cli/Makefile +++ b/tests/flit_cli/Makefile @@ -1,19 +1,29 @@ -RUNNER := python3 -SRC := $(wildcard tst_*.py) -RUN_TARGETS := $(SRC:%.py=run_%) +SUB_MAKES := $(wildcard */Makefile */makefile) +SUB_DIRS := $(patsubst %/,%,$(dir $(SUB_MAKES))) +CHECK_TARGETS := $(addprefix check__,$(SUB_DIRS)) +CLEAN_TARGETS := $(addprefix clean__,$(SUB_DIRS)) +BUILD_TARGETS := $(addprefix build__,$(SUB_DIRS)) -.PHONY: check help clean build run_% -check: $(TARGETS) $(RUN_TARGETS) +.PHONY: build check help clean +build: $(BUILD_TARGETS) + +check: $(CHECK_TARGETS) help: @echo "Makefile for running tests on FLiT framework" @echo " help print this help documentation and exit" - @echo " build just compile the targets" + @echo " build just compile all subdirectories" @echo " check run tests and print results to the console" @echo " clean remove all generated files" -build: -clean: +.PHONY: build__% check__% clean__% + +build__%: + @$(MAKE) build --directory $* + +check__%: + @$(MAKE) check --directory $* + +clean__%: + @$(MAKE) clean --directory $* -run_% : %.py - @$(RUNNER) $< diff --git a/tests/flit_bisect/Makefile b/tests/flit_cli/flit_bisect/Makefile similarity index 100% rename from tests/flit_bisect/Makefile rename to tests/flit_cli/flit_bisect/Makefile diff --git a/tests/flit_bisect/data/tests/BisectTest.cpp b/tests/flit_cli/flit_bisect/data/tests/BisectTest.cpp similarity index 100% rename from tests/flit_bisect/data/tests/BisectTest.cpp rename to tests/flit_cli/flit_bisect/data/tests/BisectTest.cpp diff --git a/tests/flit_bisect/data/tests/file1.cpp b/tests/flit_cli/flit_bisect/data/tests/file1.cpp similarity index 100% rename from tests/flit_bisect/data/tests/file1.cpp rename to tests/flit_cli/flit_bisect/data/tests/file1.cpp diff --git a/tests/flit_bisect/data/tests/file1.h b/tests/flit_cli/flit_bisect/data/tests/file1.h similarity index 100% rename from tests/flit_bisect/data/tests/file1.h rename to tests/flit_cli/flit_bisect/data/tests/file1.h diff --git a/tests/flit_bisect/data/tests/file2.cpp b/tests/flit_cli/flit_bisect/data/tests/file2.cpp similarity index 100% rename from tests/flit_bisect/data/tests/file2.cpp rename to tests/flit_cli/flit_bisect/data/tests/file2.cpp diff --git a/tests/flit_bisect/data/tests/file2.h b/tests/flit_cli/flit_bisect/data/tests/file2.h similarity index 100% rename from tests/flit_bisect/data/tests/file2.h rename to tests/flit_cli/flit_bisect/data/tests/file2.h diff --git a/tests/flit_bisect/data/tests/file3.cpp b/tests/flit_cli/flit_bisect/data/tests/file3.cpp similarity index 100% rename from tests/flit_bisect/data/tests/file3.cpp rename to tests/flit_cli/flit_bisect/data/tests/file3.cpp diff --git a/tests/flit_bisect/data/tests/file3.h b/tests/flit_cli/flit_bisect/data/tests/file3.h similarity index 100% rename from tests/flit_bisect/data/tests/file3.h rename to tests/flit_cli/flit_bisect/data/tests/file3.h diff --git a/tests/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py similarity index 99% rename from tests/flit_bisect/tst_bisect.py rename to tests/flit_cli/flit_bisect/tst_bisect.py index 60a73962..47f2d782 100644 --- a/tests/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -270,7 +270,7 @@ # Test setup before the docstring is run. import sys before_path = sys.path[:] -sys.path.append('..') +sys.path.append('../..') import test_harness as th sys.path = before_path diff --git a/tests/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py similarity index 99% rename from tests/flit_bisect/tst_bisect_biggest.py rename to tests/flit_cli/flit_bisect/tst_bisect_biggest.py index f6b90438..b86e0128 100644 --- a/tests/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -279,7 +279,7 @@ # Test setup before the docstring is run. import sys before_path = sys.path[:] -sys.path.append('..') +sys.path.append('../..') import test_harness as th sys.path = before_path diff --git a/tests/flit_cli/flit_version/Makefile b/tests/flit_cli/flit_version/Makefile new file mode 100644 index 00000000..162e9d20 --- /dev/null +++ b/tests/flit_cli/flit_version/Makefile @@ -0,0 +1,19 @@ +RUNNER := python3 +SRC := $(wildcard tst_*.py) +RUN_TARGETS := $(SRC:%.py=run_%) + +.PHONY: check help clean build run_% +check: $(TARGETS) $(RUN_TARGETS) + +help: + @echo "Makefile for running tests on FLiT framework" + @echo " help print this help documentation and exit" + @echo " build just compile the targets" + @echo " check run tests and print results to the console" + @echo " clean remove all generated files" + +build: +clean: + +run_% : %.py + @$(RUNNER) $< diff --git a/tests/flit_cli/tst_version.py b/tests/flit_cli/flit_version/tst_version.py similarity index 99% rename from tests/flit_cli/tst_version.py rename to tests/flit_cli/flit_version/tst_version.py index afb041f0..cdb86d20 100644 --- a/tests/flit_cli/tst_version.py +++ b/tests/flit_cli/flit_version/tst_version.py @@ -128,7 +128,7 @@ # Test setup before the docstring is run. import sys before_path = sys.path[:] -sys.path.append('..') +sys.path.append('../..') import test_harness as th sys.path = before_path diff --git a/tests/flit_cli/tst_bisect.py b/tests/flit_cli/tst_bisect.py deleted file mode 100644 index 1052aba5..00000000 --- a/tests/flit_cli/tst_bisect.py +++ /dev/null @@ -1,97 +0,0 @@ -# -- LICENSE BEGIN -- -# -# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. -# -# Produced at the Lawrence Livermore National Laboratory -# -# Written by -# Michael Bentley (mikebentley15@gmail.com), -# Geof Sawaya (fredricflinstone@gmail.com), -# and Ian Briggs (ian.briggs@utah.edu) -# under the direction of -# Ganesh Gopalakrishnan -# and Dong H. Ahn. -# -# LLNL-CODE-743137 -# -# All rights reserved. -# -# This file is part of FLiT. For details, see -# https://pruners.github.io/flit -# Please also read -# https://github.com/PRUNERS/FLiT/blob/master/LICENSE -# -# Redistribution and use in source and binary forms, with or -# without modification, are permitted provided that the following -# conditions are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the disclaimer below. -# -# - Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the disclaimer -# (as noted below) in the documentation and/or other materials -# provided with the distribution. -# -# - Neither the name of the LLNS/LLNL nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL -# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -# THE POSSIBILITY OF SUCH DAMAGE. -# -# Additional BSD Notice -# -# 1. This notice is required to be provided under our contract -# with the U.S. Department of Energy (DOE). This work was -# produced at Lawrence Livermore National Laboratory under -# Contract No. DE-AC52-07NA27344 with the DOE. -# -# 2. Neither the United States Government nor Lawrence Livermore -# National Security, LLC nor any of their employees, makes any -# warranty, express or implied, or assumes any liability or -# responsibility for the accuracy, completeness, or usefulness of -# any information, apparatus, product, or process disclosed, or -# represents that its use would not infringe privately-owned -# rights. -# -# 3. Also, reference herein to any specific commercial products, -# process, or services by trade name, trademark, manufacturer or -# otherwise does not necessarily constitute or imply its -# endorsement, recommendation, or favoring by the United States -# Government or Lawrence Livermore National Security, LLC. The -# views and opinions of authors expressed herein do not -# necessarily state or reflect those of the United States -# Government or Lawrence Livermore National Security, LLC, and -# shall not be used for advertising or product endorsement -# purposes. -# -# -- LICENSE END -- - -''' -Tests flit bisect functionality. -''' - -# Test setup before the docstring is run. -import sys -before_path = sys.path[:] -sys.path.append('..') -import test_harness as th -sys.path = before_path - -if __name__ == '__main__': - import doctest - doctest.testmod() - diff --git a/tests/flit_mpi/Makefile b/tests/flit_mpi/Makefile index 1d04452e..8f27354d 100644 --- a/tests/flit_mpi/Makefile +++ b/tests/flit_mpi/Makefile @@ -1,21 +1,11 @@ -RUNNER := python3 -SRC := $(wildcard tst_*.py) -RUN_TARGETS := $(SRC:%.py=run_%) -MPIRUN := $(shell command -v mpirun 2>/dev/null) -MPICXX := $(shell command -v mpic++ 2>/dev/null) +RUNNER := python3 +SRC := $(wildcard tst_*.py) +RUN_TARGETS := $(SRC:%.py=run_%) include ../color_out.mk .PHONY: check help clean build run_% -ifeq ($(MPIRUN),) -check: - $(call color_out,RED,Warning: mpirun is not found on your system; skipping the MPI tests) -else ifeq ($(MPICXX),) -check: - $(call color_out,RED,Warning: mpic++ is not found on your system; skipping the MPI tests) -else check: $(TARGETS) $(RUN_TARGETS) -endif help: @echo "Makefile for running tests on FLiT framework" From 7811679e608a84606e2c990fdaf1401eb6e24a8a Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 18:57:06 -0600 Subject: [PATCH 095/196] tests: flit_src: fix clean to clean .d files --- tests/flit_src/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/flit_src/Makefile b/tests/flit_src/Makefile index 37a27867..3a11455a 100644 --- a/tests/flit_src/Makefile +++ b/tests/flit_src/Makefile @@ -8,6 +8,7 @@ CFLAGS += -std=c++11 LDFLAGS := -L$(FLITLIBDIR) -lflit LDFLAGS += -Wl,-rpath=$(FLITLIBDIR) SRC := $(wildcard *.cpp) +DEPS := $(SRC:%.cpp=%.d) TARGETS := $(SRC:%.cpp=%) RUN_TARGETS := $(TARGETS:%=run_%) HARNESS := ../test_harness.h @@ -30,6 +31,7 @@ help: @echo " clean remove all generated files" clean: + rm -f $(DEPS) rm -f $(TARGETS) run_% : % @@ -39,7 +41,7 @@ run_% : % $(CC) $(CFLAGS) $(DEPFLAGS) $< -o $@ $(LDFLAGS) .PRECIOUS: %.d --include $(SRC:%.cpp=%.d) +-include $(DEPS) $(TARGETS): $(FLITLIB) From 2a1d83185be7d240811c4c868729f19a3437cbfc Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 18:58:54 -0600 Subject: [PATCH 096/196] tests: output in color which test is running --- tests/color_out.mk | 11 ++++++++++- tests/flit_cli/flit_bisect/Makefile | 4 ++++ tests/flit_cli/flit_version/Makefile | 4 ++++ tests/flit_install/Makefile | 4 ++++ tests/flit_makefile/Makefile | 4 ++++ tests/flit_mpi/Makefile | 2 ++ tests/flit_src/Makefile | 3 +++ 7 files changed, 31 insertions(+), 1 deletion(-) diff --git a/tests/color_out.mk b/tests/color_out.mk index 03c446b8..533749ee 100644 --- a/tests/color_out.mk +++ b/tests/color_out.mk @@ -1,7 +1,14 @@ # A Makefile function # @param 1: color (e.g. BLUE or GREEN) # @param 2: message to be printed in the color -color_out = @if [ -t 1 ]; then \ +color_out_noline = \ + @if [ -t 1 ]; then \ + /bin/echo -ne "$(BASH_$1)$2$(BASH_CLEAR)"; \ + else \ + /bin/echo -n "$2"; \ + fi +color_out = \ + @if [ -t 1 ]; then \ /bin/echo -e "$(BASH_$1)$2$(BASH_CLEAR)"; \ else \ /bin/echo "$2"; \ @@ -11,7 +18,9 @@ BASH_CLEAR := \e[0m BASH_BLACK := \e[0;30m BASH_BROWN := \e[0;33m BASH_GRAY := \e[0;37m +BASH_GREY := \e[0;37m BASH_DARKGRAY := \e[1;30m +BASH_DARKGREY := \e[1;30m BASH_RED := \e[1;31m BASH_GREEN := \e[1;32m BASH_YELLOW := \e[1;33m diff --git a/tests/flit_cli/flit_bisect/Makefile b/tests/flit_cli/flit_bisect/Makefile index 162e9d20..ce0c8e04 100644 --- a/tests/flit_cli/flit_bisect/Makefile +++ b/tests/flit_cli/flit_bisect/Makefile @@ -2,6 +2,8 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) +include ../../color_out.mk + .PHONY: check help clean build run_% check: $(TARGETS) $(RUN_TARGETS) @@ -16,4 +18,6 @@ build: clean: run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" @$(RUNNER) $< diff --git a/tests/flit_cli/flit_version/Makefile b/tests/flit_cli/flit_version/Makefile index 162e9d20..ce0c8e04 100644 --- a/tests/flit_cli/flit_version/Makefile +++ b/tests/flit_cli/flit_version/Makefile @@ -2,6 +2,8 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) +include ../../color_out.mk + .PHONY: check help clean build run_% check: $(TARGETS) $(RUN_TARGETS) @@ -16,4 +18,6 @@ build: clean: run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" @$(RUNNER) $< diff --git a/tests/flit_install/Makefile b/tests/flit_install/Makefile index 242995ab..6cc755e5 100644 --- a/tests/flit_install/Makefile +++ b/tests/flit_install/Makefile @@ -2,6 +2,8 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) +include ../color_out.mk + .PHONY: check help clean build run_% check: $(TARGETS) $(RUN_TARGETS) @@ -16,4 +18,6 @@ build: clean: run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" @$(RUNNER) $< diff --git a/tests/flit_makefile/Makefile b/tests/flit_makefile/Makefile index 242995ab..6cc755e5 100644 --- a/tests/flit_makefile/Makefile +++ b/tests/flit_makefile/Makefile @@ -2,6 +2,8 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) +include ../color_out.mk + .PHONY: check help clean build run_% check: $(TARGETS) $(RUN_TARGETS) @@ -16,4 +18,6 @@ build: clean: run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" @$(RUNNER) $< diff --git a/tests/flit_mpi/Makefile b/tests/flit_mpi/Makefile index 8f27354d..6cc755e5 100644 --- a/tests/flit_mpi/Makefile +++ b/tests/flit_mpi/Makefile @@ -18,4 +18,6 @@ build: clean: run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" @$(RUNNER) $< diff --git a/tests/flit_src/Makefile b/tests/flit_src/Makefile index 3a11455a..19377a72 100644 --- a/tests/flit_src/Makefile +++ b/tests/flit_src/Makefile @@ -17,6 +17,7 @@ CFLAGS += -I../../src DEPFLAGS = -MD -MF $*.d +include ../color_out.mk .PHONY: build check help clean run_% build: $(TARGETS) @@ -35,6 +36,8 @@ clean: rm -f $(TARGETS) run_% : % + @$(call color_out_noline,BROWN, running) + @echo " $<" @./$< --quiet % : %.cpp $(HARNESS) Makefile From 5fb63b84f23a569826953a516b0969d4715a4ef4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 19:04:02 -0600 Subject: [PATCH 097/196] tests/.gitignore: add tst_FlitCSV --- tests/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/.gitignore b/tests/.gitignore index 8d152b31..7469162f 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -1,3 +1,4 @@ harness_tester flit_src/tst_flit_cpp flit_src/tst_flitHelpers_h +flit_src/tst_FlitCsv From 93584441b2b2a689c23f75b5b4b121b1c0b23bb8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 19:47:16 -0600 Subject: [PATCH 098/196] flit import: add tst_dbfile --- scripts/flitcli/flit_import.py | 4 + tests/flit_cli/flit_import/Makefile | 23 ++++ tests/flit_cli/flit_import/data/data1.csv | 7 ++ tests/flit_cli/flit_import/tst_dbfile.py | 143 ++++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 tests/flit_cli/flit_import/Makefile create mode 100644 tests/flit_cli/flit_import/data/data1.csv create mode 100644 tests/flit_cli/flit_import/tst_dbfile.py diff --git a/scripts/flitcli/flit_import.py b/scripts/flitcli/flit_import.py index 036f2e85..f3fec2fb 100644 --- a/scripts/flitcli/flit_import.py +++ b/scripts/flitcli/flit_import.py @@ -172,6 +172,10 @@ def main(arguments, prog=sys.argv[0]): if args.dbfile is None: args.dbfile = get_dbfile_from_toml('flit-config.toml') + if os.path.isfile(args.dbfile): + print('Appending', args.dbfile) + else: + print('Creating', args.dbfile) db = util.sqlite_open(args.dbfile) # create a new run and set the args.append run id diff --git a/tests/flit_cli/flit_import/Makefile b/tests/flit_cli/flit_import/Makefile new file mode 100644 index 00000000..ce0c8e04 --- /dev/null +++ b/tests/flit_cli/flit_import/Makefile @@ -0,0 +1,23 @@ +RUNNER := python3 +SRC := $(wildcard tst_*.py) +RUN_TARGETS := $(SRC:%.py=run_%) + +include ../../color_out.mk + +.PHONY: check help clean build run_% +check: $(TARGETS) $(RUN_TARGETS) + +help: + @echo "Makefile for running tests on FLiT framework" + @echo " help print this help documentation and exit" + @echo " build just compile the targets" + @echo " check run tests and print results to the console" + @echo " clean remove all generated files" + +build: +clean: + +run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" + @$(RUNNER) $< diff --git a/tests/flit_cli/flit_import/data/data1.csv b/tests/flit_cli/flit_import/data/data1.csv new file mode 100644 index 00000000..06444c02 --- /dev/null +++ b/tests/flit_cli/flit_import/data/data1.csv @@ -0,0 +1,7 @@ +name,host,compiler,optl,switches,precision,score_hex,score,resultfile,comparison_hex,comparison,file,nanosec +Test-name 1,My-host,g++,-O3,-funsafe-math-optimizations,d,0x3fc1f3bf9fbd47d9a800,4.13E-19,NULL,0xbf8d8000000000000000,-4.81E-35,Executable-1,0 +Test-name 1,My-host,g++,-O3,-funsafe-math-optimizations,e,0x39b1f4945ea2bda83e1d,2.622993437820000000049493126424993646159392840860537999954199990192081383442238818022440754628591392062370104918700079633947091308461839161171640941846366999487116897033647392640059787776192308046148485442313923637505619864489663342532546868165054067822553526472224056250818846029404834715074970010619585201127975867937128686584859879235956730154796047568484754028218349365890624790982353393885557838362503601335004366804753200077871854785718735900172999572949926325063118472484723814495993721500770550490477690570702216083488816431615025776587959223632347438896354452271830717685450631135729485941832893902859041046485120727804367381754781456875315095074113343122617644273653171652021857112889615423937484463835787809320022112937369856636506646976768460185212153428152275393010129262643490977972613221204038554898919875314600364413668735286620701405148737003869390251211450716301354137742031331212078879640318656013417890315294552993898491795938960646946762588295746816126420665952524682531599334464e-486,NULL,0x00000000000000000,0,Executable-1,0 +Test-name 1,My-host,g++,-O3,-funsafe-math-optimizations,f,0x406bfbc7780000000000,6.38336044132261E+032,NULL,0x40548000000000000000,3.86856262276681E+025,Executable-1,0 +Test-name 2,My-host,g++,-O3,-funsafe-math-optimizations,d,0x43f3f78060de921d6800,8.48639885075809E+304,NULL,0x43bf8000000000000000,9.74531401139999E+288,Executable-1,0 +Test-name 2,My-host,g++,-O3,-funsafe-math-optimizations,e,0x750fc6e7f87ea219b5f0,2.414900878482699999795508402316024758692093524806230899470711317155208208917239351004592145700838964809713539689950081780652142004017701820489109185237739731776069652775475587364235041317881184647657737514056077406660197340530427402720810614023982185997501558174758654488852938662786077427428151283412205029413321065359541219873748339197031818496674331872259620434905462771175297875629859443933488190292705817203369288279859977237950632350306150894955353470107246953620032474441533425556138127561529626825449889989460593037745787637371551643659888695656111848431709385771441755211411455955350026612450283221437557870777655391290501233122703416744333570839252203524526590014751409815036338943626475847611276171463663976894962144501520730899078171939790820650957206041614439841880474407327983121273223057622974837366966306292949739537499800325401059186202791792679518011908836657422244571139693819475514296103878538735858327875567104379905240638787073442073798378865190480293376910192972788631712551243e+4089,NULL,0x00000000000000000,0,Executable-1,0 +Test-name 2,My-host,g++,-O3,-funsafe-math-optimizations,f,0x3fa7f4dbb50000000000,6.18E-27,NULL,0x3f908000000000000000,3.85E-34,Executable-1,0 diff --git a/tests/flit_cli/flit_import/tst_dbfile.py b/tests/flit_cli/flit_import/tst_dbfile.py new file mode 100644 index 00000000..5da1935a --- /dev/null +++ b/tests/flit_cli/flit_import/tst_dbfile.py @@ -0,0 +1,143 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests FLiT's --version argument + +The tests are below using doctest + +Let's now make a temporary directory and test that flit init populates the +correct files + +TODO: how do I test its behavior when I do not have toml installed? + +>>> from io import StringIO +>>> import os +>>> import sqlite3 +>>> import subprocess as subp +>>> import tempfile + +>>> datafile = os.path.join('data', 'data1.csv') + +Test that if flit-config.toml does not exist, then an error occurs +But here we suppress stderr +>>> try: +... olderr = sys.stderr +... with StringIO() as ostream: +... sys.stderr = ostream +... th.flit.main(['import', datafile]) +... finally: +... sys.stderr = olderr +Traceback (most recent call last): + ... +TypeError: expected str, bytes or os.PathLike object, not int + +Test that with --dbfile , that it creates and imports into that file +>>> with th.tempdir() as temp_dir: +... fname = os.path.join(temp_dir, 'my-results.sqlite') +... with StringIO() as ostream: +... _ = th.flit.main(['import', '--dbfile', fname, datafile], +... outstream=ostream) +... import_out = ostream.getvalue().splitlines() +... with sqlite3.connect(fname) as connection: +... cursor = connection.execute('select * from tests;') +... rows = [row for row in cursor] + +>>> print('\\n'.join(import_out)) # doctest:+ELLIPSIS +Creating /.../my-results.sqlite +Importing data/data1.csv + +>>> len(rows) +6 +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From 84a010db2580a1ac9ac82b9760866b83624b44d6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 10 Sep 2018 19:56:08 -0600 Subject: [PATCH 099/196] flit_import: fix get_dbfile_from_toml() and the test --- scripts/flitcli/flit_import.py | 2 +- tests/flit_cli/flit_import/tst_dbfile.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/flitcli/flit_import.py b/scripts/flitcli/flit_import.py index f3fec2fb..0a1a6d99 100644 --- a/scripts/flitcli/flit_import.py +++ b/scripts/flitcli/flit_import.py @@ -107,7 +107,7 @@ def get_dbfile_from_toml(tomlfile): except FileNotFoundError: print('Error: {0} not found. Run "flit init"'.format(tomlfile), file=sys.stderr) - return 1 + raise util.fill_defaults(projconf) assert projconf['database']['type'] == 'sqlite', \ diff --git a/tests/flit_cli/flit_import/tst_dbfile.py b/tests/flit_cli/flit_import/tst_dbfile.py index 5da1935a..c63b9d38 100644 --- a/tests/flit_cli/flit_import/tst_dbfile.py +++ b/tests/flit_cli/flit_import/tst_dbfile.py @@ -109,7 +109,7 @@ ... sys.stderr = olderr Traceback (most recent call last): ... -TypeError: expected str, bytes or os.PathLike object, not int +FileNotFoundError: [Errno 2] No such file or directory: 'flit-config.toml' Test that with --dbfile , that it creates and imports into that file >>> with th.tempdir() as temp_dir: From c942169167d594d146aa64265a76993ac5e839d6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 13 Sep 2018 23:19:26 -0600 Subject: [PATCH 100/196] Github issue template: take from a stock template It is their bug report template that I have removed some pieces of. --- .github/ISSUE_TEMPLATE/bug_report.md | 35 ++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..b7353733 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. From b12a4b927557a93dc94241a2c0ef424435f4a9f4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 13 Sep 2018 23:33:37 -0600 Subject: [PATCH 101/196] issue-templates: Shorten the bug report template --- .github/ISSUE_TEMPLATE/bug_report.md | 35 +++++----------------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b7353733..b06b8f3e 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,35 +1,12 @@ --- -name: Bug report -about: Create a report to help us improve +name: 🐛 Bug report +about: Create a report to help us improve 🤔 --- -**Describe the bug** +**Describe the problem** A clear and concise description of what the bug is. +Include screenshots if applicable. -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] - -**Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] - -**Additional context** -Add any other context about the problem here. +**Suggested Fix** +Do you have a suggestion for how to resole the issue? From b1a2370e682670469b6d54018a8d9dcae173ec9a Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 13 Sep 2018 23:38:27 -0600 Subject: [PATCH 102/196] issue-templates: add feature request template --- .github/ISSUE_TEMPLATE/bug_report.md | 6 ++++++ .github/ISSUE_TEMPLATE/feature_request.md | 19 +++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index b06b8f3e..cab70590 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,9 +4,15 @@ about: Create a report to help us improve 🤔 --- +## Bug Report + **Describe the problem** A clear and concise description of what the bug is. Include screenshots if applicable. **Suggested Fix** Do you have a suggestion for how to resole the issue? + +**Alternative approaches:** +A clear and concise description of any alternative solutions or features you've +considered. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..fb209aed --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: 🚀 Feature Request +about: I have a suggestion (and may want to implement it 🙂)! + +--- + +## Feature Request + +**Describe the new feature:** +A clear and concise description of what your problem is. Ex. I have an issue +when [...] + +**Suggested change:** +A clear and concise description of what you want to happen. Add any considered +drawbacks. + +**Alternative approaches:** +A clear and concise description of any alternative solutions or features you've +considered. From cb912ac79438abba90bf5894f5619ed31abc753b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 13 Sep 2018 23:42:31 -0600 Subject: [PATCH 103/196] Add pull request template --- .github/PULL_REQUEST_TEMPLATE.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..f2b40f0a --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,16 @@ +Fixes # + +**Description:** +Describe what you changed and why. + +- +- +- + +**Documentation:** +What documentation did you change? +If the change does not require updates to documentation, justify why. + +**Tests:** +What automated tests did you change? +If the change does not require updates to tests, justify why. From 139fcc3ccd33aaefea5c8334f2d2ed475c699efe Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 14 Sep 2018 21:09:08 -0600 Subject: [PATCH 104/196] tests: fix skipping mpi tests when mpi is not installed --- tests/flit_mpi/Makefile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/flit_mpi/Makefile b/tests/flit_mpi/Makefile index 6cc755e5..0a7cd3c3 100644 --- a/tests/flit_mpi/Makefile +++ b/tests/flit_mpi/Makefile @@ -1,11 +1,21 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) +MPIRUN := $(shell command -v mpirun 2>/dev/null) +MPICXX := $(shell command -v mpic++ 2>/dev/null) include ../color_out.mk .PHONY: check help clean build run_% +ifeq ($(MPIRUN),) +check: + $(call color_out,RED,Warning: mpirun is not found on your system; skipping the MPI tests) +else ifeq ($(MPICXX),) +check: + $(call color_out,RED,Warning: mpic++ is not found on your system; skipping the MPI tests) +else check: $(TARGETS) $(RUN_TARGETS) +endif help: @echo "Makefile for running tests on FLiT framework" From 35a9c4700d5ddcce806a21205d4409db1bcf2526 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 14 Sep 2018 21:10:01 -0600 Subject: [PATCH 105/196] test_harness: fixed tempdir() deletion on raised exception --- tests/test_harness.py | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/test_harness.py b/tests/test_harness.py index 73a4b354..88873817 100644 --- a/tests/test_harness.py +++ b/tests/test_harness.py @@ -185,24 +185,37 @@ def tempdir(*args, **kwargs): ... print(os.path.isdir(temporary_directory)) ... True - >>> print(os.path.isdir(temporary_directory)) + >>> os.path.isdir(temporary_directory) False - >>> print(os.path.exists(temporary_directory)) + >>> os.path.exists(temporary_directory) False Test that an exception is not thrown if it was already deleted >>> import shutil >>> with tempdir() as new_dir: ... shutil.rmtree(new_dir) + + Test that the directory is still deleted even if an exception is thrown + within the with statement. + >>> try: + ... with tempdir() as new_dir: + ... temporary_directory = new_dir + ... raise RuntimeError() + ... except: + ... pass + >>> os.path.isdir(temporary_directory) + False ''' import tempfile import shutil new_dir = tempfile.mkdtemp(*args, **kwargs) - yield new_dir try: - shutil.rmtree(new_dir) - except FileNotFoundError: - pass + yield new_dir + finally: + try: + shutil.rmtree(new_dir) + except FileNotFoundError: + pass def touch(filename): ''' From 0f554770254df0ba697cae78303cf93d7de2595e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 14 Sep 2018 21:25:04 -0600 Subject: [PATCH 106/196] tests: run doctest on test_harness.py --- tests/Makefile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/Makefile b/tests/Makefile index 000a3fed..728d16c8 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -4,6 +4,7 @@ CFLAGS += -std=c++11 LDFLAGS := TESTER_SRC := harness_tester.cpp HARNESS := test_harness.h +HARNESS_PY := test_harness.py TESTER := $(TESTER_SRC:%.cpp=%) SUB_MAKES := $(wildcard */Makefile */makefile) SUB_DIRS := $(patsubst %/,%,$(dir $(SUB_MAKES))) @@ -16,7 +17,7 @@ build: $(TESTER) $(BUILD_TARGETS) include color_out.mk -check: run__$(TESTER) $(CHECK_TARGETS) +check: run__$(TESTER) run_tester_py $(CHECK_TARGETS) @$(call color_out,GREEN,All tests pass) help: @@ -29,8 +30,16 @@ help: clean: $(CLEAN_TARGETS) rm -f $(TESTER) +.PHONY: run_tester_py +run_tester_py: $(HARNESS_PY) + @$(call color_out_noline,BROWN, testing) + @echo " $(HARNESS_PY)" + @python3 -m doctest $(HARNESS_PY) + .PHONY: run__% build__% check__% clean__% run__$(TESTER): $(TESTER) + @$(call color_out_noline,BROWN, testing) + @echo " $(HARNESS)" @./$(TESTER) | grep "failures: *10" >/dev/null build__%: From 576a6b8b06abfe70f418b833f2e0fd4be184a6d4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 14 Sep 2018 21:43:56 -0600 Subject: [PATCH 107/196] Travis-CI: Test OpenMPI vs No MPI vs MPICH --- .travis.yml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 78bc916b..7230bd19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,8 +87,23 @@ addons: packages: - python3 - python3-pip - - openmpi-bin - - libopenmpi-dev + +matrix: + include: + # Job 1: OpenMPI + - addons: + apt: + packages: + - libopenmpi-dev + - openmpi-bin + # Job 2: No MPI + - env: DUMMY=1 # no MPI installed + # Job 3: MPICH + - addons: + apt: + packages: + - libmpich-dev + - mpich before_install: pip3 install --user toml From 04971af1d3dc88af16c7178a2fa489e8f637a28e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 14 Sep 2018 21:47:27 -0600 Subject: [PATCH 108/196] Travis-CI: attempt again to do the three jobs --- .travis.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7230bd19..172a6b15 100644 --- a/.travis.yml +++ b/.travis.yml @@ -84,24 +84,32 @@ language: cpp os: linux addons: apt: - packages: + packages: &native_deps - python3 - python3-pip matrix: include: # Job 1: OpenMPI - - addons: + - env: mpi_type=openmpi + addons: apt: packages: + - *native_deps - libopenmpi-dev - openmpi-bin # Job 2: No MPI - - env: DUMMY=1 # no MPI installed + - env: mpi_type=none + addons: + apt: + packages: + - *native_deps # Job 3: MPICH - - addons: + - env: mpi_type=mpich + addons: apt: packages: + - *native_deps - libmpich-dev - mpich From 8a27baf1d5717da6fe153b6e10952612a50a77d7 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Fri, 14 Sep 2018 22:00:16 -0600 Subject: [PATCH 109/196] Travis-CI: comment out MPICH run per issue #222 --- .travis.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 172a6b15..b611170d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -98,20 +98,20 @@ matrix: - *native_deps - libopenmpi-dev - openmpi-bin - # Job 2: No MPI + # Job 2: MPICH + #- env: mpi_type=mpich + # addons: + # apt: + # packages: + # - *native_deps + # - libmpich-dev + # - mpich + # Job 3: No MPI - env: mpi_type=none addons: apt: packages: - *native_deps - # Job 3: MPICH - - env: mpi_type=mpich - addons: - apt: - packages: - - *native_deps - - libmpich-dev - - mpich before_install: pip3 install --user toml From cf8df698d3ec10902dbb31c96506f8a115e6c3ac Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 10:32:40 -0600 Subject: [PATCH 110/196] bisect: in memoizing, sort the list --- scripts/flitcli/flit_bisect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index cf53efac..7dfd7aeb 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -546,7 +546,7 @@ def memoize_strlist_func(func): memo = {} def memoized_func(strlist): 'func but memoized' - idx = tuple(strlist) + idx = tuple(sorted(strlist)) if idx in memo: return memo[idx] value = func(strlist) From 7d7556952c7457d20cbb323214291d4f826c630d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 10:34:12 -0600 Subject: [PATCH 111/196] bisect: add an extra assertion checking overlapping --- scripts/flitcli/flit_bisect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 7dfd7aeb..1214b147 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -782,6 +782,8 @@ def bisect_search(score_func, elements, found_callback=None): list(set(elements).difference(x[0] for x in differing_list)) assert score_func(non_differing_list) <= 0, \ 'Assumption that differing elements are independent was wrong' + assert score_func(elements) == score_func([x[0] for x in differing_list]),\ + 'Assumption that minimal sets are non-overlapping was wrong' # sort descending by score differing_list.sort(key=lambda x: -x[1]) From 161587bfba96128342f68e903e2c4dac320e06af Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 13:59:18 -0600 Subject: [PATCH 112/196] bisect: memoize extract_symbols() --- scripts/flitcli/flit_bisect.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 1214b147..a4928621 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -442,6 +442,7 @@ def is_result_differing(resultfile): lineno: line number of definition within fname. ''' +_extract_symbols_memos = {} def extract_symbols(file_or_filelist, objdir): ''' Extracts symbols for the given file(s) given. The corresponding object is @@ -468,6 +469,9 @@ def extract_symbols(file_or_filelist, objdir): fbase = os.path.splitext(os.path.basename(fname))[0] fobj = os.path.join(objdir, fbase + '_gt.o') + if fobj in _extract_symbols_memos: + return _extract_symbols_memos[fobj] + # use nm and objdump to get the binary information we need symbol_strings = subp.check_output([ 'nm', @@ -517,6 +521,7 @@ def extract_symbols(file_or_filelist, objdir): symbol_tuples.append( SymbolTuple(fname, symbol, demangled, deffile, defline)) + _extract_symbols_memos[fobj] = symbol_tuples return symbol_tuples def memoize_strlist_func(func): From 9e285816ee1303ed9838bd66927112cb1543e8a5 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 13:59:39 -0600 Subject: [PATCH 113/196] bisect: fix some doctests --- scripts/flitcli/flit_bisect.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index a4928621..e6078647 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -537,16 +537,16 @@ def memoize_strlist_func(func): >>> memoized = memoize_strlist_func(to_memoize) >>> memoized(['a', 'b', 'c']) ['a', 'b', 'c'] - a + 'a' >>> memoized(['a', 'b', 'c']) - a + 'a' >>> memoized(['e', 'a']) ['e', 'a'] - e + 'e' >>> memoized(['a', 'b', 'c']) - a + 'a' >>> memoized(['e', 'a']) - e + 'e' ''' memo = {} def memoized_func(strlist): @@ -715,7 +715,7 @@ def bisect_search(score_func, elements, found_callback=None): score_func(), so we are only counting unique calls and not duplicate calls to score_func(). >>> call_count - 9 + 10 Test out the found_callback() functionality. >>> s = set() From c55ac60036da6f4535431843ce6e7a3a6cde54f5 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 14:00:22 -0600 Subject: [PATCH 114/196] bisect: add final assert at the end Asserts that test(all_symbols) == test(found_symbols) after all is said and done. --- scripts/flitcli/flit_bisect.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index e6078647..95697a11 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1582,6 +1582,11 @@ def run_bisect(arguments, prog=sys.argv[0]): logging.info('%s', message) differing_symbols.sort(key=lambda x: (-x[1], x[0])) + all_searched_symbols = extract_symbols([x[0] for x in differing_sources], + os.path.join(args.directory, 'obj')) + checker = _gen_bisect_symbol_checker( + args, bisect_path, replacements, sources, all_searched_symbols) + assert checker(all_searched_symbols) == checker([x[0] for x in differing_symbols]) if args.biggest is None: print('All variability inducing symbols:') From d64fefc690f21e1edc3b941a40314cf649cff686 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 14:39:35 -0600 Subject: [PATCH 115/196] bisect: finish last assertion for overlapping minimal sets --- scripts/flitcli/flit_bisect.py | 15 ++++++++++----- tests/flit_cli/flit_bisect/tst_bisect.py | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 95697a11..b976ef78 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1581,12 +1581,17 @@ def run_bisect(arguments, prog=sys.argv[0]): print(message) logging.info('%s', message) + # Verify that there are no missed files, i.e. those that are more than + # singletons and that are to be grouped with one of the found symbols. + all_searched_symbols = extract_symbols( + [x[0] for x in differing_sources], + os.path.join(args.directory, 'obj')) + checker = _gen_bisect_symbol_checker( + args, bisect_path, replacements, sources, all_searched_symbols) + assert checker(all_searched_symbols) == \ + checker([x[0] for x in differing_symbols]) + differing_symbols.sort(key=lambda x: (-x[1], x[0])) - all_searched_symbols = extract_symbols([x[0] for x in differing_sources], - os.path.join(args.directory, 'obj')) - checker = _gen_bisect_symbol_checker( - args, bisect_path, replacements, sources, all_searched_symbols) - assert checker(all_searched_symbols) == checker([x[0] for x in differing_symbols]) if args.biggest is None: print('All variability inducing symbols:') diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index 47f2d782..ec196ebb 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -175,7 +175,7 @@ >>> print('\\n'.join(bisect_out[idx+1:idx+3])) line 103 -- file3_func5_PROBLEM() (score 3.0) line 92 -- file3_func2_PROBLEM() (score 1.0) ->>> bisect_out[idx+3].startswith(' ') +>>> bisect_out[idx+3].startswith(' ') False Test the All differing symbols section of the output From 91e0e882a5648489e377b058eb6ee34e3d4f0210 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 15:40:47 -0600 Subject: [PATCH 116/196] bisect: add --skip-verification flag --- scripts/flitcli/flit_bisect.py | 159 ++++++++++++++++++++++++++------- 1 file changed, 125 insertions(+), 34 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index b976ef78..086a92de 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -559,7 +559,8 @@ def memoized_func(strlist): return value return memoized_func -def bisect_biggest(score_func, elements, found_callback=None, k=1): +def bisect_biggest(score_func, elements, found_callback=None, k=1, + skip_verification=False): ''' Performs the bisect search, attempting to find the biggest offenders. This is different from bisect_search() in that this function only tries to @@ -595,6 +596,8 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): @param k: number of biggest elements to return. The default is to return the one biggest offender. If there are less than k elements that return positive scores, then only the found offenders will be returned. + @param skip_verification: skip the verification assertions for performance + reasons. @return list of the biggest offenders with their scores [(elem, score), ...] @@ -603,7 +606,8 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): ... print('scoring:', x) ... return -2*min(x) if x else 0 - >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], k=3) + >>> bisect_biggest(score_func, [1, 3, 4, 5, -1, 10, 0, -15, 3], k=3, + ... skip_verification=True) scoring: [1, 3, 4, 5, -1, 10, 0, -15, 3] scoring: [1, 3, 4, 5] scoring: [-1, 10, 0, -15, 3] @@ -633,6 +637,35 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): >>> bisect_biggest(score_func, []) [] + + >>> bisect_biggest(score_func, [-1, -2, -3, -4, -5], k=1) + scoring: [-1, -2, -3, -4, -5] + scoring: [-1, -2] + scoring: [-3, -4, -5] + scoring: [-3] + scoring: [-4, -5] + scoring: [-4] + scoring: [-5] + [(-5, 10)] + + Test that verification is performed + >>> def score_func(x): + ... return -2*min(x) if len(x) > 1 else 0 + >>> bisect_biggest(score_func, [-1, -2], k=2) + Traceback (most recent call last): + ... + AssertionError: Assumption that differing elements are independent was wrong + + >>> def score_func(x): + ... score = 0 + ... if len(x) == 0: return 0 + ... if min(x) < -1: score += max(0, -2*min(x)) + ... if len(x) > 1: score += max(0, -2*max(x)) + ... return score + >>> bisect_biggest(score_func, [-1, -2], k=2) + Traceback (most recent call last): + ... + AssertionError: Assumption that minimal sets are non-overlapping was wrong ''' if len(elements) == 0: return [] @@ -650,9 +683,22 @@ def bisect_biggest(score_func, elements, found_callback=None, k=1): else: push(elems[:len(elems) // 2]) push(elems[len(elems) // 2:]) + + if not skip_verification: + if len(frontier) == 0 or frontier[0][0] >= 0: + # found everything, so do the traditional assertions + non_differing_list = \ + list(set(elements).difference(x[0] for x in found_list)) + assert score_func(non_differing_list) <= 0, \ + 'Assumption that differing elements are independent was wrong' + assert score_func(elements) == \ + score_func([x[0] for x in found_list]), \ + 'Assumption that minimal sets are non-overlapping was wrong' + return found_list -def bisect_search(score_func, elements, found_callback=None): +def bisect_search(score_func, elements, found_callback=None, + skip_verification=False): ''' Performs the bisect search, attempting to find all elements contributing to a positive score. This score_func() function is intended to identify when @@ -690,6 +736,8 @@ def bisect_search(score_func, elements, found_callback=None): @param found_callback: a callback function to be called on every found differing element. Will be given two arguments, the element, and the score from score_func(). + @param skip_verification: skip the verification assertions for performance + reasons. This will run the score_func() two fewer times. @return minimal differing list of all elements that cause score_func() to return positive values, along with their scores, sorted descending by @@ -734,7 +782,15 @@ def bisect_search(score_func, elements, found_callback=None): >>> bisect_search(score_func, [-6, 2, 3, -3, -1, 0, 0, -5, 5]) Traceback (most recent call last): ... - AssertionError: Assumption that differing elements are independent was wrong + AssertionError: Found element does not cause variability: 5 + + Check that the assertion for found element is not turned off with + skip_verification. + >>> bisect_search(score_func, [-6, 2, 3, -3, -1, 0, 0, -5, 5], + ... skip_verification=True) + Traceback (most recent call last): + ... + AssertionError: Found element does not cause variability: 5 Check that the found_callback is not called on false positives. Here I expect no output since no single element can be found. @@ -743,6 +799,23 @@ def bisect_search(score_func, elements, found_callback=None): ... found_callback=print) ... except AssertionError: ... pass + + Check that the verification can catch the other case of overlapping minimal + sets. + >>> def score_func(x): + ... score = 0 + ... if len(x) == 0: return score + ... if min(x) < -5: score += 15 - min(x) + ... return score + max(x) - min(x) - 10 + >>> bisect_search(score_func, [-6, 2, 3, -3, -1, 0, -5, 5]) + Traceback (most recent call last): + ... + AssertionError: Assumption that minimal sets are non-overlapping was wrong + + Check that this is skipped with skip_verification + >>> bisect_search(score_func, [-6, 2, 3, -3, -1, 0, -5, 5], + ... skip_verification=True) + [(-6, 11)] ''' if len(elements) == 0: return [] @@ -773,22 +846,26 @@ def bisect_search(score_func, elements, found_callback=None): # double check that we found a differing element before declaring it # differing score = score_func([differing_element]) - if score > 0: - differing_list.append((differing_element, score)) - # inform caller that a differing element was found - if found_callback != None: - found_callback(differing_element, score) - - # Perform a sanity check. If we have found all of the differing items, then - # compiling with all but these differing items will cause a non-differing - # build. - # This will fail if our hypothesis class is wrong - non_differing_list = \ - list(set(elements).difference(x[0] for x in differing_list)) - assert score_func(non_differing_list) <= 0, \ - 'Assumption that differing elements are independent was wrong' - assert score_func(elements) == score_func([x[0] for x in differing_list]),\ - 'Assumption that minimal sets are non-overlapping was wrong' + assert score > 0, \ + 'Found element does not cause variability: {}' \ + .format(differing_element) + differing_list.append((differing_element, score)) + # inform caller that a differing element was found + if found_callback != None: + found_callback(differing_element, score) + + if not skip_verification: + # Perform a sanity check. If we have found all of the differing items, + # then compiling with all but these differing items will cause a + # non-differing build. + # This will fail if our hypothesis class is wrong + non_differing_list = \ + list(set(elements).difference(x[0] for x in differing_list)) + assert score_func(non_differing_list) <= 0, \ + 'Assumption that differing elements are independent was wrong' + assert score_func(elements) == \ + score_func([x[0] for x in differing_list]),\ + 'Assumption that minimal sets are non-overlapping was wrong' # sort descending by score differing_list.sort(key=lambda x: -x[1]) @@ -952,6 +1029,14 @@ def parse_args(arguments, prog=sys.argv[0]): In the precompile phase, also precompiles the fPIC object files into the top-level obj directory. ''') + parser.add_argument('--skip-verification', action='store_true', + help=''' + By default, bisect will run some assertions + verifying that the assumptions made to have a + performant algorithm are valid. This turns off + those assertions so as to not run the tests more + often than necessary. + ''') args = parser.parse_args(arguments) @@ -1129,11 +1214,12 @@ def search_for_linker_problems(args, bisect_path, replacements, sources, libs): # util.printlog(differing_library_msg.format(filename, score)) #if args.biggest is None: # differing_libs = bisect_search( - # memoized_checker, libs, found_callback=differing_library_callback) + # memoized_checker, libs, found_callback=differing_library_callback, + # skip_verification=args.skip_verification) #else: # differing_libs = bisect_biggest( # memoized_checker, libs, found_callback=differing_library_callback, - # k=args.biggest) + # k=args.biggest, skip_verification=args.skip_verification) #return differing_libs if memoized_checker(libs): return libs @@ -1164,7 +1250,8 @@ def search_for_source_problems(args, bisect_path, replacements, sources): differing_source_callback = lambda filename, score: \ util.printlog(differing_source_msg.format(filename, score)) differing_sources = bisect_search(memoized_checker, sources, - found_callback=differing_source_callback) + found_callback=differing_source_callback, + skip_verification=args.skip_verification) return differing_sources def search_for_symbol_problems(args, bisect_path, replacements, sources, @@ -1234,11 +1321,13 @@ def differing_symbol_callback(sym, score): if args.biggest is None: differing_symbols = bisect_search( memoized_checker, symbol_tuples, - found_callback=differing_symbol_callback) + found_callback=differing_symbol_callback, + skip_verification=args.skip_verification) else: differing_symbols = bisect_biggest( memoized_checker, symbol_tuples, - found_callback=differing_symbol_callback, k=args.biggest) + found_callback=differing_symbol_callback, k=args.biggest, + skip_verification=args.skip_verification) return differing_symbols def search_for_k_most_diff_symbols(args, bisect_path, replacements, sources): @@ -1581,15 +1670,17 @@ def run_bisect(arguments, prog=sys.argv[0]): print(message) logging.info('%s', message) - # Verify that there are no missed files, i.e. those that are more than - # singletons and that are to be grouped with one of the found symbols. - all_searched_symbols = extract_symbols( - [x[0] for x in differing_sources], - os.path.join(args.directory, 'obj')) - checker = _gen_bisect_symbol_checker( - args, bisect_path, replacements, sources, all_searched_symbols) - assert checker(all_searched_symbols) == \ - checker([x[0] for x in differing_symbols]) + if not args.skip_verification: + # Verify that there are no missed files, i.e. those that are more + # than singletons and that are to be grouped with one of the found + # symbols. + all_searched_symbols = extract_symbols( + [x[0] for x in differing_sources], + os.path.join(args.directory, 'obj')) + checker = _gen_bisect_symbol_checker( + args, bisect_path, replacements, sources, all_searched_symbols) + assert checker(all_searched_symbols) == \ + checker([x[0] for x in differing_symbols]) differing_symbols.sort(key=lambda x: (-x[1], x[0])) From 7fc22b6a1cec92e8494b7511cfdd0ad9773ea1b7 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 15:44:23 -0600 Subject: [PATCH 117/196] bisect: fix test for bisect_biggest --- tests/flit_cli/flit_bisect/tst_bisect_biggest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py index b86e0128..19f85bbd 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -235,7 +235,7 @@ Created ... ... Found differing symbol on line 90 -- file2_func1_PROBLEM() (score 7.0) - Found differing source file tests/file3.cpp: score 4.0 + ...Found differing source file tests/file3.cpp: score 4.0 The found highest variability inducing source files: tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) @@ -259,7 +259,7 @@ Created ... ... Found differing symbol on line 90 -- file2_func1_PROBLEM() (score 7.0) - Found differing source file tests/file3.cpp: score 4.0 + ...Found differing source file tests/file3.cpp: score 4.0 The found highest variability inducing source files: tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) From ce9d490f3fae0a134d3ef5f6b7c1e341a758ec77 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 1 Oct 2018 15:50:18 -0600 Subject: [PATCH 118/196] bisect: skip one verification if only one source file --- scripts/flitcli/flit_bisect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 086a92de..1057da41 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1670,7 +1670,7 @@ def run_bisect(arguments, prog=sys.argv[0]): print(message) logging.info('%s', message) - if not args.skip_verification: + if not args.skip_verification and len(differing_sources) > 1: # Verify that there are no missed files, i.e. those that are more # than singletons and that are to be grouped with one of the found # symbols. From 14a7f877366ad0a3ea150b47079ef4d6ae8aaa6c Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 10 Oct 2018 15:43:27 -0600 Subject: [PATCH 119/196] bisect: fix deadlock when updating ground-truth fails --- scripts/flitcli/flit_bisect.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 1057da41..c0bd0a34 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1766,6 +1766,9 @@ def auto_bisect_worker(arg_queue, result_queue): # exit the function pass + except: + result_queue.put((row, -1, None, None, None, 1)) + def parallel_auto_bisect(arguments, prog=sys.argv[0]): ''' Runs bisect in parallel under the auto mode. This is only applicable if From 184f9e76be137dd7cc7b5b752ad26cec3d825e8b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 10 Oct 2018 16:45:16 -0600 Subject: [PATCH 120/196] bisect: add run_make() function that outputs to the log on failure --- scripts/flitcli/flit_bisect.py | 147 ++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 39 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index c0bd0a34..212a21c5 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -256,49 +256,81 @@ def create_bisect_makefile(directory, replacements, gt_src, return makefile -def build_bisect(makefilename, directory, - target='bisect', - verbose=False, - jobs=None): +def run_make(makefilename='Makefile', directory='.', verbose=False, + jobs=mp.cpu_count(), target=None): ''' - Creates the bisect executable by executing a parallel make. + Runs a make command. If the build fails, then stdout and stderr will be + output into the log. - You may alternatively specify a different target than bisect, for example - 'bisect-clean' to specify to clean the unnecessary files for the build, - 'bisect-smallclean' to clean unnecessary things without needing to - recompile for the next bisect step, or - 'distclean' to clean everything, including the generated makefile. - - @param makefilename: the filepath to the makefile - @param directory: where to execute make - @param target: Makefile target to run - @param verbose: False means block output from GNU make and running - @param jobs: number of parallel jobs. Defaults to #cpus + @param makefilename: Name of the Makefile (default 'Makefile') + @param directory: Path to the directory to run in (default '.') + @param verbose: True means echo the output to the console (default False) + @param jobs: number of parallel jobs (default #cpus) + @param target: Makefile target to build (defaults to GNU Make's default) @return None - ''' - logging.info('Building the bisect executable') - if jobs is None: - jobs = mp.cpu_count() - kwargs = dict() + @throws subprocess.CalledProcessError on failure + + Configure the logger to spit to stdout instead of stderr + >>> import logging + >>> logger = logging.getLogger() + >>> for handler in logger.handlers[:]: + ... logger.removeHandler(handler) + >>> import sys + >>> logging.basicConfig(stream=sys.stdout, level=logging.INFO) + + Make sure the exception is thrown + >>> with NamedTemporaryFile(mode='w') as tmpmakefile: + ... print('.PHONY: default\\n', file=tmpmakefile) + ... print('default:\\n', file=tmpmakefile) + ... print('\\t@echo hello\\n', file=tmpmakefile) + ... print('\\t@false\\n', file=tmpmakefile) + ... tmpmakefile.flush() + ... + ... run_make(makefilename=tmpmakefile.name) # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + subprocess.CalledProcessError: Command ... returned non-zero exit status 2. + + See what was output to the logger + >>> with NamedTemporaryFile(mode='w') as tmpmakefile: + ... print('.PHONY: default\\n', file=tmpmakefile) + ... print('default:\\n', file=tmpmakefile) + ... print('\\t@echo hello\\n', file=tmpmakefile) + ... print('\\t@false\\n', file=tmpmakefile) + ... tmpmakefile.flush() + ... + ... try: + ... run_make(makefilename=tmpmakefile.name) #doctest: +ELLIPSIS + ... except: + ... pass + ERROR:root:make error occurred. Here is the output: + make: Entering directory `...' + hello + make: *** [default] Error 1 + make: Leaving directory `...' + + + Undo the logger configurations + >>> for handler in logger.handlers[:]: + ... logger.removeHandler(handler) + ''' command = [ 'make', '-C', directory, '-f', makefilename, '-j', str(jobs), - target, ] + if target is not None: + command.append(target) with NamedTemporaryFile() as tmpout: try: if not verbose: - kwargs['stdout'] = tmpout - kwargs['stderr'] = tmpout subp.check_call(command, stdout=tmpout, stderr=subp.STDOUT) else: ps = subp.Popen(command, stdout=subp.PIPE, stderr=subp.STDOUT) - command = ['tee'] subp.check_call(['tee', tmpout.name], stdin=ps.stdout) except: tmpout.flush() @@ -307,6 +339,34 @@ def build_bisect(makefilename, directory, tmpin.read()) raise +def build_bisect(makefilename, directory, + target='bisect', + verbose=False, + jobs=mp.cpu_count()): + ''' + Creates the bisect executable by executing a parallel make. + + You may alternatively specify a different target than bisect, for example + 'bisect-clean' to specify to clean the unnecessary files for the build, + 'bisect-smallclean' to clean unnecessary things without needing to + recompile for the next bisect step, or + 'distclean' to clean everything, including the generated makefile. + + @param makefilename: the filepath to the makefile + @param directory: where to execute make + @param target: Makefile target to run + @param verbose: False means block output from GNU make and running + @param jobs: number of parallel jobs. Defaults to #cpus + + @return None + ''' + logging.info('Building the bisect executable') + run_make( + makefilename=makefilename, + directory=directory, + verbose=verbose, + jobs=jobs, + target=target) def update_gt_results(directory, verbose=False, jobs=mp.cpu_count(), fpic=False): @@ -316,20 +376,26 @@ def update_gt_results(directory, verbose=False, @param directory: where to execute make @param verbose: False means block output from GNU make and running + @param jobs: number of parallel jobs (default #cpus) + @param fpic: True means compile the gt-fpic files too (default False) + + @return None ''' - kwargs = dict() - if not verbose: - kwargs['stdout'] = subp.DEVNULL - kwargs['stderr'] = subp.DEVNULL gt_resultfile = util.extract_make_var( 'GT_OUT', os.path.join(directory, 'Makefile'))[0] logging.info('Updating ground-truth results - %s', gt_resultfile) print('Updating ground-truth results -', gt_resultfile, end='', flush=True) - subp.check_call( - ['make', '-j', str(jobs), '-C', directory, gt_resultfile], **kwargs) + run_make( + directory=directory, + verbose=verbose, + jobs=jobs, + target=gt_resultfile) if fpic: - subp.check_call( - ['make', '-j', str(jobs), '-C', directory, 'gt-fpic'], **kwargs) + run_make( + directory=directory, + verbose=verbose, + jobs=jobs, + target='gt-fpic') print(' - done') logging.info('Finished Updating ground-truth results') @@ -1423,8 +1489,11 @@ def compile_trouble(directory, compiler, optl, switches, verbose=False, # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet - subp.check_call(['make', '-C', directory, 'Makefile'], - stdout=subp.DEVNULL, stderr=subp.DEVNULL) + run_make( + directory=directory, + verbose=verbose, + jobs=1, + target='Makefile') # trouble compilations all happen in the same directory trouble_path = os.path.join(directory, 'bisect-precompile') @@ -1484,8 +1553,8 @@ def run_bisect(arguments, prog=sys.argv[0]): # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet - subp.check_call(['make', '-C', args.directory, 'Makefile'], - stdout=subp.DEVNULL, stderr=subp.DEVNULL) + run_make(directory=args.directory, verbose=verbose, jobs=1, + target='Makefile') # create a unique directory for this bisect run bisect_dir = create_bisect_dir(args.directory) @@ -1836,8 +1905,8 @@ def parallel_auto_bisect(arguments, prog=sys.argv[0]): # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet - subp.check_call(['make', '-C', args.directory, 'Makefile'], - stdout=subp.DEVNULL, stderr=subp.DEVNULL) + run_make(directory==args.directory, verbose=verbose, jobs=1, + target='Makefile') print('Before parallel bisect run, compile all object files') for i, compilation in enumerate(sorted(compilation_set)): From 144e51b0d07f626da1f13aca2fa6acee6cad9f3d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 10 Oct 2018 16:49:54 -0600 Subject: [PATCH 121/196] bisect: fix syntax errors --- scripts/flitcli/flit_bisect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 212a21c5..f38623fe 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1553,7 +1553,7 @@ def run_bisect(arguments, prog=sys.argv[0]): # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet - run_make(directory=args.directory, verbose=verbose, jobs=1, + run_make(directory=args.directory, verbose=args.verbose, jobs=1, target='Makefile') # create a unique directory for this bisect run @@ -1905,7 +1905,7 @@ def parallel_auto_bisect(arguments, prog=sys.argv[0]): # see if the Makefile needs to be regenerated # we use the Makefile to check for itself, sweet - run_make(directory==args.directory, verbose=verbose, jobs=1, + run_make(directory=args.directory, verbose=args.verbose, jobs=1, target='Makefile') print('Before parallel bisect run, compile all object files') From 888c38efc8ce80b1923a48596d7d66aeb2beca6f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 10 Oct 2018 17:31:43 -0600 Subject: [PATCH 122/196] data/Makefile.in: add -MP to DEPFLAGS This allows header files to be missing without Makefile errors --- data/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Makefile.in b/data/Makefile.in index 7714d896..cd7021ff 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -186,7 +186,7 @@ IS_GCC_4_OR_5 = $(shell expr $(call IS_GCC,$1) \& \ DEV_LDFLAGS = GT_LDFLAGS = -DEPFLAGS += -MMD -MF $(patsubst %.o,%.d,$@) +DEPFLAGS += -MMD -MP -MF $(patsubst %.o,%.d,$@) TESTS = $(wildcard tests/*.cpp) SOURCE = $(wildcard *.cpp) From ac40e06f64891c95ba0dad85ea5be01d31b946e6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 10 Oct 2018 17:49:36 -0600 Subject: [PATCH 123/196] bisect: Update try..except in auto_bisect_worker() - Comment about result_queue.put() describing why it is there - Reraise the exception so that the exception will be printed to stderr for debugging --- scripts/flitcli/flit_bisect.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index f38623fe..b9258d3a 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1836,7 +1836,9 @@ def auto_bisect_worker(arg_queue, result_queue): pass except: + # without putting something onto the result_queue, the parent process will deadlock result_queue.put((row, -1, None, None, None, 1)) + raise def parallel_auto_bisect(arguments, prog=sys.argv[0]): ''' From d298df068e7932a370497bd4907f2901719f8a8c Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 10 Oct 2018 21:05:50 -0600 Subject: [PATCH 124/196] bisect: fix Popen usage Under --verbose, subp.Popen() is used incorrectly and can still cause a deadlock. This is now fixed. --- scripts/flitcli/flit_bisect.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index b9258d3a..a13f788e 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -332,6 +332,9 @@ def run_make(makefilename='Makefile', directory='.', verbose=False, else: ps = subp.Popen(command, stdout=subp.PIPE, stderr=subp.STDOUT) subp.check_call(['tee', tmpout.name], stdin=ps.stdout) + ps.communicate() + if ps.returncode != 0: + raise subp.CalledProcessError(ps.returncode, command) except: tmpout.flush() with open(tmpout.name, 'r') as tmpin: From 9f594c0e4cd6415fb8917c81401fd9deaaddbd35 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 15 Oct 2018 13:49:16 -0600 Subject: [PATCH 125/196] tests: move new bisect tests into the moved directory --- tests/{ => flit_cli}/flit_bisect/data/tests/file4.cpp | 0 tests/{ => flit_cli}/flit_bisect/data/tests/file4.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => flit_cli}/flit_bisect/data/tests/file4.cpp (100%) rename tests/{ => flit_cli}/flit_bisect/data/tests/file4.h (100%) diff --git a/tests/flit_bisect/data/tests/file4.cpp b/tests/flit_cli/flit_bisect/data/tests/file4.cpp similarity index 100% rename from tests/flit_bisect/data/tests/file4.cpp rename to tests/flit_cli/flit_bisect/data/tests/file4.cpp diff --git a/tests/flit_bisect/data/tests/file4.h b/tests/flit_cli/flit_bisect/data/tests/file4.h similarity index 100% rename from tests/flit_bisect/data/tests/file4.h rename to tests/flit_cli/flit_bisect/data/tests/file4.h From 3e51aedd668fae3fd1d6925a1abcc4374079a2dd Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 15 Oct 2018 14:26:15 -0600 Subject: [PATCH 126/196] fix bisect tests --- tests/flit_cli/flit_bisect/tst_bisect.py | 23 ++++++------------- .../flit_bisect/tst_bisect_biggest.py | 2 ++ 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index e1fd75c0..952bf3ee 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -134,12 +134,12 @@ Verify that the four differing sources were output in the "differing sources:" section >>> idx = bisect_out.index('all variability inducing source file(s):') ->>> print('\\n'.join(bisect_out[idx+1:idx+4])) +>>> print('\\n'.join(bisect_out[idx+1:idx+5])) + tests/file4.cpp (score 30.0) tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) tests/file3.cpp (score 4.0) - tests/file4.cpp (score ) ->>> bisect_out[idx+4].startswith('Searching for differing symbols in:') +>>> bisect_out[idx+5].startswith('Searching for differing symbols in:') True Verify that all four files were searched individually @@ -153,11 +153,11 @@ ... if x.startswith(' Found differing symbol on line')]))) line 100 -- file1_func3_PROBLEM() (score 2.0) line 103 -- file3_func5_PROBLEM() (score 3.0) +line 106 -- file4_all() (score 30.0) line 108 -- file1_func4_PROBLEM() (score 3.0) line 91 -- file2_func1_PROBLEM() (score 7.0) line 92 -- file1_func2_PROBLEM() (score 5.0) line 92 -- file3_func2_PROBLEM() (score 1.0) -line 106 - file4_all() (score ) Verify the differing symbols section for file1.cpp >>> idx = bisect_out.index(' All differing symbols in tests/file1.cpp:') @@ -184,22 +184,22 @@ False Verify the bad symbols section for file4.cpp ->>> idx = bisect_out.index(' bad symbols in tests/file4.cpp:') +>>> idx = bisect_out.index(' All differing symbols in tests/file4.cpp:') >>> print('\\n'.join(sorted(bisect_out[idx+1:idx+2]))) - line 106 -- file4_all() (score ) + line 106 -- file4_all() (score 30.0) >>> bisect_out[idx+2].startswith(' ') False Test the All differing symbols section of the output >>> idx = bisect_out.index('All variability inducing symbols:') >>> print('\\n'.join(bisect_out[idx+1:])) # doctest:+ELLIPSIS + /.../tests/file4.cpp:106 ... -- file4_all() (score 30.0) /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() (score 7.0) /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) - /.../tests/file4.cpp:106 ... -- file4_all() (score ) Example output to be expected: Updating ground-truth results - ground-truth.csv - done @@ -276,15 +276,6 @@ /.../tests/file1.cpp:100 _Z19file1_func3_PROBLEMv -- file1_func3_PROBLEM() (score 2.0) /.../tests/file3.cpp:92 _Z19file3_func2_PROBLEMv -- file3_func2_PROBLEM() (score 1.0) -Look for the symbols picked up for file4 in the log ->>> idx = log_contents.index(' Searching for bad symbols in: tests/file4.cpp') ->>> print('\\n'.join(log_contents[idx+4 : idx+9])) # doctest:+ELLIPSIS - None:None ... -- file4_func1() - /.../tests/file4.cpp:91 ... -- file4_func2() - /.../tests/file4.cpp:92 ... -- file4_func3() - /.../tests/file4.cpp:93 ... -- file4_func4() - /.../tests/file4.cpp:106 ... -- file4_all() - TODO: test the log_contents variable TODO: test the -k flag ''' diff --git a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py index 19f85bbd..2b997624 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -118,6 +118,7 @@ ... 'tests/file1.cpp': 10.0, ... 'tests/file2.cpp': 7.0, ... 'tests/file3.cpp': 4.0, +... 'tests/file4.cpp': 0.0, ... } >>> all_symbol_scores = { @@ -136,6 +137,7 @@ ... create_symbol(3, 3, 100, False): 0.0, ... create_symbol(3, 4, 101, False): 0.0, ... create_symbol(3, 5, 103, True): 3.0, +... create_symbol(4, 1, 103, False): 0.0, ... } >>> def build_bisect_stub(makepath, directory, target='bisect', verbose=False, From 7a8d548bf17ac3475eacea99357bbe02c59a3200 Mon Sep 17 00:00:00 2001 From: Ian Briggs Date: Mon, 15 Oct 2018 16:09:42 -0600 Subject: [PATCH 127/196] Only use strong sybols in the text section --- scripts/flitcli/flit_bisect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index d02a19ba..ecbdfca1 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -582,7 +582,7 @@ def extract_symbols(file_or_filelist, objdir): for symbol_string, demangled_string in zip(symbol_strings, demangled_symbol_strings): symbol_type, symbol = symbol_string.split(maxsplit=2)[1:] - if symbol_type == "W": # skip weak symbols + if symbol_type != "T": # only look at strong symbols in the text section continue demangled = demangled_string.split(maxsplit=2)[2] try: From 3082098bddcce801b31bdeb2e4f32852357b6c14 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 08:35:51 -0700 Subject: [PATCH 128/196] bisect: add to the bisect test to make symbol approach fail --- tests/flit_cli/flit_bisect/data/tests/A.cpp | 106 ++++++++++++++++++ tests/flit_cli/flit_bisect/data/tests/A.h | 14 +++ .../flit_bisect/data/tests/BisectTest.cpp | 3 +- 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 tests/flit_cli/flit_bisect/data/tests/A.cpp create mode 100644 tests/flit_cli/flit_bisect/data/tests/A.h diff --git a/tests/flit_cli/flit_bisect/data/tests/A.cpp b/tests/flit_cli/flit_bisect/data/tests/A.cpp new file mode 100644 index 00000000..2d1c4164 --- /dev/null +++ b/tests/flit_cli/flit_bisect/data/tests/A.cpp @@ -0,0 +1,106 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + +#include "A.h" + +#include + +#include + +int A::offset = 2; + +A::A() {} +A::~A() {} + +int A::fileA_method1_PROBLEM() { + if (std::string(FLIT_OPTL) == "-O3") { + return 3 + offset; // variability introduced = offset = 2 + } else { + return 3; + } +} + +int fileA_all() { + A a; + return a.fileA_method1_PROBLEM(); +} diff --git a/tests/flit_cli/flit_bisect/data/tests/A.h b/tests/flit_cli/flit_bisect/data/tests/A.h new file mode 100644 index 00000000..8110d11a --- /dev/null +++ b/tests/flit_cli/flit_bisect/data/tests/A.h @@ -0,0 +1,14 @@ +#ifndef A_H +#define A_H + +class A { +public: + static int offset; // is a global strong symbol that is not a function + A(); + virtual ~A(); + virtual int fileA_method1_PROBLEM(); +}; + +int fileA_all(); + +#endif // A_H diff --git a/tests/flit_cli/flit_bisect/data/tests/BisectTest.cpp b/tests/flit_cli/flit_bisect/data/tests/BisectTest.cpp index 75292167..b999332c 100644 --- a/tests/flit_cli/flit_bisect/data/tests/BisectTest.cpp +++ b/tests/flit_cli/flit_bisect/data/tests/BisectTest.cpp @@ -85,6 +85,7 @@ #include "file2.h" #include "file3.h" #include "file4.h" +#include "A.h" #include @@ -106,7 +107,7 @@ class BisectTest : public flit::TestBase { protected: virtual flit::Variant run_impl(const std::vector &ti) override { FLIT_UNUSED(ti); - return file1_all() + file2_all() + file3_all() + file4_all(); + return file1_all() + file2_all() + file3_all() + file4_all() + fileA_all(); } protected: From 61d05064255d491fdb7f15c03296fb00bf09474d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 09:23:47 -0700 Subject: [PATCH 129/196] flit-cli: make sure init, update, and bisect return an int --- scripts/flitcli/flit.py | 2 +- scripts/flitcli/flit_init.py | 2 +- scripts/flitcli/flit_update.py | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/flitcli/flit.py b/scripts/flitcli/flit.py index 0da95c91..015bf604 100755 --- a/scripts/flitcli/flit.py +++ b/scripts/flitcli/flit.py @@ -174,7 +174,7 @@ def main(arguments, outstream=None): try: oldout = sys.stdout sys.stdout = outstream - _main_impl(arguments) + return _main_impl(arguments) finally: sys.stdout = oldout diff --git a/scripts/flitcli/flit_init.py b/scripts/flitcli/flit_init.py index 125b48ba..08f30d61 100644 --- a/scripts/flitcli/flit_init.py +++ b/scripts/flitcli/flit_init.py @@ -161,7 +161,7 @@ def copy_files(dest_to_src, remove_license=True): litmus_to_copy[os.path.join('tests', srcfile)] = srcpath copy_files(litmus_to_copy) - flit_update.main(['--directory', args.directory]) + return flit_update.main(['--directory', args.directory]) if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 14d782b6..9e612e39 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -195,5 +195,7 @@ def main(arguments, prog=sys.argv[0]): flitutil.process_in_file(os.path.join(conf.data_dir, 'Makefile.in'), makefile, replacements, overwrite=True) + return 0 + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) From 5cb2164e9957597c375398036a123491579b4879 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 09:45:45 -0700 Subject: [PATCH 130/196] tst_empty_project: update for checking the return value --- tests/flit_makefile/tst_empty_project.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/flit_makefile/tst_empty_project.py b/tests/flit_makefile/tst_empty_project.py index 10240ce2..320af4c5 100644 --- a/tests/flit_makefile/tst_empty_project.py +++ b/tests/flit_makefile/tst_empty_project.py @@ -87,10 +87,15 @@ Let's now make a temporary directory and test that flit init populates the correct files + +>>> class TestError(RuntimeError): pass + >>> import glob >>> import os >>> with th.tempdir() as temp_dir: -... th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS +... retval = th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS +... if retval != 0: +... raise TestError('Main returned {}'.format(retval)) ... files = os.listdir(temp_dir) Creating /.../flit-config.toml Creating /.../custom.mk From a2119f756d87ec40dc7517cf439256a97a9a8f4e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 09:24:24 -0700 Subject: [PATCH 131/196] tests: update bisect tests for A.cpp --- scripts/flitcli/flit_bisect.py | 18 ++- tests/flit_cli/flit_bisect/tst_bisect.py | 104 ++++-------------- .../flit_bisect/tst_bisect_biggest.py | 7 +- 3 files changed, 39 insertions(+), 90 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index ecbdfca1..79c90127 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1748,13 +1748,19 @@ def run_bisect(arguments, prog=sys.argv[0]): # Verify that there are no missed files, i.e. those that are more # than singletons and that are to be grouped with one of the found # symbols. - all_searched_symbols = extract_symbols( - [x[0] for x in differing_sources], - os.path.join(args.directory, 'obj')) + message = 'Verifying assumption about independent symbols' + print(message) + logging.info('%s', message) + fsymbol_tuples, remaining_symbols = \ + extract_symbols([x[0] for x in differing_sources], + os.path.join(args.directory, 'obj')) checker = _gen_bisect_symbol_checker( - args, bisect_path, replacements, sources, all_searched_symbols) - assert checker(all_searched_symbols) == \ - checker([x[0] for x in differing_symbols]) + args, bisect_path, replacements, sources, fsymbol_tuples, + remaining_symbols) + assert checker(fsymbol_tuples) == \ + checker([x[0] for x in differing_symbols]), \ + 'Assumption about independent symbols is False, ' \ + 'false negative results are possible' differing_symbols.sort(key=lambda x: (-x[1], x[0])) diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index 952bf3ee..501f9a51 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -95,19 +95,25 @@ >>> import subprocess as subp >>> from io import StringIO +>>> class BisectTestError(RuntimeError): pass + >>> with th.tempdir() as temp_dir: ... with StringIO() as ostream: -... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) ... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise BisectTestError('Main #1 returned {}'.format(retval)) ... shutil.rmtree(os.path.join(temp_dir, 'tests')) ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) ... with StringIO() as ostream: -... _ = th.flit.main(['bisect', '-C', temp_dir, +... retval = th.flit.main(['bisect', '-C', temp_dir, ... '--precision', 'double', ... 'g++ -O3', 'BisectTest'], ... outstream=ostream) ... bisect_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise BisectTestError('Main #2 returned {}'.format(retval)) ... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: ... raw_log = fin.readlines() ... stripped_log = [line[line.index(' bisect:')+8:].rstrip() @@ -129,23 +135,24 @@ Verify that all source files were found and output during the search >>> sorted([x.split(':')[0].split()[-1] for x in bisect_out ... if x.startswith(' Found differing source file')]) -['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp', 'tests/file4.cpp'] +['tests/A.cpp', 'tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp', 'tests/file4.cpp'] Verify that the four differing sources were output in the "differing sources:" section >>> idx = bisect_out.index('all variability inducing source file(s):') ->>> print('\\n'.join(bisect_out[idx+1:idx+5])) +>>> print('\\n'.join(bisect_out[idx+1:idx+6])) tests/file4.cpp (score 30.0) tests/file1.cpp (score 10.0) tests/file2.cpp (score 7.0) tests/file3.cpp (score 4.0) ->>> bisect_out[idx+5].startswith('Searching for differing symbols in:') + tests/A.cpp (score 2.0) +>>> bisect_out[idx+6].startswith('Searching for differing symbols in:') True Verify that all four files were searched individually >>> sorted([x.split()[-1] for x in bisect_out ... if x.startswith('Searching for differing symbols in:')]) -['tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp', 'tests/file4.cpp'] +['tests/A.cpp', 'tests/file1.cpp', 'tests/file2.cpp', 'tests/file3.cpp', 'tests/file4.cpp'] Verify all non-templated functions were identified during the symbol searches >>> print('\\n'.join( @@ -158,6 +165,7 @@ line 91 -- file2_func1_PROBLEM() (score 7.0) line 92 -- file1_func2_PROBLEM() (score 5.0) line 92 -- file3_func2_PROBLEM() (score 1.0) +line 95 -- A::fileA_method1_PROBLEM() (score 2.0) Verify the differing symbols section for file1.cpp >>> idx = bisect_out.index(' All differing symbols in tests/file1.cpp:') @@ -190,6 +198,13 @@ >>> bisect_out[idx+2].startswith(' ') False +Verify the bad symbols section for fileA.cpp +>>> idx = bisect_out.index(' All differing symbols in tests/A.cpp:') +>>> print('\\n'.join(sorted(bisect_out[idx+1:idx+2]))) + line 95 -- A::fileA_method1_PROBLEM() (score 2.0) +>>> bisect_out[idx+2].startswith(' ') +False + Test the All differing symbols section of the output >>> idx = bisect_out.index('All variability inducing symbols:') >>> print('\\n'.join(bisect_out[idx+1:])) # doctest:+ELLIPSIS @@ -198,86 +213,11 @@ /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) + /.../tests/A.cpp:95 ... -- A::fileA_method1_PROBLEM() (score 2.0) /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) -Example output to be expected: -Updating ground-truth results - ground-truth.csv - done -Searching for differing source files: - Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 - Created /.../bisect-01/bisect-make-02.mk - compiling and running - score 14.0 - Created /.../bisect-01/bisect-make-03.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-04.mk - compiling and running - score 10.0 - Found differing source file tests/file1.cpp: score 10.0 - Created /.../bisect-01/bisect-make-05.mk - compiling and running - score 11.0 - Created /.../bisect-01/bisect-make-06.mk - compiling and running - score 4.0 - Created /.../bisect-01/bisect-make-07.mk - compiling and running - score 4.0 - Found differing source file tests/file3.cpp: score 4.0 - Created /.../bisect-01/bisect-make-08.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-09.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-10.mk - compiling and running - score 7.0 - Found differing source file tests/file2.cpp: score 7.0 - Created /.../bisect-01/bisect-make-11.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-12.mk - compiling and running - score 0.0 - all variability inducing source file(s): - tests/file1.cpp (score 10.0) - tests/file2.cpp (score 7.0) - tests/file3.cpp (score 4.0) -Searching for differing symbols in: tests/file1.cpp - Created /.../bisect-01/bisect-make-13.mk - compiling and running - score 10.0 - Created /.../bisect-01/bisect-make-14.mk - compiling and running - score 5.0 - Created /.../bisect-01/bisect-make-15.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-16.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-17.mk - compiling and running - score 5.0 - Found differing symbol on line 92 -- file1_func2_PROBLEM() (score 5.0) - Created /.../bisect-01/bisect-make-18.mk - compiling and running - score 5.0 - Created /.../bisect-01/bisect-make-19.mk - compiling and running - score 5.0 - Created /.../bisect-01/bisect-make-20.mk - compiling and running - score 2.0 - Found differing symbol on line 100 -- file1_func3_PROBLEM() (score 2.0) - Created /.../bisect-01/bisect-make-21.mk - compiling and running - score 3.0 - Created /.../bisect-01/bisect-make-22.mk - compiling and running - score 3.0 - Found differing symbol on line 108 -- file1_func4_PROBLEM() (score 3.0) - Created /.../bisect-01/bisect-make-23.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-24.mk - compiling and running - score 0.0 - All differing symbols in tests/file1.cpp: - line 92 -- file1_func2_PROBLEM() (score 5.0) - line 108 -- file1_func4_PROBLEM() (score 3.0) - line 100 -- file1_func3_PROBLEM() (score 2.0) -Searching for differing symbols in: tests/file2.cpp - Created /.../bisect-01/bisect-make-25.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-26.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-27.mk - compiling and running - score 7.0 - Created /.../bisect-01/bisect-make-28.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-29.mk - compiling and running - score 7.0 - Found differing symbol on line 91 -- file2_func1_PROBLEM() (score 7.0) - Created /.../bisect-01/bisect-make-30.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-31.mk - compiling and running - score 0.0 - All differing symbols in tests/file2.cpp: - line 91 -- file2_func1_PROBLEM() (score 7.0) -Searching for differing symbols in: tests/file3.cpp - Created /.../bisect-01/bisect-make-32.mk - compiling and running - score 4.0 - Created /.../bisect-01/bisect-make-33.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-34.mk - compiling and running - score 4.0 - Created /.../bisect-01/bisect-make-35.mk - compiling and running - score 1.0 - Found differing symbol on line 92 -- file3_func2_PROBLEM() (score 1.0) - Created /.../bisect-01/bisect-make-36.mk - compiling and running - score 3.0 - Created /.../bisect-01/bisect-make-37.mk - compiling and running - score 3.0 - Found differing symbol on line 103 -- file3_func5_PROBLEM() (score 3.0) - Created /.../bisect-01/bisect-make-38.mk - compiling and running - score 0.0 - Created /.../bisect-01/bisect-make-39.mk - compiling and running - score 0.0 - All differing symbols in tests/file3.cpp: - line 103 -- file3_func5_PROBLEM() (score 3.0) - line 92 -- file3_func2_PROBLEM() (score 1.0) -All variability inducing symbols: - /.../tests/file2.cpp:91 _Z19file2_func1_PROBLEMv -- file2_func1_PROBLEM() (score 7.0) - /.../tests/file1.cpp:92 _Z19file1_func2_PROBLEMv -- file1_func2_PROBLEM() (score 5.0) - /.../tests/file1.cpp:108 _Z19file1_func4_PROBLEMv -- file1_func4_PROBLEM() (score 3.0) - /.../tests/file3.cpp:103 _Z19file3_func5_PROBLEMv -- file3_func5_PROBLEM() (score 3.0) - /.../tests/file1.cpp:100 _Z19file1_func3_PROBLEMv -- file1_func3_PROBLEM() (score 2.0) - /.../tests/file3.cpp:92 _Z19file3_func2_PROBLEMv -- file3_func2_PROBLEM() (score 1.0) - TODO: test the log_contents variable -TODO: test the -k flag ''' # Test setup before the docstring is run. diff --git a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py index 2b997624..d34da25c 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -119,6 +119,7 @@ ... 'tests/file2.cpp': 7.0, ... 'tests/file3.cpp': 4.0, ... 'tests/file4.cpp': 0.0, +... 'tests/A.cpp': 2.0, ... } >>> all_symbol_scores = { @@ -138,6 +139,8 @@ ... create_symbol(3, 4, 101, False): 0.0, ... create_symbol(3, 5, 103, True): 3.0, ... create_symbol(4, 1, 103, False): 0.0, +... Sym('tests/A.cpp', '_ZN1A21fileA_method1_PROBLEMEv', +... 'A::fileA_method1_PROBLEM()', 'tests/A.cpp', 95): 2.0, ... } >>> def build_bisect_stub(makepath, directory, target='bisect', verbose=False, @@ -225,7 +228,7 @@ >>> print('\\n'.join(bisect_out_1)) # doctest:+ELLIPSIS Updating ground-truth results - ground-truth.csv - done Looking for the top 1 different symbol(s) by starting with files - Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 21.0 + Created /.../bisect-01/bisect-make-01.mk - compiling and running - score 23.0 ... Found differing source file tests/file1.cpp: score 10.0 Searching for differing symbols in: tests/file1.cpp @@ -248,7 +251,7 @@ >>> print('\\n'.join(bisect_out_2)) # doctest:+ELLIPSIS Updating ground-truth results - ground-truth.csv - done Looking for the top 2 different symbol(s) by starting with files - Created /.../bisect-02/bisect-make-01.mk - compiling and running - score 21.0 + Created /.../bisect-02/bisect-make-01.mk - compiling and running - score 23.0 ... Found differing source file tests/file1.cpp: score 10.0 Searching for differing symbols in: tests/file1.cpp From 65b5818235643653af5c42c4156f73bd6feea25d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Sat, 17 Nov 2018 09:16:50 -0700 Subject: [PATCH 132/196] symbol-bisect: only search over functions --- scripts/flitcli/flit_bisect.py | 90 +++++++++---------- tests/flit_cli/flit_bisect/tst_bisect.py | 6 +- .../flit_bisect/tst_bisect_biggest.py | 4 +- 3 files changed, 45 insertions(+), 55 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 79c90127..3a3de257 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -96,7 +96,6 @@ import logging import multiprocessing as mp import os -import re import shutil import sqlite3 import subprocess as subp @@ -338,8 +337,9 @@ def run_make(makefilename='Makefile', directory='.', verbose=False, except: tmpout.flush() with open(tmpout.name, 'r') as tmpin: - logging.error('make error occurred. Here is the output:\n' + - tmpin.read()) + msg = 'make error occurred. Here is the output:\n' \ + + tmpin.read() + logging.error('%s', msg) raise def build_bisect(makefilename, directory, @@ -523,15 +523,21 @@ def extract_symbols(file_or_filelist, objdir): @param objdir: (str) directory where object files are compiled for the given files. - @return a list of SymbolTuple objects + @return two lists of SymbolTuple objects (funcsyms, remaining). + The first is the list of exported functions that are strong symbols and + have a filename and line number where they are defined. The second is + all remaining symbols that are strong, exported, and defined. ''' - symbol_tuples = [] + funcsym_tuples = [] + remainingsym_tuples = [] # if it is not a string, then assume it is a list of strings if not isinstance(file_or_filelist, str): for fname in file_or_filelist: - symbol_tuples.extend(extract_symbols(fname, objdir)) - return symbol_tuples + funcsyms, remaining = extract_symbols(fname, objdir) + funcsym_tuples.extend(funcsyms) + remainingsym_tuples.extend(remaining) + return (funcsym_tuples, remainingsym_tuples) # now we know it is a string, so assume it is a filename fname = file_or_filelist @@ -546,6 +552,7 @@ def extract_symbols(file_or_filelist, objdir): 'nm', '--extern-only', '--defined-only', + '--line-numbers', fobj, ]).decode('utf-8').splitlines() demangled_symbol_strings = subp.check_output([ @@ -555,45 +562,27 @@ def extract_symbols(file_or_filelist, objdir): '--demangle', fobj, ]).decode('utf-8').splitlines() - objdump_strings = subp.check_output([ - 'objdump', '--disassemble-all', '--line-numbers', fobj, - ]).decode('utf-8').splitlines() - - # create the symbol -> (fname, lineno) map - symbol_line_mapping = dict() - symbol = None - for line in objdump_strings: - if len(line.strip()) == 0: # skip empty lines - continue - if line[0].isdigit(): # we are at a symbol - symbol = line.split()[1][1:-2] - continue - if symbol is None: # if we don't have an active symbol - continue # then skip - srcmatch = re.search(':[0-9]+$', line) - if srcmatch is not None: - deffile = line[:srcmatch.start()] - defline = int(line[srcmatch.start()+1:]) - symbol_line_mapping[symbol] = (deffile, defline) - symbol = None # deactivate the symbol to not overwrite - # generate the symbol tuples for symbol_string, demangled_string in zip(symbol_strings, demangled_symbol_strings): symbol_type, symbol = symbol_string.split(maxsplit=2)[1:] - if symbol_type != "T": # only look at strong symbols in the text section - continue demangled = demangled_string.split(maxsplit=2)[2] - try: - deffile, defline = symbol_line_mapping[symbol] - except KeyError: - deffile, defline = None, None - symbol_tuples.append( - SymbolTuple(fname, symbol, demangled, deffile, defline)) - _extract_symbols_memos[fobj] = symbol_tuples - return symbol_tuples + if symbol_type == 'W': # skip weak symbols + continue + + if '\t' in symbol: # if filename and linenumber are specified + deffile, defline = symbol.split('\t', maxsplit=1)[1].split(':') + defline = int(defline) + funcsym_tuples.append( + SymbolTuple(fname, symbol, demangled, deffile, defline)) + else: + remainingsym_tuples.append( + SymbolTuple(fname, symbol, demangled, None, None)) + + _extract_symbols_memos[fobj] = (funcsym_tuples, remainingsym_tuples) + return funcsym_tuples, remainingsym_tuples def memoize_strlist_func(func): ''' @@ -922,7 +911,7 @@ def bisect_search(score_func, elements, found_callback=None, .format(differing_element) differing_list.append((differing_element, score)) # inform caller that a differing element was found - if found_callback != None: + if found_callback is not None: found_callback(differing_element, score) if not skip_verification: @@ -1216,7 +1205,7 @@ def builder_and_checker(sources_to_optimize): return memoize_strlist_func(builder_and_checker) def _gen_bisect_symbol_checker(args, bisect_path, replacements, sources, - symbols, indent=' '): + fsymbols, remainingsymbols, indent=' '): ''' Generates and returns the function that builds and check a list of sources for showing variability. The returned function is memoized, so no need to @@ -1236,7 +1225,8 @@ def builder_and_checker(symbols_to_optimize): @return The comparison value between this mixed compilation and the full baseline compilation. ''' - gt_symbols = list(set(symbols).difference(symbols_to_optimize)) + gt_symbols = list(set(fsymbols + remainingsymbols) + .difference(symbols_to_optimize)) all_sources = list(sources) # copy the list of all source files symbol_sources = [x.src for x in symbols_to_optimize + gt_symbols] trouble_src = [] @@ -1355,20 +1345,20 @@ def search_for_symbol_problems(args, bisect_path, replacements, sources, logging.info('%sNote: only searching over globally exported functions', indent) logging.debug('%sSymbols:', indent) - symbol_tuples = extract_symbols(differing_source, - os.path.join(args.directory, 'obj')) - for sym in symbol_tuples: + fsymbol_tuples, remaining_symbols = \ + extract_symbols(differing_source, os.path.join(args.directory, 'obj')) + for sym in fsymbol_tuples: message = '{indent} {sym.fname}:{sym.lineno} {sym.symbol} ' \ '-- {sym.demangled}'.format(indent=indent, sym=sym) logging.debug('%s', message) memoized_checker = _gen_bisect_symbol_checker( - args, bisect_path, replacements, sources, symbol_tuples, - indent=indent + ' ') + args, bisect_path, replacements, sources, fsymbol_tuples, + remaining_symbols, indent=indent + ' ') # Check to see if -fPIC destroyed any chance of finding any differing # symbols - if memoized_checker(symbol_tuples) <= 0.0: + if memoized_checker(fsymbol_tuples) <= 0.0: message_1 = '{} Warning: -fPIC compilation destroyed the ' \ 'optimization'.format(indent) message_2 = '{} Cannot find any trouble symbols'.format(indent) @@ -1391,12 +1381,12 @@ def differing_symbol_callback(sym, score): if args.biggest is None: differing_symbols = bisect_search( - memoized_checker, symbol_tuples, + memoized_checker, fsymbol_tuples, found_callback=differing_symbol_callback, skip_verification=args.skip_verification) else: differing_symbols = bisect_biggest( - memoized_checker, symbol_tuples, + memoized_checker, fsymbol_tuples, found_callback=differing_symbol_callback, k=args.biggest, skip_verification=args.skip_verification) return differing_symbols diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index 501f9a51..3c19b99c 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -162,7 +162,7 @@ line 103 -- file3_func5_PROBLEM() (score 3.0) line 106 -- file4_all() (score 30.0) line 108 -- file1_func4_PROBLEM() (score 3.0) -line 91 -- file2_func1_PROBLEM() (score 7.0) +line 90 -- file2_func1_PROBLEM() (score 7.0) line 92 -- file1_func2_PROBLEM() (score 5.0) line 92 -- file3_func2_PROBLEM() (score 1.0) line 95 -- A::fileA_method1_PROBLEM() (score 2.0) @@ -179,7 +179,7 @@ Verify the differing symbols section for file2.cpp >>> idx = bisect_out.index(' All differing symbols in tests/file2.cpp:') >>> bisect_out[idx+1] -' line 91 -- file2_func1_PROBLEM() (score 7.0)' +' line 90 -- file2_func1_PROBLEM() (score 7.0)' >>> bisect_out[idx+2].startswith(' ') False @@ -209,7 +209,7 @@ >>> idx = bisect_out.index('All variability inducing symbols:') >>> print('\\n'.join(bisect_out[idx+1:])) # doctest:+ELLIPSIS /.../tests/file4.cpp:106 ... -- file4_all() (score 30.0) - /.../tests/file2.cpp:91 ... -- file2_func1_PROBLEM() (score 7.0) + /.../tests/file2.cpp:90 ... -- file2_func1_PROBLEM() (score 7.0) /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) diff --git a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py index d34da25c..b2228f36 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -173,11 +173,11 @@ ... if not isinstance(file_or_filelist, str): ... for fname in file_or_filelist: ... symbol_tuples.extend(extract_symbols_stub(fname, objdir)) -... return symbol_tuples +... return symbol_tuples, [] ... ... return sorted([x for x in all_symbol_scores ... if x.fname == file_or_filelist], -... key=lambda x: x.symbol) +... key=lambda x: x.symbol), [] >>> flit_bisect.build_bisect = build_bisect_stub >>> flit_bisect.update_gt_results = update_gt_results_stub From 2be02b5fc6ca2bb1b3020e7e7c40741ad02708f3 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 10:05:31 -0700 Subject: [PATCH 133/196] tst_run_mpi: update to check return value of main() --- tests/flit_mpi/tst_run_mpi.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/flit_mpi/tst_run_mpi.py b/tests/flit_mpi/tst_run_mpi.py index d33e1cc1..7b101802 100644 --- a/tests/flit_mpi/tst_run_mpi.py +++ b/tests/flit_mpi/tst_run_mpi.py @@ -93,12 +93,20 @@ >>> import shutil >>> import subprocess as subp +>>> class TestError(RuntimeError): pass + >>> with th.tempdir() as temp_dir: -... th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS +... retval = th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS +... if retval != 0: +... raise TestError('Main #1 returned with {}, failed to initialize' +... .format(retval)) ... _ = shutil.copy(os.path.join('data', 'MpiHello.cpp'), ... os.path.join(temp_dir, 'tests')) ... _ = shutil.copy(os.path.join('data', 'flit-config.toml'), temp_dir) -... th.flit.main(['update', '-C', temp_dir]) +... retval = th.flit.main(['update', '-C', temp_dir]) +... if retval != 0: +... raise TestError('Main #2 returned with {}, failed to update' +... .format(retval)) ... compile_str = subp.check_output(['make', '-C', temp_dir, 'gt'], ... stderr=subp.STDOUT) ... run_str = subp.check_output(['make', '-C', temp_dir, 'ground-truth.csv'], From 13bd470103f45bca955252f6a7cf3913662beafe Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 10:24:57 -0700 Subject: [PATCH 134/196] Add licence headers to files missing them --- benchmarks/polybench/main.cpp | 83 +++++++++++++++++++++++ benchmarks/random/main.cpp | 83 +++++++++++++++++++++++ scripts/watch-progress.sh | 82 ++++++++++++++++++++++ tests/flit_cli/flit_bisect/data/tests/A.h | 83 +++++++++++++++++++++++ 4 files changed, 331 insertions(+) diff --git a/benchmarks/polybench/main.cpp b/benchmarks/polybench/main.cpp index 60a4a640..5b4dbcdb 100644 --- a/benchmarks/polybench/main.cpp +++ b/benchmarks/polybench/main.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "flit.h" int main(int argCount, char* argList[]) { diff --git a/benchmarks/random/main.cpp b/benchmarks/random/main.cpp index 60a4a640..5b4dbcdb 100644 --- a/benchmarks/random/main.cpp +++ b/benchmarks/random/main.cpp @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #include "flit.h" int main(int argCount, char* argList[]) { diff --git a/scripts/watch-progress.sh b/scripts/watch-progress.sh index 062213f4..bdaad8c0 100755 --- a/scripts/watch-progress.sh +++ b/scripts/watch-progress.sh @@ -1,4 +1,86 @@ #!/bin/bash +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + cd results watch -n 2 \ diff --git a/tests/flit_cli/flit_bisect/data/tests/A.h b/tests/flit_cli/flit_bisect/data/tests/A.h index 8110d11a..a4fb888c 100644 --- a/tests/flit_cli/flit_bisect/data/tests/A.h +++ b/tests/flit_cli/flit_bisect/data/tests/A.h @@ -1,3 +1,86 @@ +/* -- LICENSE BEGIN -- + * + * Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. + * + * Produced at the Lawrence Livermore National Laboratory + * + * Written by + * Michael Bentley (mikebentley15@gmail.com), + * Geof Sawaya (fredricflinstone@gmail.com), + * and Ian Briggs (ian.briggs@utah.edu) + * under the direction of + * Ganesh Gopalakrishnan + * and Dong H. Ahn. + * + * LLNL-CODE-743137 + * + * All rights reserved. + * + * This file is part of FLiT. For details, see + * https://pruners.github.io/flit + * Please also read + * https://github.com/PRUNERS/FLiT/blob/master/LICENSE + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the disclaimer below. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the disclaimer + * (as noted below) in the documentation and/or other materials + * provided with the distribution. + * + * - Neither the name of the LLNS/LLNL nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL + * SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + * + * Additional BSD Notice + * + * 1. This notice is required to be provided under our contract + * with the U.S. Department of Energy (DOE). This work was + * produced at Lawrence Livermore National Laboratory under + * Contract No. DE-AC52-07NA27344 with the DOE. + * + * 2. Neither the United States Government nor Lawrence Livermore + * National Security, LLC nor any of their employees, makes any + * warranty, express or implied, or assumes any liability or + * responsibility for the accuracy, completeness, or usefulness of + * any information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately-owned + * rights. + * + * 3. Also, reference herein to any specific commercial products, + * process, or services by trade name, trademark, manufacturer or + * otherwise does not necessarily constitute or imply its + * endorsement, recommendation, or favoring by the United States + * Government or Lawrence Livermore National Security, LLC. The + * views and opinions of authors expressed herein do not + * necessarily state or reflect those of the United States + * Government or Lawrence Livermore National Security, LLC, and + * shall not be used for advertising or product endorsement + * purposes. + * + * -- LICENSE END -- + */ + #ifndef A_H #define A_H From 48429042eddadaab3f1cc5693a8a389d76ed402f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 20 Nov 2018 19:12:49 +0000 Subject: [PATCH 135/196] bisect: strip of filename from symbol --- scripts/flitcli/flit_bisect.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 3a3de257..9ad37c4b 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -573,7 +573,8 @@ def extract_symbols(file_or_filelist, objdir): continue if '\t' in symbol: # if filename and linenumber are specified - deffile, defline = symbol.split('\t', maxsplit=1)[1].split(':') + symbol, definition = symbol.split('\t', maxsplit=1) + deffile, defline = definition.split(':') defline = int(defline) funcsym_tuples.append( SymbolTuple(fname, symbol, demangled, deffile, defline)) From 7bd4a4e805be053f4782cedc456343755c16537d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 06:04:15 +0000 Subject: [PATCH 136/196] bisect: first attempt to doing flitelf.py --- scripts/flitcli/flit_bisect.py | 58 +-------- scripts/flitcli/flitelf.py | 210 +++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+), 52 deletions(-) create mode 100644 scripts/flitcli/flitelf.py diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 9ad37c4b..6153dfde 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -103,6 +103,7 @@ import flitconfig as conf import flitutil as util +import flitelf as elf brief_description = 'Bisect compilation to identify problematic source code' @@ -499,22 +500,10 @@ def is_result_differing(resultfile): ''' return float(get_comparison_result(resultfile)) != 0.0 -SymbolTuple = namedtuple('SymbolTuple', 'src, symbol, demangled, fname, lineno') -SymbolTuple.__doc__ = ''' -Tuple containing information about the symbols in a file. Has the following -attributes: - src: source file that was compiled - symbol: mangled symbol in the compiled version - demangled: demangled version of symbol - fname: filename where the symbol is actually defined. This usually - will be equal to src, but may not be in some situations. - lineno: line number of definition within fname. -''' - _extract_symbols_memos = {} def extract_symbols(file_or_filelist, objdir): ''' - Extracts symbols for the given file(s) given. The corresponding object is + Extracts symbols for the given source file(s). The corresponding object is assumed to be in the objdir with the filename replaced with the GNU Make pattern %.cpp=%_gt.o. @@ -528,11 +517,11 @@ def extract_symbols(file_or_filelist, objdir): have a filename and line number where they are defined. The second is all remaining symbols that are strong, exported, and defined. ''' - funcsym_tuples = [] - remainingsym_tuples = [] # if it is not a string, then assume it is a list of strings if not isinstance(file_or_filelist, str): + funcsym_tuples = [] + remainingsym_tuples = [] for fname in file_or_filelist: funcsyms, remaining = extract_symbols(fname, objdir) funcsym_tuples.extend(funcsyms) @@ -547,43 +536,8 @@ def extract_symbols(file_or_filelist, objdir): if fobj in _extract_symbols_memos: return _extract_symbols_memos[fobj] - # use nm and objdump to get the binary information we need - symbol_strings = subp.check_output([ - 'nm', - '--extern-only', - '--defined-only', - '--line-numbers', - fobj, - ]).decode('utf-8').splitlines() - demangled_symbol_strings = subp.check_output([ - 'nm', - '--extern-only', - '--defined-only', - '--demangle', - fobj, - ]).decode('utf-8').splitlines() - - # generate the symbol tuples - for symbol_string, demangled_string in zip(symbol_strings, - demangled_symbol_strings): - symbol_type, symbol = symbol_string.split(maxsplit=2)[1:] - demangled = demangled_string.split(maxsplit=2)[2] - - if symbol_type == 'W': # skip weak symbols - continue - - if '\t' in symbol: # if filename and linenumber are specified - symbol, definition = symbol.split('\t', maxsplit=1) - deffile, defline = definition.split(':') - defline = int(defline) - funcsym_tuples.append( - SymbolTuple(fname, symbol, demangled, deffile, defline)) - else: - remainingsym_tuples.append( - SymbolTuple(fname, symbol, demangled, None, None)) - - _extract_symbols_memos[fobj] = (funcsym_tuples, remainingsym_tuples) - return funcsym_tuples, remainingsym_tuples + _extract_symbols_memos[fobj] = elf.extract_symbols(fobj, fname) + return _extract_symbols_memos[fobj] def memoize_strlist_func(func): ''' diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py new file mode 100644 index 00000000..e9a66acb --- /dev/null +++ b/scripts/flitcli/flitelf.py @@ -0,0 +1,210 @@ +# Much of this is copied from the examples given in +# https://github.com/eliben/pyelftools.git + +from collections import namedtuple +import sys + +from elftools.common.py3compat import bytes2str +from elftools.dwarf.descriptions import describe_form_class +from elftools.elf.elffile import ELFFile +from elftools.elf.sections import SymbolTableSection + +SymbolTuple = namedtuple('SymbolTuple', 'src, symbol, demangled, fname, lineno') +SymbolTuple.__doc__ = ''' +Tuple containing information about the symbols in a file. Has the following +attributes: + src: source file that was compiled + symbol: mangled symbol in the compiled version + demangled: demangled version of symbol + fname: filename where the symbol is actually defined. This usually + will be equal to src, but may not be in some situations. + lineno: line number of definition within fname. +''' + +def extract_symbols(objfile, srcfile): + ''' + Extracts symbols for the given object file. + + @param objfile: (str) path to object file + + @return two lists of SymbolTuple objects (funcsyms, remaining). + The first is the list of exported functions that are strong symbols and + have a filename and line number where they are defined. The second is + all remaining symbols that are strong, exported, and defined. + ''' + funcsym_tuples = [] + remainingsym_tuples = [] + + with open(objfile, 'rb') as fin: + elffile = ELFFile(fin) + + #symtabs = [elffile.get_section_by_name('.symtab')] + symtabs = [x for x in elffile.iter_sections() + if isinstance(x, SymbolTableSection)] + if len(symtabs) == 0: + raise RuntimeError('Object file {} does not have a symbol table' + .format(objfile)) + + # get globally exported defined symbols + syms = [sym for symtab in symtabs + for sym in symtab.iter_symbols() + if _is_symbol(sym) and + _is_extern(sym) and + _is_strong(sym) and + _is_defined(sym)] + + # split symbols into functions and non-functions + fsyms = [sym for sym in syms if _is_func(sym)] # functions + rsyms = list(set(syms).difference(fsyms)) # remaining + + # TODO: find filename and line numbers for each relevant func symbol + locs = _locate_symbols(elffile, fsyms) + + # TODO: demangle all symbols + p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) + out, _ = p.communicate('\n'.join([sym.name for sym in fsyms])) + fdemangled = out.decode('utf8').splitlines() + + p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) + out, _ = p.communicate('\n'.join([sym.name for sym in rsyms])) + rdemangled = out.decode('utf8').splitlines() + + from pprint import pprint + print('demangled = ', end='') + pprint(demangled) + + assert len(demangled) == len(fsyms) + funcsym_tuples = [SymbolTuple(srcfile, fsyms[i].name, fdemangled[i], + locs[i][0], locs[i][1]) + for i in range(len(fsyms))] + remaining_tuples = [SymbolTuples(srcfile, rsyms[i].name, rdemangled[i], + None, None) + for i in range(len(rsyms))] + + return funcsym_tuples, remaining_tuples + +# # use nm and objdump to get the binary information we need +# symbol_strings = subp.check_output([ +# 'nm', +# '--extern-only', +# '--defined-only', +# '--line-numbers', +# objfile, +# ]).decode('utf-8').splitlines() +# demangled_symbol_strings = subp.check_output([ +# 'nm', +# '--extern-only', +# '--defined-only', +# '--demangle', +# objfile, +# ]).decode('utf-8').splitlines() +# +# print('extract_symbols({})'.format(fname)) +# if fname == 'tests/A.cpp': +# from pprint import pprint +# print('A.cpp: symbol strings:') +# pprint(symbol_strings) +# print('A.cpp: demangled symbol strings:') +# pprint(demangled_symbol_strings) +# +# # generate the symbol tuples +# for symbol_string, demangled_string in zip(symbol_strings, +# demangled_symbol_strings): +# symbol_type, symbol = symbol_string.split(maxsplit=2)[1:] +# demangled = demangled_string.split(maxsplit=2)[2] +# +# if symbol_type == 'W': # skip weak symbols +# continue +# +# if '\t' in symbol: # if filename and linenumber are specified +# symbol, definition = symbol.split('\t', maxsplit=1) +# deffile, defline = definition.split(':') +# defline = int(defline) +# symtuple = SymbolTuple(fname, symbol, demangled, deffile, defline)) +# if symbol_type == 'T': +# funcsym_tuples.append(symtuple) +# else: +# remainingsym_tuples.append(symtuple) +# else: +# remainingsym_tuples.append( +# SymbolTuple(fname, symbol, demangled, None, None)) +# +# _extract_symbols_memos[objfile] = (funcsym_tuples, remainingsym_tuples) +# return funcsym_tuples, remainingsym_tuples + +def _symbols(symtab): + 'Returns all symbols from the given symbol table' + return [sym for sym in symtab.iter_symbols() if _is_symbol(sym)] + +def _is_symbol(sym): + 'Returns True if elf.sections.Symbol object is a symbol' + return sym.name != '' and sym['st_info']['type'] != 'STT_FILE' + +def _is_extern(sym): + 'Returns True if elf.sections.Symbol is an extern symbol' + return sym['st_info']['bind'] != 'STB_LOCAL' + +def _is_weak(sym): + 'Returns True if elf.sections.Symbol is a weak symbol' + return sym['st_info']['bind'] == 'STB_WEAK' + +def _is_strong(sym): + 'Returns True if elf.sections.Symbol is a strong symbol' + return sym['st_info']['bind'] == 'STB_GLOBAL' + +def _is_defined(sym): + 'Returns True if elf.sections.Symbol is defined' + return sym['st_shndx'] != 'SHN_UNDEF' + +def _is_func(sym): + 'Returns True if elf.sections.Symbol is a function' + return sym['st_info']['type'] == 'STT_FUNC' + +def _locate_symbols(elffile, symbols): + ''' + Locates the filename and line number of each symbol in the elf file. + + @param elffile: (elf.elffile.ELFFile) The top-level elf file + @param symbols: (list(elf.sections.Symbol)) symbols to locate + + @return list(tuple(filename, lineno)) in the order of the given symbols + + If the file does not have DWARF info or a symbol is not found, an exception + is raised + ''' + if not elffile.has_dwarf_info(): + raise RuntimeError('Elf file has no DWARF info') + + dwarf = elffile.get_dwarf_info() + mangled_names = [x.name for x in symbols] + + dies = [x for cu in dwarf.iter_CUs() for x in cu.iter_DIEs()] + die_map= { + x.attributes['DW_AT_linkage_name'].value.decode('utf8'): x + for x in dies + if 'DW_AT_linkage_name' in x.attributes + and x.attributes['DW_AT_linkage_name'].value.decode('utf8') + in mangled_names + } + + from pprint import pprint + print('die_map = ', end='') + pprint(die_map) + print('mangled_names = ', end='') + pprint(mangled_names) + assert len(die_map) == len(mangled_names) + + locations = [] + for name in mangled_names: + location = [None, None] + die = die_map[name] + if 'DW_AT_decl_line' in die.attributes: + location[1] = die.attributes['DW_AT_decl_line'] + if 'DW_AT_decl_file' in die.attributes: + fno = die.attributes['DW_AT_decl_file'] + # TODO: find the filename in the line number information table + locations.append(location) + + return locations + #function_name = + From 7e7dc1772f8791f49849a542c4cfaef259af4fac Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 08:53:38 -0700 Subject: [PATCH 137/196] Install flitelf.py --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index b4e71358..17bb81f7 100644 --- a/Makefile +++ b/Makefile @@ -109,6 +109,7 @@ install: $(TARGET) install -m 0755 $(SCRIPT_DIR)/flit.py $(PREFIX)/share/flit/scripts/ install -m 0755 $(SCRIPT_DIR)/flit_*.py $(PREFIX)/share/flit/scripts/ install -m 0644 $(SCRIPT_DIR)/flitutil.py $(PREFIX)/share/flit/scripts/ + install -m 0644 $(SCRIPT_DIR)/flitelf.py $(PREFIX)/share/flit/scripts/ install -m 0644 $(SCRIPT_DIR)/README.md $(PREFIX)/share/flit/scripts/ install -m 0644 $(DOC_DIR)/*.md $(PREFIX)/share/flit/doc/ install -m 0644 $(DATA_DIR)/Makefile.in $(PREFIX)/share/flit/data/ From e8d7077cf1cfe6258753fff429dc584d43afa4b4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 09:09:31 -0700 Subject: [PATCH 138/196] flitelf: fix errors and get returned even if die not found --- scripts/flitcli/flitelf.py | 41 +++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py index e9a66acb..d2518157 100644 --- a/scripts/flitcli/flitelf.py +++ b/scripts/flitcli/flitelf.py @@ -2,6 +2,7 @@ # https://github.com/eliben/pyelftools.git from collections import namedtuple +import subprocess as subp import sys from elftools.common.py3compat import bytes2str @@ -62,22 +63,22 @@ def extract_symbols(objfile, srcfile): # TODO: demangle all symbols p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) - out, _ = p.communicate('\n'.join([sym.name for sym in fsyms])) + out, _ = p.communicate('\n'.join([sym.name for sym in fsyms]).encode()) fdemangled = out.decode('utf8').splitlines() p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) - out, _ = p.communicate('\n'.join([sym.name for sym in rsyms])) + out, _ = p.communicate('\n'.join([sym.name for sym in rsyms]).encode()) rdemangled = out.decode('utf8').splitlines() from pprint import pprint - print('demangled = ', end='') - pprint(demangled) + print('fdemangled = ', end='') + pprint(fdemangled) - assert len(demangled) == len(fsyms) + assert len(fdemangled) == len(fsyms) funcsym_tuples = [SymbolTuple(srcfile, fsyms[i].name, fdemangled[i], locs[i][0], locs[i][1]) for i in range(len(fsyms))] - remaining_tuples = [SymbolTuples(srcfile, rsyms[i].name, rdemangled[i], + remaining_tuples = [SymbolTuple(srcfile, rsyms[i].name, rdemangled[i], None, None) for i in range(len(rsyms))] @@ -187,22 +188,26 @@ def _locate_symbols(elffile, symbols): in mangled_names } - from pprint import pprint - print('die_map = ', end='') - pprint(die_map) - print('mangled_names = ', end='') - pprint(mangled_names) - assert len(die_map) == len(mangled_names) + #from pprint import pprint + #print('die_map = ', end='') + #pprint(die_map) + #print('mangled_names = ', end='') + #pprint(mangled_names) + #assert len(die_map) == len(mangled_names) locations = [] for name in mangled_names: location = [None, None] - die = die_map[name] - if 'DW_AT_decl_line' in die.attributes: - location[1] = die.attributes['DW_AT_decl_line'] - if 'DW_AT_decl_file' in die.attributes: - fno = die.attributes['DW_AT_decl_file'] - # TODO: find the filename in the line number information table + try: + die = die_map[name] + except KeyError: + pass + else: + if 'DW_AT_decl_line' in die.attributes: + location[1] = die.attributes['DW_AT_decl_line'].value + if 'DW_AT_decl_file' in die.attributes: + fno = die.attributes['DW_AT_decl_file'].value + # TODO: find the filename in the line number information table locations.append(location) return locations From c9a4fb00aecd1ea0d15771303035c831df317f2e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 12:17:58 -0700 Subject: [PATCH 139/196] flitelf: Finish implementing filename and lineno --- scripts/flitcli/flitelf.py | 78 +++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py index d2518157..c8f97c7a 100644 --- a/scripts/flitcli/flitelf.py +++ b/scripts/flitcli/flitelf.py @@ -4,6 +4,7 @@ from collections import namedtuple import subprocess as subp import sys +import os from elftools.common.py3compat import bytes2str from elftools.dwarf.descriptions import describe_form_class @@ -176,40 +177,55 @@ def _locate_symbols(elffile, symbols): if not elffile.has_dwarf_info(): raise RuntimeError('Elf file has no DWARF info') - dwarf = elffile.get_dwarf_info() - mangled_names = [x.name for x in symbols] - - dies = [x for cu in dwarf.iter_CUs() for x in cu.iter_DIEs()] - die_map= { - x.attributes['DW_AT_linkage_name'].value.decode('utf8'): x - for x in dies - if 'DW_AT_linkage_name' in x.attributes - and x.attributes['DW_AT_linkage_name'].value.decode('utf8') - in mangled_names - } - - #from pprint import pprint - #print('die_map = ', end='') - #pprint(die_map) - #print('mangled_names = ', end='') - #pprint(mangled_names) - #assert len(die_map) == len(mangled_names) + dwarfinfo = elffile.get_dwarf_info() + fltable = _gen_file_line_table(dwarfinfo) locations = [] - for name in mangled_names: - location = [None, None] - try: - die = die_map[name] - except KeyError: - pass + for sym in symbols: + for fname, lineno, start, end in fltable: + if start <= sym.entry['st_value'] < end: + locations.append((fname.decode('utf8'), lineno)) + break else: - if 'DW_AT_decl_line' in die.attributes: - location[1] = die.attributes['DW_AT_decl_line'].value - if 'DW_AT_decl_file' in die.attributes: - fno = die.attributes['DW_AT_decl_file'].value - # TODO: find the filename in the line number information table - locations.append(location) + locations.append((None, None)) return locations - #function_name = +def _gen_file_line_table(dwarfinfo): + ''' + Generates and returns a list of (filename, lineno, startaddr, endaddr). + ''' + # generate the table + table = [] + for cu in dwarfinfo.iter_CUs(): + lineprog = dwarfinfo.line_program_for_CU(cu) + prevstate = None + for entry in lineprog.get_entries(): + # We're interested in those entries where a new state is assigned + if entry.state is None or entry.state.end_sequence: + continue + # Looking for a range of addresses in two consecutive states that + # contain a required address. + if prevstate is not None: + print(lineprog) + filename = lineprog['file_entry'][prevstate.file - 1].name + dirno = lineprog['file_entry'][prevstate.file - 1].dir_index + filepath = os.path.join(lineprog['include_directory'][dirno - 1], filename) + line = prevstate.line + fromaddr = prevstate.address + toaddr = max(fromaddr, entry.state.address) + table.append((filepath, line, fromaddr, toaddr)) + prevstate = entry.state + + # consolidate the table + consolidated = [] + prev = table[0] + for entry in table[1:]: + if prev[1] == entry[1] and prev[3] == entry[2]: + prev = (prev[0], prev[1], prev[2], entry[3]) + else: + consolidated.append(prev) + prev = entry + consolidated.append(prev) + + return consolidated From 5d12420496ee58969b9075974897cc50a6b57065 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 12:24:29 -0700 Subject: [PATCH 140/196] bisect: update tests from flitelf implementation --- tests/flit_cli/flit_bisect/tst_bisect.py | 16 ++++++++-------- tests/flit_cli/flit_bisect/tst_bisect_biggest.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index 3c19b99c..286b0f9d 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -208,14 +208,14 @@ Test the All differing symbols section of the output >>> idx = bisect_out.index('All variability inducing symbols:') >>> print('\\n'.join(bisect_out[idx+1:])) # doctest:+ELLIPSIS - /.../tests/file4.cpp:106 ... -- file4_all() (score 30.0) - /.../tests/file2.cpp:90 ... -- file2_func1_PROBLEM() (score 7.0) - /.../tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) - /.../tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) - /.../tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) - /.../tests/A.cpp:95 ... -- A::fileA_method1_PROBLEM() (score 2.0) - /.../tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) - /.../tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) + tests/file4.cpp:106 ... -- file4_all() (score 30.0) + tests/file2.cpp:90 ... -- file2_func1_PROBLEM() (score 7.0) + tests/file1.cpp:92 ... -- file1_func2_PROBLEM() (score 5.0) + tests/file1.cpp:108 ... -- file1_func4_PROBLEM() (score 3.0) + tests/file3.cpp:103 ... -- file3_func5_PROBLEM() (score 3.0) + tests/A.cpp:95 ... -- A::fileA_method1_PROBLEM() (score 2.0) + tests/file1.cpp:100 ... -- file1_func3_PROBLEM() (score 2.0) + tests/file3.cpp:92 ... -- file3_func2_PROBLEM() (score 1.0) TODO: test the log_contents variable ''' diff --git a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py index b2228f36..07d630fe 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect_biggest.py +++ b/tests/flit_cli/flit_bisect/tst_bisect_biggest.py @@ -101,7 +101,7 @@ >>> flit_bisect = th._path_import(th._script_dir, 'flit_bisect') >>> util = th._path_import(th._script_dir, 'flitutil') ->>> Sym = flit_bisect.SymbolTuple +>>> Sym = flit_bisect.elf.SymbolTuple >>> def create_symbol(fileno, funcno, lineno, isproblem): ... prob_str = '_PROBLEM' if isproblem else '' ... filename = 'tests/file{}.cpp'.format(fileno) From 1865fc5874e410eb1cccfce6681194005917d7f4 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 13:02:27 -0700 Subject: [PATCH 141/196] travis-ci: Add pyelftools to before_install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b611170d..48c27965 100644 --- a/.travis.yml +++ b/.travis.yml @@ -113,7 +113,7 @@ matrix: packages: - *native_deps -before_install: pip3 install --user toml +before_install: pip3 install --user toml pyelftools script: make -j 4 && make check From baa075a904300fc98ffbbf1f484d16f16852aa5d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 13:09:58 -0700 Subject: [PATCH 142/196] travis-ci: try to conditionally test pyelftools --- .travis.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 48c27965..5bb26a56 100644 --- a/.travis.yml +++ b/.travis.yml @@ -91,7 +91,9 @@ addons: matrix: include: # Job 1: OpenMPI - - env: mpi_type=openmpi + - env: + - mpi_type=openmpi + - extra_pip=pyelftools addons: apt: packages: @@ -107,13 +109,15 @@ matrix: # - libmpich-dev # - mpich # Job 3: No MPI - - env: mpi_type=none + - env: + - mpi_type=none + - extra_pip= addons: apt: packages: - *native_deps -before_install: pip3 install --user toml pyelftools +before_install: pip3 install --user toml $extra_pip script: make -j 4 && make check From 001f41bc3dd02745b44f4b5271eaa97eaba46ba9 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 13:43:49 -0700 Subject: [PATCH 143/196] bisect: give error if pyelftools is not present and disable bisect tests --- scripts/flitcli/flit_bisect.py | 10 +++++- scripts/flitcli/flitelf.py | 55 ++--------------------------- tests/flit_cli/flit_bisect/Makefile | 10 ++++++ 3 files changed, 21 insertions(+), 54 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 6153dfde..bc14469e 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -84,6 +84,14 @@ Implements the bisect subcommand, identifying the problematic subset of source files that cause the variability. ''' +import sys + +try: + import flitelf as elf +except ModuleNotFoundError: + print('Error: pyelftools is not installed, bisect disabled', + file=sys.stderr) + sys.exit(1) from collections import namedtuple from tempfile import NamedTemporaryFile @@ -99,12 +107,12 @@ import shutil import sqlite3 import subprocess as subp -import sys import flitconfig as conf import flitutil as util import flitelf as elf + brief_description = 'Bisect compilation to identify problematic source code' def hash_compilation(compiler, optl, switches): diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py index c8f97c7a..224fe4a4 100644 --- a/scripts/flitcli/flitelf.py +++ b/scripts/flitcli/flitelf.py @@ -6,8 +6,6 @@ import sys import os -from elftools.common.py3compat import bytes2str -from elftools.dwarf.descriptions import describe_form_class from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection @@ -59,10 +57,10 @@ def extract_symbols(objfile, srcfile): fsyms = [sym for sym in syms if _is_func(sym)] # functions rsyms = list(set(syms).difference(fsyms)) # remaining - # TODO: find filename and line numbers for each relevant func symbol + # find filename and line numbers for each relevant func symbol locs = _locate_symbols(elffile, fsyms) - # TODO: demangle all symbols + # demangle all symbols p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) out, _ = p.communicate('\n'.join([sym.name for sym in fsyms]).encode()) fdemangled = out.decode('utf8').splitlines() @@ -85,55 +83,6 @@ def extract_symbols(objfile, srcfile): return funcsym_tuples, remaining_tuples -# # use nm and objdump to get the binary information we need -# symbol_strings = subp.check_output([ -# 'nm', -# '--extern-only', -# '--defined-only', -# '--line-numbers', -# objfile, -# ]).decode('utf-8').splitlines() -# demangled_symbol_strings = subp.check_output([ -# 'nm', -# '--extern-only', -# '--defined-only', -# '--demangle', -# objfile, -# ]).decode('utf-8').splitlines() -# -# print('extract_symbols({})'.format(fname)) -# if fname == 'tests/A.cpp': -# from pprint import pprint -# print('A.cpp: symbol strings:') -# pprint(symbol_strings) -# print('A.cpp: demangled symbol strings:') -# pprint(demangled_symbol_strings) -# -# # generate the symbol tuples -# for symbol_string, demangled_string in zip(symbol_strings, -# demangled_symbol_strings): -# symbol_type, symbol = symbol_string.split(maxsplit=2)[1:] -# demangled = demangled_string.split(maxsplit=2)[2] -# -# if symbol_type == 'W': # skip weak symbols -# continue -# -# if '\t' in symbol: # if filename and linenumber are specified -# symbol, definition = symbol.split('\t', maxsplit=1) -# deffile, defline = definition.split(':') -# defline = int(defline) -# symtuple = SymbolTuple(fname, symbol, demangled, deffile, defline)) -# if symbol_type == 'T': -# funcsym_tuples.append(symtuple) -# else: -# remainingsym_tuples.append(symtuple) -# else: -# remainingsym_tuples.append( -# SymbolTuple(fname, symbol, demangled, None, None)) -# -# _extract_symbols_memos[objfile] = (funcsym_tuples, remainingsym_tuples) -# return funcsym_tuples, remainingsym_tuples - def _symbols(symtab): 'Returns all symbols from the given symbol table' return [sym for sym in symtab.iter_symbols() if _is_symbol(sym)] diff --git a/tests/flit_cli/flit_bisect/Makefile b/tests/flit_cli/flit_bisect/Makefile index ce0c8e04..b7fb7853 100644 --- a/tests/flit_cli/flit_bisect/Makefile +++ b/tests/flit_cli/flit_bisect/Makefile @@ -2,10 +2,20 @@ RUNNER := python3 SRC := $(wildcard tst_*.py) RUN_TARGETS := $(SRC:%.py=run_%) +IS_PYELF := $(shell if python3 -c 'import elftools' 2>/dev/null; then \ + echo true; \ + fi) + include ../../color_out.mk .PHONY: check help clean build run_% +ifeq ($(IS_PYELF),true) check: $(TARGETS) $(RUN_TARGETS) +else +check: + $(call color_out,RED,Warning: pyelftools is not found on your system;\ + skipping bisect tests) +endif help: @echo "Makefile for running tests on FLiT framework" From 5873bfd8d4dd5d35f920538cda8d0c81ce14db69 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 13:54:56 -0700 Subject: [PATCH 144/196] Update documentation for pyelftools --- documentation/flit-command-line.md | 5 +++++ documentation/installation.md | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/documentation/flit-command-line.md b/documentation/flit-command-line.md index 5c7cae5e..d0f51713 100644 --- a/documentation/flit-command-line.md +++ b/documentation/flit-command-line.md @@ -136,6 +136,11 @@ flit import --dbfile temporary.sqlite backup/results/*.csv ## flit bisect +There is an additional optional dependency in order to run `flit bisect`. That +is [pyelftools](https://github.com/eliben/pyelftools) as discussed in [FLiT +Installation](installation.md). If `pyelftools` is not installed, then +`bisect` is disabled. + When FLiT runs identify compilations that cause some tests to exhibit variability, one may want to investigate further and understand where the compiler introduced overly aggressive optimizations. diff --git a/documentation/installation.md b/documentation/installation.md index 1bcdd8b4..6cb3ab23 100644 --- a/documentation/installation.md +++ b/documentation/installation.md @@ -26,8 +26,11 @@ Stuff you may need to get * [git](https://git-scm.com) * [python3](https://www.python.org) - * The [toml](https://github.com/uiri/toml) module (for + * [toml](https://github.com/uiri/toml) module (for [TOML](https://github.com/toml-lang/toml) configuration files) + * (optional) [pyelftools](https://github.com/eliben/pyelftools) module for + parsing ELF files. This is used for `flit bisect`; all other functionality + will work without it. * [make](https://www.gnu.org/software/make) * [gcc](https://gcc.gnu.org) version 4.9 or higher * [sqlite3](https://sqlite.org) version 3.0 or higher. @@ -38,14 +41,27 @@ For Debian-based systems: ```bash sudo apt install \ bash binutils build-essential coreutils git hostname \ - python3 python3-toml + python3 python3-toml python3-pyelftools +``` + +The python modules can also be installed with `apt` + +```bash +sudo apt install python3-toml python3-pyelftools +``` + +or with `pip` + +```bash +sudo apt install python3-pip +pip3 install --user toml pyelftools ``` For homebrew on OSX (besides installing [Xcode](https://developer.apple.com/xcode)) ```bash brew install make python3 gcc git -pip3 install toml +pip3 install toml pyelftools ``` If you install python version 3.0 or later, then you will need to have a From c52d60ac9f2993e2be9207c9ae8d211646cac3c8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 14:08:49 -0700 Subject: [PATCH 145/196] bisect: disable without pyelftools using main() --- scripts/flitcli/flit_bisect.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index bc14469e..ce31a07c 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -84,14 +84,6 @@ Implements the bisect subcommand, identifying the problematic subset of source files that cause the variability. ''' -import sys - -try: - import flitelf as elf -except ModuleNotFoundError: - print('Error: pyelftools is not installed, bisect disabled', - file=sys.stderr) - sys.exit(1) from collections import namedtuple from tempfile import NamedTemporaryFile @@ -107,10 +99,14 @@ import shutil import sqlite3 import subprocess as subp +import sys import flitconfig as conf import flitutil as util -import flitelf as elf +try: + import flitelf as elf +except ModuleNotFoundError: + elf = None brief_description = 'Bisect compilation to identify problematic source code' @@ -1980,6 +1976,11 @@ def main(arguments, prog=sys.argv[0]): stuff and runs the run_bisect multiple times if so. ''' + if elf is None: + print('Error: pyelftools is not installed, bisect disabled', + file=sys.stderr) + return 1 + if '-a' in arguments or '--auto-sqlite-run' in arguments: return parallel_auto_bisect(arguments, prog) From 841ad1f54927b4bc936a784a6f42c3053f034527 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 14:29:01 -0700 Subject: [PATCH 146/196] bisect: ModuleNotFoundError -> ImportError Apparrently the ModuleNotFoundError was introduced as a subclass of ImportError in python 3.6. To support older versions of python 3, we need to catch ImportError instead --- scripts/flitcli/flit_bisect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index ce31a07c..480b68da 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -105,7 +105,7 @@ import flitutil as util try: import flitelf as elf -except ModuleNotFoundError: +except ImportError: elf = None From c4fdac15594114bb90f474a0d19b353108cfd8a0 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 14:37:30 -0700 Subject: [PATCH 147/196] Update Installation.md: small grammar correction --- documentation/installation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/installation.md b/documentation/installation.md index 6cb3ab23..b7654e65 100644 --- a/documentation/installation.md +++ b/documentation/installation.md @@ -41,10 +41,10 @@ For Debian-based systems: ```bash sudo apt install \ bash binutils build-essential coreutils git hostname \ - python3 python3-toml python3-pyelftools + python3 ``` -The python modules can also be installed with `apt` +The python modules can be installed with `apt` ```bash sudo apt install python3-toml python3-pyelftools From ba231f4002eaf95ef3358199652e1f599399e259 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 14:53:28 -0700 Subject: [PATCH 148/196] flitelf: fix pylint findings --- scripts/flitcli/flitelf.py | 133 +++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 27 deletions(-) diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py index 224fe4a4..afa4d370 100644 --- a/scripts/flitcli/flitelf.py +++ b/scripts/flitcli/flitelf.py @@ -1,9 +1,95 @@ # Much of this is copied from the examples given in # https://github.com/eliben/pyelftools.git +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Utility functions for dealing with ELF binary files. This file requires the +pyelftools package to be installed (i.e. module elftools). +''' + from collections import namedtuple import subprocess as subp -import sys import os from elftools.elf.elffile import ELFFile @@ -32,13 +118,9 @@ def extract_symbols(objfile, srcfile): have a filename and line number where they are defined. The second is all remaining symbols that are strong, exported, and defined. ''' - funcsym_tuples = [] - remainingsym_tuples = [] - with open(objfile, 'rb') as fin: elffile = ELFFile(fin) - #symtabs = [elffile.get_section_by_name('.symtab')] symtabs = [x for x in elffile.iter_sections() if isinstance(x, SymbolTableSection)] if len(symtabs) == 0: @@ -47,11 +129,11 @@ def extract_symbols(objfile, srcfile): # get globally exported defined symbols syms = [sym for symtab in symtabs - for sym in symtab.iter_symbols() - if _is_symbol(sym) and - _is_extern(sym) and - _is_strong(sym) and - _is_defined(sym)] + for sym in symtab.iter_symbols() + if _is_symbol(sym) + and _is_extern(sym) + and _is_strong(sym) + and _is_defined(sym)] # split symbols into functions and non-functions fsyms = [sym for sym in syms if _is_func(sym)] # functions @@ -61,27 +143,17 @@ def extract_symbols(objfile, srcfile): locs = _locate_symbols(elffile, fsyms) # demangle all symbols - p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) - out, _ = p.communicate('\n'.join([sym.name for sym in fsyms]).encode()) - fdemangled = out.decode('utf8').splitlines() - - p = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) - out, _ = p.communicate('\n'.join([sym.name for sym in rsyms]).encode()) - rdemangled = out.decode('utf8').splitlines() + fdemangled = _demangle([sym.name for sym in fsyms]) + rdemangled = _demangle([sym.name for sym in rsyms]) - from pprint import pprint - print('fdemangled = ', end='') - pprint(fdemangled) - - assert len(fdemangled) == len(fsyms) funcsym_tuples = [SymbolTuple(srcfile, fsyms[i].name, fdemangled[i], locs[i][0], locs[i][1]) for i in range(len(fsyms))] remaining_tuples = [SymbolTuple(srcfile, rsyms[i].name, rdemangled[i], - None, None) + None, None) for i in range(len(rsyms))] - return funcsym_tuples, remaining_tuples + return funcsym_tuples, remaining_tuples def _symbols(symtab): 'Returns all symbols from the given symbol table' @@ -111,6 +183,14 @@ def _is_func(sym): 'Returns True if elf.sections.Symbol is a function' return sym['st_info']['type'] == 'STT_FUNC' +def _demangle(symbol_list): + 'Demangles each C++ name in the given list' + proc = subp.Popen(['c++filt'], stdin=subp.PIPE, stdout=subp.PIPE) + out, _ = proc.communicate('\n'.join(symbol_list).encode()) + demangled = out.decode('utf8').splitlines() + assert len(demangled) == len(symbol_list) + return demangled + def _locate_symbols(elffile, symbols): ''' Locates the filename and line number of each symbol in the elf file. @@ -146,8 +226,8 @@ def _gen_file_line_table(dwarfinfo): ''' # generate the table table = [] - for cu in dwarfinfo.iter_CUs(): - lineprog = dwarfinfo.line_program_for_CU(cu) + for unit in dwarfinfo.iter_CUs(): + lineprog = dwarfinfo.line_program_for_CU(unit) prevstate = None for entry in lineprog.get_entries(): # We're interested in those entries where a new state is assigned @@ -156,7 +236,6 @@ def _gen_file_line_table(dwarfinfo): # Looking for a range of addresses in two consecutive states that # contain a required address. if prevstate is not None: - print(lineprog) filename = lineprog['file_entry'][prevstate.file - 1].name dirno = lineprog['file_entry'][prevstate.file - 1].dir_index filepath = os.path.join(lineprog['include_directory'][dirno - 1], filename) From 023150ea5153ae46773db24dc654fa3671abdcd8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 15:16:58 -0700 Subject: [PATCH 149/196] flit-cli: fix pylint findings --- pylint.rc | 3 +- scripts/flitcli/flit.py | 65 ++++++++++++++++------------------ scripts/flitcli/flit_bisect.py | 11 ------ scripts/flitcli/flit_import.py | 35 +++++++++--------- scripts/flitcli/flit_init.py | 2 +- scripts/flitcli/flit_make.py | 35 +++++++++--------- scripts/flitcli/flit_update.py | 19 +++++----- scripts/flitcli/flitconfig.py | 3 +- 8 files changed, 81 insertions(+), 92 deletions(-) diff --git a/pylint.rc b/pylint.rc index 8e47ce6f..5c6e95f6 100644 --- a/pylint.rc +++ b/pylint.rc @@ -368,7 +368,8 @@ class-naming-style=PascalCase #class-rgx= # Naming style matching correct constant names -const-naming-style=UPPER_CASE +#const-naming-style=UPPER_CASE +const-naming-style=any # Regular expression matching correct constant names. Overrides const-naming- # style diff --git a/scripts/flitcli/flit.py b/scripts/flitcli/flit.py index 015bf604..f5ae92bb 100755 --- a/scripts/flitcli/flit.py +++ b/scripts/flitcli/flit.py @@ -129,28 +129,28 @@ def generate_help_documentation(subcom_map): >>> help_str, help_subcom_str = generate_help_documentation(dict()) ''' parser = argparse.ArgumentParser( - description=''' - The flit command-line tool allows for users to write - portability test cases. One can test primarily for - compiler effects on reproducibility of floating-point - algorithms. That at least is the main use case for this - tool, although you may come up with some other uses. - ''', - ) + description=''' + The flit command-line tool allows for users to write + portability test cases. One can test primarily for + compiler effects on reproducibility of floating-point + algorithms. That at least is the main use case for this + tool, although you may come up with some other uses. + ''', + ) parser.add_argument('-v', '--version', action='store_true', help='Print version and exit') subparsers = parser.add_subparsers(metavar='subcommand', dest='subcommand') help_subparser = subparsers.add_parser( - 'help', help='display help for a specific subcommand') + 'help', help='display help for a specific subcommand') help_subparser.add_argument( - metavar='subcommand', - dest='help_subcommand', - choices=subcom_map.keys(), - help=''' - display the help documentation for a specific subcommand. - choices are {0}. - '''.format(', '.join(sorted(subcom_map.keys()))), - ) + metavar='subcommand', + dest='help_subcommand', + choices=subcom_map.keys(), + help=''' + display the help documentation for a specific subcommand. + choices are {0}. + '''.format(', '.join(sorted(subcom_map.keys()))), + ) for name, module in sorted(subcom_map.items()): subparsers.add_parser(name, help=module.brief_description) @@ -170,13 +170,12 @@ def main(arguments, outstream=None): ''' if outstream is None: return _main_impl(arguments) - else: - try: - oldout = sys.stdout - sys.stdout = outstream - return _main_impl(arguments) - finally: - sys.stdout = oldout + try: + oldout = sys.stdout + sys.stdout = outstream + return _main_impl(arguments) + finally: + sys.stdout = oldout def _main_impl(arguments): 'Implementation of main' @@ -214,21 +213,19 @@ def _main_impl(arguments): print(help_subcommand_str) return 0 - elif help_subcommand not in all_subcommands: + if help_subcommand not in all_subcommands: sys.stderr.write('Error: invalid subcommand: {0}.\n' \ .format(subcommand)) sys.stderr.write('Call with --help for more information\n') return 1 - else: - # just forward to the documentation from the submodule - return subcom_map[help_subcommand].main( - ['--help'], prog='{0} {1}'.format(sys.argv[0], help_subcommand)) - else: - # it is one of the other subcommands. Just forward the request on - return subcom_map[subcommand].main( - arguments, prog='{0} {1}'.format(sys.argv[0], subcommand)) + # just forward to the documentation from the submodule + return subcom_map[help_subcommand].main( + ['--help'], prog='{0} {1}'.format(sys.argv[0], help_subcommand)) + + # it is one of the other subcommands. Just forward the request on + return subcom_map[subcommand].main( + arguments, prog='{0} {1}'.format(sys.argv[0], subcommand)) if __name__ == '__main__': sys.exit(main(sys.argv[1:])) - diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 480b68da..17f1292a 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -85,7 +85,6 @@ files that cause the variability. ''' -from collections import namedtuple from tempfile import NamedTemporaryFile import argparse import csv @@ -1253,16 +1252,6 @@ def search_for_source_problems(args, bisect_path, replacements, sources): memoized_checker = _gen_bisect_source_checker(args, bisect_path, replacements, sources) - # TODO: make a callback that immediately starts the symbol search on the - # TODO- first found file. Do this for when args.biggest is defined. - # TODO- What we want here is that the first file found triggers a symbol - # TODO- search. Then the top k symbols are found from that file. We move - # TODO- to the next file. If that file has a greater variance than the kth - # TODO- symbol found from the previous set of files, then we're done, else - # TODO- run symbol bisect on it to get the top k symbols as well (we can - # TODO- stop as soon as a symbol is less than the kth symbol (after - # TODO- updating the list of k). - print('Searching for differing source files:') logging.info('Searching for differing source files under the trouble' ' compilation') diff --git a/scripts/flitcli/flit_import.py b/scripts/flitcli/flit_import.py index 0a1a6d99..510b3acc 100644 --- a/scripts/flitcli/flit_import.py +++ b/scripts/flitcli/flit_import.py @@ -82,15 +82,14 @@ 'Implements the import subcommand, importing results into a database' -import flitutil as util - import argparse import csv import datetime import os -import sqlite3 import sys +import flitutil as util + brief_description = 'Import flit results into the configured database' def _file_check(filename): @@ -115,23 +114,24 @@ def get_dbfile_from_toml(tomlfile): return projconf['database']['filepath'] def main(arguments, prog=sys.argv[0]): + 'Main logic here' parser = argparse.ArgumentParser( - prog=prog, - description=''' - Import flit results into the configured database. The - configured database is found from the settings in - flit-config.toml. You can import either exported results or - results from manually running the tests. Note that importing - the same thing twice will result in having two copies of it - in the database. - ''', - ) + prog=prog, + description=''' + Import flit results into the configured database. The configured + database is found from the settings in flit-config.toml. You can + import either exported results or results from manually running the + tests. Note that importing the same thing twice will result in + having two copies of it in the database. + ''', + ) parser.add_argument('importfile', nargs='+', type=_file_check, help=''' File(s) to import into the database. These files may be csv files or sqlite3 databases. ''') - parser.add_argument('-a', '--append', type=int, default=None, metavar='RUN_ID', + parser.add_argument('-a', '--append', type=int, default=None, + metavar='RUN_ID', help=''' Append the import to the specified run id. The default behavior is to add a new run to include the @@ -182,9 +182,10 @@ def main(arguments, prog=sys.argv[0]): if args.append is None: # Create a new run to use in import db.execute('insert into runs(rdate,label) values (?,?)', - (datetime.datetime.now(), args.label)) + (datetime.datetime.now(), args.label)) db.commit() - args.append = db.execute('select id from runs order by id').fetchall()[-1]['id'] + args.append = \ + db.execute('select id from runs order by id').fetchall()[-1]['id'] # Make sure the run id exists. run_ids = [x['id'] for x in db.execute('select id from runs')] @@ -251,5 +252,7 @@ def main(arguments, prog=sys.argv[0]): ''', to_insert) db.commit() + return 0 + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/scripts/flitcli/flit_init.py b/scripts/flitcli/flit_init.py index 08f30d61..0e5071f1 100644 --- a/scripts/flitcli/flit_init.py +++ b/scripts/flitcli/flit_init.py @@ -85,7 +85,6 @@ import argparse import os import shutil -import socket import sys import flitconfig as conf @@ -95,6 +94,7 @@ brief_description = 'Initializes a flit test directory for use' def main(arguments, prog=sys.argv[0]): + 'Main logic here' parser = argparse.ArgumentParser( prog=prog, description=''' diff --git a/scripts/flitcli/flit_make.py b/scripts/flitcli/flit_make.py index 90deb059..83e56a17 100644 --- a/scripts/flitcli/flit_make.py +++ b/scripts/flitcli/flit_make.py @@ -93,13 +93,14 @@ brief_description = 'Runs the make and adds to the database' def main(arguments, prog=sys.argv[0]): + 'Main logic here' parser = argparse.ArgumentParser( - prog=prog, - description=''' - This command runs the full set of tests and adds the results - to the configured database. - ''', - ) + prog=prog, + description=''' + This command runs the full set of tests and adds the results + to the configured database. + ''', + ) processors = multiprocessing.cpu_count() parser.add_argument('-j', '--jobs', type=int, default=processors, help=''' @@ -142,20 +143,16 @@ def main(arguments, prog=sys.argv[0]): # TODO: can we make a progress bar here? print('Calling GNU Make for the runbuild') subprocess.check_call([ - 'make', - 'runbuild', - '-j{0}'.format(args.jobs), - ] + make_args, - **check_call_kwargs - ) + 'make', + 'runbuild', + '-j{0}'.format(args.jobs), + ] + make_args, **check_call_kwargs) print('Calling GNU Make to execute the tests') subprocess.check_call([ - 'make', - 'run', - '-j{0}'.format(args.exec_jobs), - ] + make_args, - **check_call_kwargs - ) + 'make', + 'run', + '-j{0}'.format(args.exec_jobs), + ] + make_args, **check_call_kwargs) print('Importing into the database') # TODO: find a way to not import over again if called multiple times status = flit_import.main(['--label', args.label] + @@ -163,5 +160,7 @@ def main(arguments, prog=sys.argv[0]): if status != 0: return status + return 0 + if __name__ == '__main__': sys.exit(main(sys.argv[1:])) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 9e612e39..d6edfb3b 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -93,16 +93,17 @@ brief_description = 'Updates the Makefile based on flit-config.toml' def main(arguments, prog=sys.argv[0]): + 'Main logic here' parser = argparse.ArgumentParser( - prog=prog, - description=''' - Updates the Makefile based on flit-config.toml. The Makefile - is autogenerated and should not be modified manually. If there - are things you want to replace or add, you can use custom.mk - which is included at the end of the Makefile. So, you may add - rules, add to variables, or override variables. - ''', - ) + prog=prog, + description=''' + Updates the Makefile based on flit-config.toml. The Makefile + is autogenerated and should not be modified manually. If there + are things you want to replace or add, you can use custom.mk + which is included at the end of the Makefile. So, you may add + rules, add to variables, or override variables. + ''', + ) parser.add_argument('-C', '--directory', default='.', help='The directory to initialize') args = parser.parse_args(arguments) diff --git a/scripts/flitcli/flitconfig.py b/scripts/flitcli/flitconfig.py index d9a66c4e..add10553 100644 --- a/scripts/flitcli/flitconfig.py +++ b/scripts/flitcli/flitconfig.py @@ -89,7 +89,7 @@ import os -all = [ +__all__ = [ 'version', 'script_dir', 'doc_dir', @@ -123,4 +123,3 @@ # directory containing litmus tests litmus_test_dir = os.path.realpath(os.path.join(script_dir, '..', '..', 'litmus-tests', 'tests')) - From d6d668145b0601fbb563ea2d9f38823246f88e91 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 21 Nov 2018 17:34:00 -0700 Subject: [PATCH 150/196] Makefile: add conditional for CLANG --- data/Makefile.in | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index cd7021ff..923b0953 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -122,7 +122,6 @@ LD_REQUIRED := RUNWRAP = $(RUN_WRAPPER) ifeq ($(ENABLE_MPI),yes) # If we are using MPI - $(info MPI is enabled) RUNWRAP += mpirun $(MPIRUN_ARGS) CC_REQUIRED += -DFLIT_USE_MPI CC_REQUIRED += $(shell mpic++ --showme:compile) @@ -165,9 +164,13 @@ GET_COMPILER = $(shell $1 --version | head -n 1 | awk '{{ print $$1 }}') # Returns 1 if the given compiler is GCC, else 0 # @param 1: executable name or path to compiler -IS_GCC = $(shell expr $(call GET_COMPILER,$(1)) = gcc \| \ +IS_GCC = $(shell expr $(call GET_COMPILER,$1) = gcc \| \ $(call GET_COMPILER,$1) = g++) +# Returns 1 if the given compiler is CLANG, else 0 +# @param 1: executable name or path to compiler +IS_CLANG = $(shell expr $(call GET_COMPILER,$1) = clang) + # Returns the version of the compiler as returned by -dumpversion # @param 1: executable name or path to compiler GET_COMPILER_VER = $(shell $1 -dumpversion) @@ -395,8 +398,12 @@ R_DEP := $(R_OBJ:%.o=%.d) .PHONY: rec rec: $(R_TARGET) -# if the current compiler is not GCC 4 or 5, then enable -no-pie -ifeq ($(call IS_GCC_4_OR_5,$($(R_CUR_COMPILER))),0) +# clang's flag is -nopie +# else if the current compiler is not GCC 4 or 5, then enable -no-pie +# GCC 4 and 5 do not need -no-pie since that is the default +ifeq ($(call IS_CLANG,$($(R_CUR_COMPILER))),1) + LD_REQUIRED += -nopie +else ifeq ($(call IS_GCC_4_OR_5,$($(R_CUR_COMPILER))),0) LD_REQUIRED += -no-pie endif @@ -420,13 +427,19 @@ $(OBJ_DIR)/%_$(R_ID).o: %.cpp Makefile custom.mk | $(OBJ_DIR) # Otherwise, we're not in a recursion. else # ifndef R_IS_RECURSED -# if the dev compiler is not an old version of GCC -ifeq ($(call IS_GCC_4_OR_5,$(DEV_CC)),0) +# clang's flag is -nopie +# else if the current compiler is not GCC 4 or 5, then enable -no-pie +# GCC 4 and 5 do not need -no-pie since that is the default +ifeq ($(call IS_CLANG,$(DEV_CC)),1) + DEV_LDFLAGS += -nopie +else ifeq ($(call IS_GCC_4_OR_5,$(DEV_CC)),0) DEV_LDFLAGS += -no-pie endif -# if the gt compiler is not an old version of GCC -ifeq ($(call IS_GCC_4_OR_5,$(GT_CC)),0) +# same for the gt compiler +ifeq ($(call IS_CLANG,$(GT_CC)),1) + GT_LDFLAGS += -nopie +else ifeq ($(call IS_GCC_4_OR_5,$(GT_CC)),0) GT_LDFLAGS += -no-pie endif @@ -441,13 +454,13 @@ $(RESULTS_DIR): # Set these as empty "simply-expanded variables". This affects the "+=" operator. # see https://ftp.gnu.org/old-gnu/Manuals/make-3.79.1/html_chapter/make_6.html -TARGET_OUTS := +TARGET_OUTS := # @param 1: compiler variable name (e.g. CLANG) # @param 2: optimization level variable name (e.g. O2) # @param 3: switches variable name (e.g. USEFASTM) define RECURSION_RULE -TARGETS += $$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip $2) +TARGETS += $$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip $2) # TODO: use the variable $$(MAKECMDGOALS) to get the original make target # TODO- or see if it is even necessary From 247a5e31a5e310a657dd960db90a8a57beccecfd Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 15:59:45 -0700 Subject: [PATCH 151/196] tst_clang: first attempt --- tests/flit_makefile/fake_clang34.py | 164 ++++++++++++++++++++++++++++ tests/flit_makefile/tst_clang.py | 147 +++++++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100755 tests/flit_makefile/fake_clang34.py create mode 100644 tests/flit_makefile/tst_clang.py diff --git a/tests/flit_makefile/fake_clang34.py b/tests/flit_makefile/fake_clang34.py new file mode 100755 index 00000000..cdeeb342 --- /dev/null +++ b/tests/flit_makefile/fake_clang34.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- +'Pretend to be clang 3.4, specifically checking for unsupported flags' + +import sys + +def print_version(): + 'Print fake version information' + print('clang version 3.4.1 (tags/RELEASE_341/final)') + print('Target: x86_64-pc-linux-gnu') + print('Thread model: posix') + print('InstalledDir: /usr/bin') + +def main(arguments): + 'Main logic here' + print('fake_clang34.py {}'.format(arguments), file=sys.stderr) + + recognized_arguments = [ + '-fno-pie', + '-std', + '-g', + '-o', + '-nopie', + '-fassociative-math', + '-mavx', + '-fexcess-precision', + '-ffinite-math-only', + '-mavx2', + '-mfma', + '-march', + '-ffp-contract', + '-ffloat-store', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-fsingle-precision-constant', + '-mfpmath', + '-mtune', + '-funsafe-math-optimizations', + '-MMD', + '-MP', + '-MF', + '-c' + ] + + recognized_beginnings = [ + '-W', + '-D', + '-I', + '-l', + '-L', + '-O', + ] + + with open('fake_clang.log', 'a') as log: + log.write('*' * 80 + '\n') + log.write('\n'.join(arguments) + '\n') + + if '--version' in arguments: + print_version() + return 0 + + for arg in arguments: + canonical = arg.split('=', maxsplit=1)[0] + if canonical.startswith('-'): + print(canonical, file=sys.stderr) + recognized = canonical in recognized_arguments or \ + any(canonical.startswith(x) for x in recognized_beginnings) + if not recognized: + print('Error: unrecognized argument "{0}"'.format(arg), + file=sys.stderr) + return 1 + + if '-o' in arguments or '--output' in arguments: + idx = arguments.index('-o' if '-o' in arguments else '--output') + outfile = arguments[idx + 1] + open(outfile, 'a').close() # create an empty file if it does not exist + + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/tests/flit_makefile/tst_clang.py b/tests/flit_makefile/tst_clang.py new file mode 100644 index 00000000..79ecbc90 --- /dev/null +++ b/tests/flit_makefile/tst_clang.py @@ -0,0 +1,147 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests FLiT's capabilities with compiling against older versions of Clang + +Let's now make a temporary directory and test that using the fake clang, we can +verify correct usage. + +>>> from io import StringIO +>>> import glob +>>> import os +>>> import shutil +>>> import subprocess as subp + +>>> with th.tempdir() as temp_dir: +... temp_dir = 'tmp' +... with StringIO() as ostream: +... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... os.remove(os.path.join(temp_dir, 'flit-config.toml')) +... with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as conf: +... _ = conf.write('[[hosts]]\\n') +... _ = conf.write('[hosts.dev_build]\\n') +... _ = conf.write("compiler_name = 'fake-clang'\\n") +... _ = conf.write('[hosts.ground_truth]\\n') +... _ = conf.write("compiler_name = 'fake-clang'\\n") +... _ = conf.write('[[hosts.compilers]]\\n') +... _ = conf.write("binary = './fake_clang34.py'\\n") +... _ = conf.write("name = 'fake-clang'\\n") +... _ = conf.write("type = 'clang'\\n") +... _ = shutil.copy('fake_clang34.py', temp_dir) +... _ = subp.call(['make', '--always-make', 'Makefile', '-C', temp_dir]) +... make_out = subp.check_output(['make', 'gt', '-C', temp_dir]) +... make_out = make_out.decode('utf8').splitlines() +... with open(os.path.join(temp_dir, 'fake_clang.log'), 'r') as log: +... logout = log.readlines() + +Verify the output of flit init +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating /.../flit-config.toml +Creating /.../custom.mk +Creating /.../main.cpp +Creating /.../tests/Empty.cpp +Creating /.../Makefile + +Check the output of Make +>>> any(['-no-pie' in x for x in make_out]) +False +>>> len(['-nopie' in x for x in make_out]) +3 + +>>> print('\\n'.join(make_out)) + +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) + From 71e3f21fccb688cdcfa569bc3ac36080ced3cb60 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 17:47:29 -0700 Subject: [PATCH 152/196] tst_clang: second pass --- data/Makefile.in | 57 +++++++++++++++-------------- scripts/flitcli/flit_update.py | 4 ++ tests/flit_makefile/fake_clang34.py | 6 ++- tests/flit_makefile/tst_clang.py | 20 ++++------ 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 923b0953..5229de31 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -93,6 +93,9 @@ UNAME_S := $(shell uname -s) CLANG := {clang_compiler} INTEL := {intel_compiler} GCC := {gcc_compiler} +CLANG_TYPE := clang +INTEL_TYPE := intel +GCC_TYPE := gcc # keep only the compilers that are not None and are in the path COMPILERS := {compilers} @@ -102,11 +105,13 @@ FLIT_LIB_DIR := {flit_lib_dir} FLIT_DATA_DIR := {flit_data_dir} FLIT_SCRIPT_DIR := {flit_script_dir} -DEV_CC ?= {dev_compiler} +DEV_CXX ?= {dev_compiler} +DEV_CXX_TYPE ?= {dev_type} DEV_OPTL ?= {dev_optl} DEV_SWITCHES ?= {dev_switches} -GT_CC := {ground_truth_compiler} +GT_CXX := {ground_truth_compiler} +GT_CXX_TYPE := {ground_truth_type} GT_OPTL := {ground_truth_optl} GT_SWITCHES := {ground_truth_switches} @@ -162,15 +167,6 @@ endif # @param 1: executable name or path to compiler GET_COMPILER = $(shell $1 --version | head -n 1 | awk '{{ print $$1 }}') -# Returns 1 if the given compiler is GCC, else 0 -# @param 1: executable name or path to compiler -IS_GCC = $(shell expr $(call GET_COMPILER,$1) = gcc \| \ - $(call GET_COMPILER,$1) = g++) - -# Returns 1 if the given compiler is CLANG, else 0 -# @param 1: executable name or path to compiler -IS_CLANG = $(shell expr $(call GET_COMPILER,$1) = clang) - # Returns the version of the compiler as returned by -dumpversion # @param 1: executable name or path to compiler GET_COMPILER_VER = $(shell $1 -dumpversion) @@ -182,9 +178,8 @@ IS_MAJOR_VER = $(shell expr substr $(call GET_COMPILER_VER,$1) 1 1 = $2) # Returns 1 if the compiler is GCC version 4 or version 5 # @param 1: executable name or path to compiler -IS_GCC_4_OR_5 = $(shell expr $(call IS_GCC,$1) \& \ - \( $(call IS_MAJOR_VER,$1,4) \| \ - $(call IS_MAJOR_VER,$1,5) \)) +IS_VER_4_OR_5 = $(shell expr $(call IS_MAJOR_VER,$1,4) \| \ + $(call IS_MAJOR_VER,$1,5)) DEV_LDFLAGS = GT_LDFLAGS = @@ -401,11 +396,13 @@ rec: $(R_TARGET) # clang's flag is -nopie # else if the current compiler is not GCC 4 or 5, then enable -no-pie # GCC 4 and 5 do not need -no-pie since that is the default -ifeq ($(call IS_CLANG,$($(R_CUR_COMPILER))),1) +ifeq ($($(R_CUR_COMPILER)_TYPE),clang) LD_REQUIRED += -nopie -else ifeq ($(call IS_GCC_4_OR_5,$($(R_CUR_COMPILER))),0) +else ifeq ($($(R_CUR_COMPILER)_TYPE), gcc) +ifeq ($(call IS_VER_4_OR_5,$($(R_CUR_COMPILER))),0) LD_REQUIRED += -no-pie endif +endif $(R_TARGET): $(R_OBJ) $($(R_CUR_COMPILER)) $($(R_CUR_OPTL)) $($(R_CUR_SWITCHES)) \ @@ -430,18 +427,22 @@ else # ifndef R_IS_RECURSED # clang's flag is -nopie # else if the current compiler is not GCC 4 or 5, then enable -no-pie # GCC 4 and 5 do not need -no-pie since that is the default -ifeq ($(call IS_CLANG,$(DEV_CC)),1) +ifeq ($(DEV_CXX_TYPE),clang) DEV_LDFLAGS += -nopie -else ifeq ($(call IS_GCC_4_OR_5,$(DEV_CC)),0) +else ifeq ($(DEV_CXX_TYPE), gcc) +ifeq ($(call IS_VER_4_OR_5,$(DEV_CXX)),0) DEV_LDFLAGS += -no-pie endif +endif # same for the gt compiler -ifeq ($(call IS_CLANG,$(GT_CC)),1) +ifeq ($(GT_CXX_TYPE),clang) GT_LDFLAGS += -nopie -else ifeq ($(call IS_GCC_4_OR_5,$(GT_CC)),0) +else ifeq ($(GT_CXX_TYPE), gcc) +ifeq ($(call IS_VER_4_OR_5,$(GT_CXX)),0) GT_LDFLAGS += -no-pie endif +endif $(OBJ_DIR): mkdir -p $(OBJ_DIR) @@ -573,13 +574,13 @@ endif # ifeq ($(UNAME_S),Darwin): meaning, we are on a mac # Dev compilation rules first (easier to understand) $(DEV_TARGET): $(DEV_OBJ) Makefile custom.mk - $(DEV_CC) $(CC_REQUIRED) $(DEV_CFLAGS) \ + $(DEV_CXX) $(CC_REQUIRED) $(DEV_CFLAGS) \ -o $@ $(DEV_OBJ) $(LD_REQUIRED) $(DEV_LDFLAGS) $(OBJ_DIR)/%_dev.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(DEV_CC) $(DEV_OPTL) $(DEV_SWITCHES) $(CC_REQUIRED) $(DEV_CFLAGS) $(DEPFLAGS) -c $< -o $@ \ + $(DEV_CXX) $(DEV_OPTL) $(DEV_SWITCHES) $(CC_REQUIRED) $(DEV_CFLAGS) $(DEPFLAGS) -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(DEV_CC)"' \ + -DFLIT_COMPILER='"$(DEV_CXX)"' \ -DFLIT_OPTL='"$(DEV_OPTL)"' \ -DFLIT_SWITCHES='"$(DEV_SWITCHES)"' \ -DFLIT_FILENAME='"$(notdir $(DEV_TARGET))"' @@ -589,20 +590,20 @@ $(GT_OUT): $(GT_TARGET) $(RUNWRAP) ./$(GT_TARGET) --output $(GT_OUT) --no-timing $(GT_TARGET): $(GT_OBJ) Makefile custom.mk - $(GT_CC) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) + $(GT_CXX) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) $(OBJ_DIR)/%_gt.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(GT_CC) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ + $(GT_CXX) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(GT_CC)"' \ + -DFLIT_COMPILER='"$(GT_CXX)"' \ -DFLIT_OPTL='"$(GT_OPTL)"' \ -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"' $(OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(GT_CC) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(GT_CXX) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(GT_CC)"' \ + -DFLIT_COMPILER='"$(GT_CXX)"' \ -DFLIT_OPTL='"$(GT_OPTL)"' \ -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"' diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 14d782b6..91378493 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -134,6 +134,7 @@ def main(arguments, prog=sys.argv[0]): assert len(matching_dev_compilers) < 2, \ 'Multiple compilers with name {0} found'.format(dev_compiler_name) dev_compiler_bin = matching_dev_compilers[0]['binary'] + dev_compiler_type = matching_dev_compilers[0]['type'] #if '/' in dev_compiler_bin: # dev_compiler_bin = os.path.realpath(dev_compiler_bin) @@ -149,6 +150,7 @@ def main(arguments, prog=sys.argv[0]): 'Multiple compilers with name {0} found'.format(gt_compiler_name) # TODO: use the compiler mnemonic rather than the path gt_compiler_bin = matching_gt_compilers[0]['binary'] + gt_compiler_type = matching_gt_compilers[0]['type'] #if '/' in dev_compiler_bin: # gt_compiler_bin = os.path.realpath(gt_compiler_bin) @@ -174,9 +176,11 @@ def main(arguments, prog=sys.argv[0]): if val is not None] replacements = { 'dev_compiler': dev_compiler_bin, + 'dev_type': dev_compiler_type, 'dev_optl': dev_optl, 'dev_switches': dev_switches, 'ground_truth_compiler': gt_compiler_bin, + 'ground_truth_type': gt_compiler_type, 'ground_truth_optl': gt_optl, 'ground_truth_switches': gt_switches, 'flit_include_dir': conf.include_dir, diff --git a/tests/flit_makefile/fake_clang34.py b/tests/flit_makefile/fake_clang34.py index cdeeb342..595dbd2c 100755 --- a/tests/flit_makefile/fake_clang34.py +++ b/tests/flit_makefile/fake_clang34.py @@ -93,7 +93,6 @@ def print_version(): def main(arguments): 'Main logic here' - print('fake_clang34.py {}'.format(arguments), file=sys.stderr) recognized_arguments = [ '-fno-pie', @@ -142,10 +141,13 @@ def main(arguments): print_version() return 0 + if '-dumpversion' in arguments: + print('3.4.0') + return 0 + for arg in arguments: canonical = arg.split('=', maxsplit=1)[0] if canonical.startswith('-'): - print(canonical, file=sys.stderr) recognized = canonical in recognized_arguments or \ any(canonical.startswith(x) for x in recognized_beginnings) if not recognized: diff --git a/tests/flit_makefile/tst_clang.py b/tests/flit_makefile/tst_clang.py index 79ecbc90..4c2d25ef 100644 --- a/tests/flit_makefile/tst_clang.py +++ b/tests/flit_makefile/tst_clang.py @@ -93,7 +93,6 @@ >>> import subprocess as subp >>> with th.tempdir() as temp_dir: -... temp_dir = 'tmp' ... with StringIO() as ostream: ... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) ... init_out = ostream.getvalue().splitlines() @@ -109,7 +108,7 @@ ... _ = conf.write("name = 'fake-clang'\\n") ... _ = conf.write("type = 'clang'\\n") ... _ = shutil.copy('fake_clang34.py', temp_dir) -... _ = subp.call(['make', '--always-make', 'Makefile', '-C', temp_dir]) +... _ = subp.check_output(['make', '--always-make', 'Makefile', '-C', temp_dir]) ... make_out = subp.check_output(['make', 'gt', '-C', temp_dir]) ... make_out = make_out.decode('utf8').splitlines() ... with open(os.path.join(temp_dir, 'fake_clang.log'), 'r') as log: @@ -117,20 +116,17 @@ Verify the output of flit init >>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS -Creating /.../flit-config.toml -Creating /.../custom.mk -Creating /.../main.cpp -Creating /.../tests/Empty.cpp -Creating /.../Makefile +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile Check the output of Make >>> any(['-no-pie' in x for x in make_out]) False ->>> len(['-nopie' in x for x in make_out]) -3 - ->>> print('\\n'.join(make_out)) - +>>> len([1 for x in make_out if '-nopie' in x]) +1 ''' # Test setup before the docstring is run. From a4b8e2ab2b08e0b411a2631078c2b7fee508e987 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 18:02:59 -0700 Subject: [PATCH 153/196] tst_clang -> tst_clang34 --- tests/flit_makefile/{tst_clang.py => tst_clang34.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/flit_makefile/{tst_clang.py => tst_clang34.py} (100%) diff --git a/tests/flit_makefile/tst_clang.py b/tests/flit_makefile/tst_clang34.py similarity index 100% rename from tests/flit_makefile/tst_clang.py rename to tests/flit_makefile/tst_clang34.py From d3888bf82080eb1211812ca648eccb84f8ef51e6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 18:13:42 -0700 Subject: [PATCH 154/196] Add tst_gcc4.py --- tests/flit_makefile/fake_clang34.py | 4 - tests/flit_makefile/fake_gcc4.py | 159 ++++++++++++++++++++++++++++ tests/flit_makefile/tst_clang34.py | 2 - tests/flit_makefile/tst_gcc4.py | 141 ++++++++++++++++++++++++ 4 files changed, 300 insertions(+), 6 deletions(-) create mode 100755 tests/flit_makefile/fake_gcc4.py create mode 100644 tests/flit_makefile/tst_gcc4.py diff --git a/tests/flit_makefile/fake_clang34.py b/tests/flit_makefile/fake_clang34.py index 595dbd2c..bc586bc3 100755 --- a/tests/flit_makefile/fake_clang34.py +++ b/tests/flit_makefile/fake_clang34.py @@ -133,10 +133,6 @@ def main(arguments): '-O', ] - with open('fake_clang.log', 'a') as log: - log.write('*' * 80 + '\n') - log.write('\n'.join(arguments) + '\n') - if '--version' in arguments: print_version() return 0 diff --git a/tests/flit_makefile/fake_gcc4.py b/tests/flit_makefile/fake_gcc4.py new file mode 100755 index 00000000..1f7cd6f0 --- /dev/null +++ b/tests/flit_makefile/fake_gcc4.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- +'Pretend to be gcc 4.8.4, specifically checking for unsupported flags' + +import sys + +def print_version(): + 'Print fake version information' + print('Ubuntu g++ (GCC) 4.8.4') + print('Copyright (C) 2018 Free Software Foundation, Inc.') + print('This is a fake GCC compiler that does not actually do anything') + +def main(arguments): + 'Main logic here' + + recognized_arguments = [ + '-fno-pie', + '-std', + '-g', + '-o', + '-fassociative-math', + '-mavx', + '-fexcess-precision', + '-ffinite-math-only', + '-mavx2', + '-fcx-fortran-rules', + '-ffp-contract', + '-ffloat-store', + '-fcx-limited-range', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-mfpmath', + '-funsafe-math-optimizations', + '-MMD', + '-MP', + '-MF', + '-c' + ] + + recognized_beginnings = [ + '-W', + '-D', + '-I', + '-l', + '-L', + '-O', + ] + + if '--version' in arguments: + print_version() + return 0 + + if '-dumpversion' in arguments: + print('4.8.4') + return 0 + + + for arg in arguments: + canonical = arg.split('=', maxsplit=1)[0] + if canonical.startswith('-'): + recognized = canonical in recognized_arguments or \ + any(canonical.startswith(x) for x in recognized_beginnings) + if not recognized: + print('Error: unrecognized argument "{0}"'.format(arg), + file=sys.stderr) + return 1 + + if '-o' in arguments or '--output' in arguments: + idx = arguments.index('-o' if '-o' in arguments else '--output') + outfile = arguments[idx + 1] + open(outfile, 'a').close() # create an empty file if it does not exist + + return 0 + +if __name__ == '__main__': + sys.exit(main(sys.argv[1:])) diff --git a/tests/flit_makefile/tst_clang34.py b/tests/flit_makefile/tst_clang34.py index 4c2d25ef..443848b5 100644 --- a/tests/flit_makefile/tst_clang34.py +++ b/tests/flit_makefile/tst_clang34.py @@ -111,8 +111,6 @@ ... _ = subp.check_output(['make', '--always-make', 'Makefile', '-C', temp_dir]) ... make_out = subp.check_output(['make', 'gt', '-C', temp_dir]) ... make_out = make_out.decode('utf8').splitlines() -... with open(os.path.join(temp_dir, 'fake_clang.log'), 'r') as log: -... logout = log.readlines() Verify the output of flit init >>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS diff --git a/tests/flit_makefile/tst_gcc4.py b/tests/flit_makefile/tst_gcc4.py new file mode 100644 index 00000000..2398e8e5 --- /dev/null +++ b/tests/flit_makefile/tst_gcc4.py @@ -0,0 +1,141 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests FLiT's capabilities with compiling against older versions of GCC + +Let's now make a temporary directory and test that using the fake gcc, we can +verify correct usage. + +>>> from io import StringIO +>>> import glob +>>> import os +>>> import shutil +>>> import subprocess as subp + +>>> with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... _ = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... os.remove(os.path.join(temp_dir, 'flit-config.toml')) +... with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as conf: +... _ = conf.write('[[hosts]]\\n') +... _ = conf.write('[hosts.dev_build]\\n') +... _ = conf.write("compiler_name = 'fake-gcc'\\n") +... _ = conf.write('[hosts.ground_truth]\\n') +... _ = conf.write("compiler_name = 'fake-gcc'\\n") +... _ = conf.write('[[hosts.compilers]]\\n') +... _ = conf.write("binary = './fake_gcc4.py'\\n") +... _ = conf.write("name = 'fake-gcc'\\n") +... _ = conf.write("type = 'gcc'\\n") +... _ = shutil.copy('fake_gcc4.py', temp_dir) +... _ = subp.check_output(['make', '--always-make', 'Makefile', '-C', temp_dir]) +... make_out = subp.check_output(['make', 'gt', '-C', temp_dir]) +... make_out = make_out.decode('utf8').splitlines() + +Verify the output of flit init +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile + +Check the output of Make +>>> any(['-no-pie' in x for x in make_out]) +False +>>> any(['-nopie' in x for x in make_out]) +False +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) + From 6762bd80abc4b0d59e07c084808f9cabe3471d38 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 18:38:14 -0700 Subject: [PATCH 155/196] Fix bisect Makefile from CC -> CXX --- data/Makefile_bisect_binary.in | 28 ++++++++++++------------ tests/flit_cli/flit_bisect/tst_bisect.py | 18 +++++++++------ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/data/Makefile_bisect_binary.in b/data/Makefile_bisect_binary.in index 7fcde77e..9ac5d402 100644 --- a/data/Makefile_bisect_binary.in +++ b/data/Makefile_bisect_binary.in @@ -97,10 +97,10 @@ PRECISION := {precision} TEST_CASE := {test_case} -TROUBLE_CC := {trouble_cc} +TROUBLE_CXX := {trouble_cc} TROUBLE_OPTL := {trouble_optl} TROUBLE_SWITCHES := {trouble_switches} -BISECT_LINK := $(GT_CC) +BISECT_LINK := $(GT_CXX) TROUBLE_ID := {trouble_id} @@ -127,7 +127,7 @@ SPLIT_SRC := TROUBLE_LDFLAGS = # if the trouble compiler is not GCC 4 or 5, then add -no-pie -ifeq ($(call IS_GCC_4_OR_5,$(TROUBLE_CC)),0) +ifeq ($(call IS_GCC_4_OR_5,$(TROUBLE_CXX)),0) TROUBLE_LDFLAGS += -no-pie endif @@ -194,7 +194,7 @@ $(GT_LIB_OUT): $(GT_LIB_TARGET) $(RUNWRAP) ./$(GT_LIB_TARGET) --output $(GT_LIB_OUT) --no-timing --precision "$(PRECISION)" $(TEST_CASE) $(GT_LIB_TARGET): $(GT_OBJ) Makefile custom.mk $(MAKEFILE) - $(GT_CC) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) + $(GT_CXX) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) $(BISECT_RESULT): $(BISECT_OUT) $(GT_LIB_OUT) $(GT_LIB_TARGET) $(RUNWRAP) ./$(GT_LIB_TARGET) --compare-mode --compare-gt $(GT_LIB_OUT) --suffix "-comparison.csv" $< -o /dev/null @@ -212,10 +212,10 @@ $(TROUBLE_TARGET_OUT): $(TROUBLE_TARGET) | $(BISECT_DIR) $(RUNWRAP) ./$< --precision "$(PRECISION)" --output $@ $(TEST_CASE) --no-timing $(BISECT_TARGET): $(BISECT_OBJ) $(SPLIT_OBJ) Makefile custom.mk | $(BISECT_DIR) - $(GT_CC) $(CC_REQUIRED) -o $@ $(BISECT_OBJ) $(SPLIT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) + $(GT_CXX) $(CC_REQUIRED) -o $@ $(BISECT_OBJ) $(SPLIT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) $(TROUBLE_TARGET): $(TROUBLE_TARGET_OBJ) Makefile custom.mk | $(BISECT_DIR) - $(TROUBLE_CC) $(CC_REQUIRED) -o $@ $(TROUBLE_TARGET_OBJ) $(LD_REQUIRED) $(TROUBLE_LDFLAGS) + $(TROUBLE_CXX) $(CC_REQUIRED) -o $@ $(TROUBLE_TARGET_OBJ) $(LD_REQUIRED) $(TROUBLE_LDFLAGS) .PHONY: trouble trouble-out trouble-fpic trouble: $(TROUBLE_TARGET) @@ -270,9 +270,9 @@ $(BISECT_OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(BISECT_OBJ_DIR) if [ -f "$(OBJ_DIR)/$*_gt_fPIC.o" ]; then \ ln -s "../../$(OBJ_DIR)/$*_gt_fPIC.o" "$@"; \ else \ - $(GT_CC) $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(GT_CXX) $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(GT_CC)"' \ + -DFLIT_COMPILER='"$(GT_CXX)"' \ -DFLIT_OPTL='"$(GT_OPTL)"' \ -DFLIT_SWITCHES='"$(GT_SWITCHES)"' \ -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"'; \ @@ -281,9 +281,9 @@ $(BISECT_OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(BISECT_OBJ_DIR) # specify how to build the troublesome ones $(OBJ_DIR)/%_bisect_$(TROUBLE_ID).o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(TROUBLE_CC) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ + $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(TROUBLE_CC)"' \ + -DFLIT_COMPILER='"$(TROUBLE_CXX)"' \ -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ -DFLIT_SWITCHES='"$(TROUBLE_SWITCHES)"' \ -DFLIT_FILENAME='"bisect-default-out"' @@ -293,9 +293,9 @@ $(BISECT_OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(BI if [ -f "$(OBJ_DIR)/$*_bisect_$(TROUBLE_ID)_fPIC.o" ]; then \ ln -s "../../$(OBJ_DIR)/$*_bisect_$(TROUBLE_ID)_fPIC.o" "$@"; \ else \ - $(TROUBLE_CC) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(TROUBLE_CC)"' \ + -DFLIT_COMPILER='"$(TROUBLE_CXX)"' \ -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ -DFLIT_SWITCHES='"$(TROUBLE_SWITCHES)"' \ -DFLIT_FILENAME='"bisect-default-out"'; \ @@ -303,9 +303,9 @@ $(BISECT_OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(BI # and the fPIC variant $(OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(TROUBLE_CC) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ - -DFLIT_COMPILER='"$(TROUBLE_CC)"' \ + -DFLIT_COMPILER='"$(TROUBLE_CXX)"' \ -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ -DFLIT_SWITCHES='"$(TROUBLE_SWITCHES)"' \ -DFLIT_FILENAME='"bisect-default-out"' diff --git a/tests/flit_cli/flit_bisect/tst_bisect.py b/tests/flit_cli/flit_bisect/tst_bisect.py index 286b0f9d..fb149bdc 100644 --- a/tests/flit_cli/flit_bisect/tst_bisect.py +++ b/tests/flit_cli/flit_bisect/tst_bisect.py @@ -100,20 +100,24 @@ >>> with th.tempdir() as temp_dir: ... with StringIO() as ostream: ... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... if retval != 0: +... raise BisectTestError( +... 'Could not initialize (retval={0}):\\n'.format(retval) + +... ostream.getvalue()) ... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise BisectTestError('Main #1 returned {}'.format(retval)) ... shutil.rmtree(os.path.join(temp_dir, 'tests')) ... _ = shutil.copytree(os.path.join('data', 'tests'), ... os.path.join(temp_dir, 'tests')) ... with StringIO() as ostream: ... retval = th.flit.main(['bisect', '-C', temp_dir, -... '--precision', 'double', -... 'g++ -O3', 'BisectTest'], -... outstream=ostream) +... '--precision', 'double', +... 'g++ -O3', 'BisectTest'], +... outstream=ostream) +... if retval != 0: +... raise BisectTestError( +... 'Could not bisect (retval={0}):\\n'.format(retval) + +... ostream.getvalue()) ... bisect_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise BisectTestError('Main #2 returned {}'.format(retval)) ... with open(os.path.join(temp_dir, 'bisect-01', 'bisect.log')) as fin: ... raw_log = fin.readlines() ... stripped_log = [line[line.index(' bisect:')+8:].rstrip() From 6451b405cde0c09468f35d33de90ffaf1bd3c2da Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 18:41:49 -0700 Subject: [PATCH 156/196] tst_mpi: update test to reflect removing 'MPI is disabled' --- tests/flit_mpi/tst_run_mpi.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/flit_mpi/tst_run_mpi.py b/tests/flit_mpi/tst_run_mpi.py index 7b101802..13308c46 100644 --- a/tests/flit_mpi/tst_run_mpi.py +++ b/tests/flit_mpi/tst_run_mpi.py @@ -143,13 +143,6 @@ >>> run_str_2 = run_str_2.decode('utf-8').strip().splitlines() >>> run_str_3 = run_str_3.decode('utf-8').strip().splitlines() -Make sure the info statement about MPI being enabled is done at each make call - ->>> 'MPI is enabled' in compile_str -True ->>> 'MPI is enabled' in run_str -True - Make sure the correct arguments are passed to mpirun >>> 'mpirun -n 2 ./gtrun --output ground-truth.csv --no-timing' in run_str From 64c6393213002b7e544ae9d0b3497269bb6b99da Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 21:51:10 -0700 Subject: [PATCH 157/196] docs: describe minimum supported compilers and Clang Only --- documentation/installation.md | 42 ++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/documentation/installation.md b/documentation/installation.md index b7654e65..a99b8714 100644 --- a/documentation/installation.md +++ b/documentation/installation.md @@ -8,6 +8,7 @@ Instruction Contents: * [Prerequisites](#prerequisites) * [Compilers](#compilers) + * [Clang Only](#clang-only) * [Optional Dependencies](#optional-dependencies) * [FLiT Setup](#flit-setup) * [Database Setup](#database-setup) @@ -32,7 +33,8 @@ Stuff you may need to get parsing ELF files. This is used for `flit bisect`; all other functionality will work without it. * [make](https://www.gnu.org/software/make) -* [gcc](https://gcc.gnu.org) version 4.9 or higher +* [gcc](https://gcc.gnu.org) version 4.9 or higher (or + [clang](https://clang.llvm.org), see section [Clang Only](#clang-only)) * [sqlite3](https://sqlite.org) version 3.0 or higher. You can use the one that comes with python, or install as a standalone. @@ -76,6 +78,44 @@ install another version of GCC, as well as Clang and the Intel compiler. If you are missing either Clang or the Intel compiler, FLiT will still work as expected. +The supported compiler versions are: + +| Compiler Type | Minimum Supported Version | +|:-------------:|:-------------------------:| +| gcc | 4.9.0 | +| clang | 3.4.0 | +| intel | 16.0 | + +If your compiler version is below those on this list and you want FLiT to +support it, please create an [issue](https://github.com/PRUNERS/FLiT/issues) +and we may be able to add support for you. Otherwise, you are on your own. + +Likewise, if you want support added for other types of compilers, such as the +PGI compiler or the IBM compiler, please create an +[issue](https://github.com/PRUNERS/FLiT/issues). + + +### Clang Only + +FLiT is mostly geared around having at least GCC around, however, users may +want to skip using GCC and use Clang instead. If this is your use case, this +can be done. + +To compile FLiT using Clang, set the `CXX` environment variable to the +executable for Clang you wish to use. For example: + +```bash +git clone https://github.com/PRUNERS/FLiT.git +cd FLiT +export CXX=clang +make +sudo make install +``` + +Then when creating your environment, simply provide only a Clang compiler. +This setup is largely untested, so if you have trouble, please submit an +[issue](https://github.com/PRUNERS/FLiT/issues). + ### Optional Dependencies FLiT has [MPI support](mpi-support.md) which you may want to use. To compile From 381553bcb70456dab2136ae23d96ed2e06095554 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Mon, 26 Nov 2018 22:39:01 -0700 Subject: [PATCH 158/196] Specify the minimum version of binutils --- documentation/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/installation.md b/documentation/installation.md index b7654e65..aa9cbc7e 100644 --- a/documentation/installation.md +++ b/documentation/installation.md @@ -18,7 +18,7 @@ Instruction Contents: Stuff you should already have: * [bash](https://www.gnu.org/software/bash) -* [binutils](https://www.gnu.org/software/binutils) +* [binutils](https://www.gnu.org/software/binutils) version 2.26 or higher * [coreutils](https://www.gnu.org/software/coreutils/coreutils.html) * hostname From 82761010414643362d6bbb9e144b4f4e1bd216bc Mon Sep 17 00:00:00 2001 From: JJ Garzella Date: Tue, 27 Nov 2018 14:26:54 +0000 Subject: [PATCH 159/196] Generalize flags into toml file. The flags were hardcoded into the Makefile, now the are generated through the toml file. This commit removes a layer of indirection in which each flag is stored in a variable, and the compiler's flags are lists of variables rather than lists of flags. This indirection is useful for mutliple things, including names, flags with spaces, and the empty flag. Therefore, in a future commit, this level should be reproduced at the Python level, and re-introduced. In the meantime, this commit will compile and run fine, so long as none of the special cases mentioned above are hit. --- data/Makefile.in | 246 ++++++++++---------- scripts/flitcli/config/flit-default.toml.in | 30 +++ scripts/flitcli/flit_update.py | 12 +- 3 files changed, 167 insertions(+), 121 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 7714d896..dd36fcf8 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -247,127 +247,135 @@ endif # more comp settings, taken from here: # https://software.intel.com/sites/default/files/article/326703/fp-control-2012-08.pdf +SWITCHES_GCC := {switches_gcc} +SWITCHES_CLANG := {switches_clang} +SWITCHES_INTEL := {switches_intel} + +OPCODES_GCC := {opcodes_gcc} +OPCODES_CLANG := {opcodes_clang} +OPCODES_INTEL := {opcodes_intel} + #individual flags ## optls -O0 := -O0 -O1 := -O1 -O2 := -O2 -O3 := -O3 - -#switches - -ASSOCMATH := -fassociative-math -AVX := -mavx -COMPTRANS := -mp1 -DEFFLAGS := -DISFMA := -no-fma -ENAFMA := -fma -FASTEXPREC := -fexcess-precision=fast -FASTM := -ffast-math -FINMATH := -ffinite-math-only -FLUSHDEN := -ftz -FMAGCC := -mavx2 -mfma -FMAICC := -march=core-avx2 -FORTRULES := -fcx-fortran-rules -FPCONT := -ffp-contract=on -FPMODDBL := -fp-model=double -FPMODEXC := -fp-model=except -FPMODEXT := -fp-model=extended -FPMODFST1 := -fp-model fast=1 -FPMODFST2 := -fp-model fast=2 -FPMODPRE := -fp-model=precise -FPMODSRC := -fp-model=source -FPMODSTR := -fp-model=strict -FPTRAP := -fp-trap=common -FSTORE := -ffloat-store -LIMITEDRANGE := -fcx-limited-range -MCONSTS := -fmerge-all-constants -NOFLUSHDEN := -no-ftz -NOPRECDIV := -no-prec-div -NOTRAP := -fno-trapping-math -PRECDIV := -prec-div -RECIPMATH := -freciprocal-math -ROUNDINGMATH := -frounding-math -ROUNDUSR := -fp-port -SIGNALNAN := -fsignaling-nans -SINGLEPRECCONST := -fsingle-precision-constant -SSE := -mfpmath=sse -mtune=native -STDEXPREC := -fexcess-precision=standard -UNSOPTS := -funsafe-math-optimizations -USEFASTM := --use_fast_math - -# Collections - -OPCODES := O0 O1 O2 O3 - -# NOTE: gcc disables ASSOCMATH @ O0 -SWITCHES_GCC += ASSOCMATH -SWITCHES_GCC += AVX -SWITCHES_GCC += DEFFLAGS -SWITCHES_GCC += FASTEXPREC -SWITCHES_GCC += FINMATH -SWITCHES_GCC += FMAGCC -SWITCHES_GCC += FORTRULES -SWITCHES_GCC += FPCONT -SWITCHES_GCC += FSTORE -SWITCHES_GCC += LIMITEDRANGE -SWITCHES_GCC += MCONSTS -SWITCHES_GCC += NOTRAP -SWITCHES_GCC += RECIPMATH -SWITCHES_GCC += ROUNDINGMATH -SWITCHES_GCC += SIGNALNAN -SWITCHES_GCC += SSE -SWITCHES_GCC += UNSOPTS - -#NOTE: Clang not honoring ASSOCMATH (issues warning with 3.9) -# see: https://llvm.org/bugs/show_bug.cgi?id=27372 - -SWITCHES_CLANG += ASSOCMATH -SWITCHES_CLANG += AVX -SWITCHES_CLANG += DEFFLAGS -SWITCHES_CLANG += FASTEXPREC -SWITCHES_CLANG += FINMATH -SWITCHES_CLANG += FMAGCC -SWITCHES_CLANG += FMAICC -SWITCHES_CLANG += FPCONT -SWITCHES_CLANG += FSTORE -SWITCHES_CLANG += MCONSTS -SWITCHES_CLANG += NOTRAP -SWITCHES_CLANG += RECIPMATH -SWITCHES_CLANG += ROUNDINGMATH -SWITCHES_CLANG += SIGNALNAN -SWITCHES_CLANG += SINGLEPRECCONST -SWITCHES_CLANG += SSE -SWITCHES_CLANG += STDEXPREC -SWITCHES_CLANG += UNSOPTS - -SWITCHES_INTEL += AVX -SWITCHES_INTEL += COMPTRANS -SWITCHES_INTEL += DEFFLAGS -SWITCHES_INTEL += DISFMA -SWITCHES_INTEL += ENAFMA -SWITCHES_INTEL += FLUSHDEN -SWITCHES_INTEL += FMAGCC -SWITCHES_INTEL += FMAICC -SWITCHES_INTEL += FPMODDBL -SWITCHES_INTEL += FPMODEXT -SWITCHES_INTEL += FPMODFST1 -SWITCHES_INTEL += FPMODFST2 -SWITCHES_INTEL += FPMODPRE -SWITCHES_INTEL += FPMODSRC -SWITCHES_INTEL += FPMODSTR -SWITCHES_INTEL += FSTORE -SWITCHES_INTEL += LIMITEDRANGE -SWITCHES_INTEL += MCONSTS -SWITCHES_INTEL += NOFLUSHDEN -SWITCHES_INTEL += NOPRECDIV -SWITCHES_INTEL += PRECDIV -SWITCHES_INTEL += ROUNDINGMATH -SWITCHES_INTEL += ROUNDUSR -SWITCHES_INTEL += SINGLEPRECCONST -SWITCHES_INTEL += SSE -SWITCHES_INTEL += USEFASTM +#O0 := -O0 +#O1 := -O1 +#O2 := -O2 +#O3 := -O3 +# +##switches +# +#ASSOCMATH := -fassociative-math +#AVX := -mavx +#COMPTRANS := -mp1 +#DEFFLAGS := +#DISFMA := -no-fma +#ENAFMA := -fma +#FASTEXPREC := -fexcess-precision=fast +#FASTM := -ffast-math +#FINMATH := -ffinite-math-only +#FLUSHDEN := -ftz +#FMAGCC := -mavx2 -mfma +#FMAICC := -march=core-avx2 +#FORTRULES := -fcx-fortran-rules +#FPCONT := -ffp-contract=on +#FPMODDBL := -fp-model=double +#FPMODEXC := -fp-model=except +#FPMODEXT := -fp-model=extended +#FPMODFST1 := -fp-model fast=1 +#FPMODFST2 := -fp-model fast=2 +#FPMODPRE := -fp-model=precise +#FPMODSRC := -fp-model=source +#FPMODSTR := -fp-model=strict +#FPTRAP := -fp-trap=common +#FSTORE := -ffloat-store +#LIMITEDRANGE := -fcx-limited-range +#MCONSTS := -fmerge-all-constants +#NOFLUSHDEN := -no-ftz +#NOPRECDIV := -no-prec-div +#NOTRAP := -fno-trapping-math +#PRECDIV := -prec-div +#RECIPMATH := -freciprocal-math +#ROUNDINGMATH := -frounding-math +#ROUNDUSR := -fp-port +#SIGNALNAN := -fsignaling-nans +#SINGLEPRECCONST := -fsingle-precision-constant +#SSE := -mfpmath=sse -mtune=native +#STDEXPREC := -fexcess-precision=standard +#UNSOPTS := -funsafe-math-optimizations +#USEFASTM := --use_fast_math +# +## Collections +# +#OPCODES := O0 O1 O2 O3 +# +## NOTE: gcc disables ASSOCMATH @ O0 +#SWITCHES_GCC += ASSOCMATH +#SWITCHES_GCC += AVX +#SWITCHES_GCC += DEFFLAGS +#SWITCHES_GCC += FASTEXPREC +#SWITCHES_GCC += FINMATH +#SWITCHES_GCC += FMAGCC +#SWITCHES_GCC += FORTRULES +#SWITCHES_GCC += FPCONT +#SWITCHES_GCC += FSTORE +#SWITCHES_GCC += LIMITEDRANGE +#SWITCHES_GCC += MCONSTS +#SWITCHES_GCC += NOTRAP +#SWITCHES_GCC += RECIPMATH +#SWITCHES_GCC += ROUNDINGMATH +#SWITCHES_GCC += SIGNALNAN +#SWITCHES_GCC += SSE +#SWITCHES_GCC += UNSOPTS +# +##NOTE: Clang not honoring ASSOCMATH (issues warning with 3.9) +## see: https://llvm.org/bugs/show_bug.cgi?id=27372 +# +#SWITCHES_CLANG += ASSOCMATH +#SWITCHES_CLANG += AVX +#SWITCHES_CLANG += DEFFLAGS +#SWITCHES_CLANG += FASTEXPREC +#SWITCHES_CLANG += FINMATH +#SWITCHES_CLANG += FMAGCC +#SWITCHES_CLANG += FMAICC +#SWITCHES_CLANG += FPCONT +#SWITCHES_CLANG += FSTORE +#SWITCHES_CLANG += MCONSTS +#SWITCHES_CLANG += NOTRAP +#SWITCHES_CLANG += RECIPMATH +#SWITCHES_CLANG += ROUNDINGMATH +#SWITCHES_CLANG += SIGNALNAN +#SWITCHES_CLANG += SINGLEPRECCONST +#SWITCHES_CLANG += SSE +#SWITCHES_CLANG += STDEXPREC +#SWITCHES_CLANG += UNSOPTS +# +#SWITCHES_INTEL += AVX +#SWITCHES_INTEL += COMPTRANS +#SWITCHES_INTEL += DEFFLAGS +#SWITCHES_INTEL += DISFMA +#SWITCHES_INTEL += ENAFMA +#SWITCHES_INTEL += FLUSHDEN +#SWITCHES_INTEL += FMAGCC +#SWITCHES_INTEL += FMAICC +#SWITCHES_INTEL += FPMODDBL +#SWITCHES_INTEL += FPMODEXT +#SWITCHES_INTEL += FPMODFST1 +#SWITCHES_INTEL += FPMODFST2 +#SWITCHES_INTEL += FPMODPRE +#SWITCHES_INTEL += FPMODSRC +#SWITCHES_INTEL += FPMODSTR +#SWITCHES_INTEL += FSTORE +#SWITCHES_INTEL += LIMITEDRANGE +#SWITCHES_INTEL += MCONSTS +#SWITCHES_INTEL += NOFLUSHDEN +#SWITCHES_INTEL += NOPRECDIV +#SWITCHES_INTEL += PRECDIV +#SWITCHES_INTEL += ROUNDINGMATH +#SWITCHES_INTEL += ROUNDUSR +#SWITCHES_INTEL += SINGLEPRECCONST +#SWITCHES_INTEL += SSE +#SWITCHES_INTEL += USEFASTM ########################################################## @@ -468,7 +476,7 @@ endef $(foreach c, $(COMPILERS), \ $(foreach s, $(SWITCHES_$(strip $c)), \ - $(foreach o, $(OPCODES), \ + $(foreach o, $(OPCODES_$(strip $c)), \ $(eval $(call RECURSION_RULE, $c, $o, $s))))) TARGET_OUTS := $(TARGETS:%=%-out) TARGET_RESULTS := $(TARGET_OUTS:%=%-comparison.csv) diff --git a/scripts/flitcli/config/flit-default.toml.in b/scripts/flitcli/config/flit-default.toml.in index a6e16b10..b9f866c0 100644 --- a/scripts/flitcli/config/flit-default.toml.in +++ b/scripts/flitcli/config/flit-default.toml.in @@ -156,14 +156,44 @@ switches = '' binary = 'g++' name = 'g++' type = 'gcc' + optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', + ] + switches = [ + '-funsafe-math-optimizations', + '' + ] [[hosts.compilers]] binary = 'clang++' name = 'clang++' type = 'clang' + optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', + ] + switches = [ + '-funsafe-math-optimizations', + '' + ] [[hosts.compilers]] binary = 'icpc' name = 'icpc' type = 'intel' + optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', + ] + switches = [ + '-funsafe-math-optimizations', + '' + ] diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 14d782b6..c86bcf6e 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -154,12 +154,16 @@ def main(arguments, prog=sys.argv[0]): supported_compiler_types = ('clang', 'gcc', 'intel') base_compilers = {x: None for x in supported_compiler_types} + compiler_flags = {x: None for x in supported_compiler_types} + compiler_op_levels = {x: None for x in supported_compiler_types} for compiler in host['compilers']: assert compiler['type'] in supported_compiler_types, \ 'Unsupported compiler type: {}'.format(compiler['type']) assert base_compilers[compiler['type']] is None, \ 'You can only specify one of each type of compiler.' base_compilers[compiler['type']] = compiler['binary'] + compiler_flags[compiler['type']] = compiler['switches'] + compiler_op_levels[compiler['type']] = compiler['optimization_levels'] test_run_args = '' if not projconf['run']['timing']: @@ -170,7 +174,7 @@ def main(arguments, prog=sys.argv[0]): '--timing-repeats', str(projconf['run']['timing_repeats']), ]) - given_compilers = [key.upper() for key, val in base_compilers.items() + given_compilers = [key for key, val in base_compilers.items() if val is not None] replacements = { 'dev_compiler': dev_compiler_bin, @@ -187,10 +191,14 @@ def main(arguments, prog=sys.argv[0]): 'test_run_args': test_run_args, 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', 'mpirun_args': projconf['run']['mpirun_args'], - 'compilers': ' '.join(given_compilers), + 'compilers': ' '.join([c.upper() for c in given_compilers]), } replacements.update({key + '_compiler': val for key, val in base_compilers.items()}) + replacements.update({'opcodes_' + compiler: ' '.join(compiler_op_levels[compiler]) + for compiler in given_compilers}) + replacements.update({'switches_' + compiler: ' '.join(compiler_flags[compiler]) + for compiler in given_compilers}) flitutil.process_in_file(os.path.join(conf.data_dir, 'Makefile.in'), makefile, replacements, overwrite=True) From 3a0cfbaaccbd1052afdc82d4cf698da4d34ac8a7 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 27 Nov 2018 08:43:36 -0700 Subject: [PATCH 160/196] flit-config: remove hosts and restructure --- benchmarks/polybench/flit-config.toml | 25 +------ benchmarks/random/flit-config.toml | 48 +------------- scripts/flitcli/config/flit-default.toml.in | 73 +++++++++++---------- scripts/flitcli/flit_update.py | 11 ++-- tests/flit_mpi/data/flit-config.toml | 2 + 5 files changed, 46 insertions(+), 113 deletions(-) diff --git a/benchmarks/polybench/flit-config.toml b/benchmarks/polybench/flit-config.toml index cbe16d21..314dced4 100644 --- a/benchmarks/polybench/flit-config.toml +++ b/benchmarks/polybench/flit-config.toml @@ -1,24 +1 @@ -# Autogenerated by "flit init" -# flit version v2.0-alpha.3 - -[database] - -type = 'sqlite' -filepath = 'results.sqlite' - - -[[hosts]] - -[hosts.dev_build] - -compiler_name = 'g++' -optimization_level = '-O2' -switches = '-funsafe-math-optimizations' - - -[hosts.ground_truth] - -compiler_name = 'g++' -optimization_level = '-O0' -switches = '' - +# Use the default values diff --git a/benchmarks/random/flit-config.toml b/benchmarks/random/flit-config.toml index 6fc21156..44a265ae 100644 --- a/benchmarks/random/flit-config.toml +++ b/benchmarks/random/flit-config.toml @@ -1,50 +1,4 @@ -# Autogenerated by "flit init" -# flit version v2.0-alpha.3 - -[database] - -# older versions of flit supported postgres. that has been removed. only -# sqlite is supported at the moment. -type = 'sqlite' - -# if relative path, it is relative to the directory containing this -# configuration file. -filepath = 'results.sqlite' - [run] timing = false -# For now, only one host is supported, all others are ignored -[[hosts]] - -name = 'yoga-manjaro' -flit_path = '/home/bentley/git/FLiT/scripts/flitcli/flit.py' -config_dir = '/home/bentley/git/FLiT/scripts/flitcli/config' - -# The settings for "make dev" -[hosts.dev_build] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list -compiler_name = 'g++' -optimization_level = '-O2' -switches = '-funsafe-math-optimizations' - -# The ground truth compilation to use in analysis, for "make gt" -[hosts.ground_truth] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list -compiler_name = 'g++' -optimization_level = '-O0' -switches = '' - - # This host's list of compilers. - # For now, only used for hosts.ground_truth and hosts.dev_build. - # TODO: use this list to generate the Makefile - [[hosts.compilers]] - - # binary can be an absolute path, relative path, or binary name (found in - # PATH). If you want to specify a compiler in the same directory as this - # config file, prepend with a "./" (e.g. "./my-compiler") - binary = 'g++' - name = 'g++' - +# Use default values for all other options diff --git a/scripts/flitcli/config/flit-default.toml.in b/scripts/flitcli/config/flit-default.toml.in index a6e16b10..e79b6808 100644 --- a/scripts/flitcli/config/flit-default.toml.in +++ b/scripts/flitcli/config/flit-default.toml.in @@ -82,6 +82,14 @@ # Autogenerated by "flit init" # flit version {flit_version} +# General information +[host] + +# If you omit name, the system hostname will be used +name = '{hostname}' +flit_path = '{flit_path}' +config_dir = '{config_dir}' + [database] # older versions of flit supported postgres. that has been removed. only @@ -116,15 +124,8 @@ enable_mpi = false mpirun_args = '' -# For now, only the first host is supported, all others are ignored -[[hosts]] - -name = '{hostname}' -flit_path = '{flit_path}' -config_dir = '{config_dir}' - # The settings for "make dev" -[hosts.dev_build] +[dev_build] # compiler_name must be found in [[hosts.compilers]] list under name attribute # but the optimization level and switches do not need to be in the compiler list compiler_name = 'g++' @@ -132,38 +133,38 @@ optimization_level = '-O2' switches = '-funsafe-math-optimizations' # The ground truth compilation to use in analysis, for "make gt" -[hosts.ground_truth] +[ground_truth] # compiler_name must be found in [[hosts.compilers]] list under name attribute # but the optimization level and switches do not need to be in the compiler list compiler_name = 'g++' optimization_level = '-O0' switches = '' - # This host's list of compilers. - # - binary: can be an absolute path, relative path, or binary name (found in - # PATH). If you want to specify a compiler in the same directory as this - # config file, prepend with a "./" (e.g. "./my-compiler") - # - name: can be any string. Used to recognize in the other options such as - # dev_build and ground_truth - # - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') - # Currently, only one of each type may be specified. - # Note that these are all defaulted to use g++, clang++, and icpc from the - # PATH. - # If you specify any one compiler, then these defaults are erased. If you - # specify no compiler, then these defaults take effect. - - [[hosts.compilers]] - binary = 'g++' - name = 'g++' - type = 'gcc' - - [[hosts.compilers]] - binary = 'clang++' - name = 'clang++' - type = 'clang' - - [[hosts.compilers]] - binary = 'icpc' - name = 'icpc' - type = 'intel' +# List of compilers. +# - binary: can be an absolute path, relative path, or binary name (found in +# PATH). If you want to specify a compiler in the same directory as this +# config file, prepend with a "./" (e.g. "./my-compiler") +# - name: can be any string. Used to recognize in the other options such as +# dev_build and ground_truth +# - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') +# Currently, only one of each type may be specified. +# Note that these are all defaulted to use g++, clang++, and icpc from the +# PATH. +# If you specify any one compiler, then these defaults are erased. If you +# specify no compiler, then these defaults take effect. + +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' + +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' + +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index d6edfb3b..e0f9d0e5 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -123,12 +123,11 @@ def main(arguments, prog=sys.argv[0]): else: print('Creating {0}'.format(makefile)) - host = projconf['hosts'][0] - dev_build = host['dev_build'] + dev_build = projconf['dev_build'] dev_compiler_name = dev_build['compiler_name'] dev_optl = dev_build['optimization_level'] dev_switches = dev_build['switches'] - matching_dev_compilers = [x for x in host['compilers'] + matching_dev_compilers = [x for x in projconf['compiler'] if x['name'] == dev_compiler_name] assert len(matching_dev_compilers) > 0, \ 'Compiler name {0} not found'.format(dev_compiler_name) @@ -138,11 +137,11 @@ def main(arguments, prog=sys.argv[0]): #if '/' in dev_compiler_bin: # dev_compiler_bin = os.path.realpath(dev_compiler_bin) - ground_truth = host['ground_truth'] + ground_truth = projconf['ground_truth'] gt_compiler_name = ground_truth['compiler_name'] gt_optl = ground_truth['optimization_level'] gt_switches = ground_truth['switches'] - matching_gt_compilers = [x for x in host['compilers'] + matching_gt_compilers = [x for x in projconf['compiler'] if x['name'] == gt_compiler_name] assert len(matching_dev_compilers) > 0, \ 'Compiler name {0} not found'.format(gt_compiler_name) @@ -155,7 +154,7 @@ def main(arguments, prog=sys.argv[0]): supported_compiler_types = ('clang', 'gcc', 'intel') base_compilers = {x: None for x in supported_compiler_types} - for compiler in host['compilers']: + for compiler in projconf['compiler']: assert compiler['type'] in supported_compiler_types, \ 'Unsupported compiler type: {}'.format(compiler['type']) assert base_compilers[compiler['type']] is None, \ diff --git a/tests/flit_mpi/data/flit-config.toml b/tests/flit_mpi/data/flit-config.toml index 63aeaf74..686e8e0b 100644 --- a/tests/flit_mpi/data/flit-config.toml +++ b/tests/flit_mpi/data/flit-config.toml @@ -1,3 +1,5 @@ [run] enable_mpi = true mpirun_args = '-n 2' + +# Use default for all other options From f8b62d4b197ea16cdac3c915e2b20807f72e4af5 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 27 Nov 2018 09:47:15 -0700 Subject: [PATCH 161/196] flit-config: update documentation with the [host] change --- documentation/available-compiler-flags.md | 98 ++++------ documentation/flit-configuration-file.md | 197 ++++++++++++-------- scripts/flitcli/config/flit-default.toml.in | 27 +-- 3 files changed, 175 insertions(+), 147 deletions(-) diff --git a/documentation/available-compiler-flags.md b/documentation/available-compiler-flags.md index 9556f47f..c4de4c09 100644 --- a/documentation/available-compiler-flags.md +++ b/documentation/available-compiler-flags.md @@ -20,51 +20,42 @@ If you want to have specific flag combinations, you can place it in the list, such as `"-mavx2 -mfma -funsafe-math-optimizations"`. Below is the original default list for the supported compilers: -| Flag | GCC | Clang | Intel | NVCC | -| ----------------------------- |:-----:|:-----:|:-----:|:----:| -| `-fassociative-math` | X | X | | | -| `-fcx-fortran-rules` | X | | | | -| `-fcx-limited-range` | X | | X | | -| `-fexcess-precision=fast` | X | X | | | -| `-fexcess-precision=standard` | | X | | | -| `-ffinite-math-only` | X | X | | | -| `-ffloat-store` | X | X | X | | -| `-ffp-contract=on` | X | X | | | -| `-fma` | | | X | | -| `-fmerge-all-constants` | X | X | X | | -| `-fno-trapping-math` | X | X | | | -| `-fp-model fast=1` | | | X | | -| `-fp-model fast=2` | | | X | | -| `-fp-model=double` | | | X | | -| `-fp-model=extended` | | | X | | -| `-fp-model=precise` | | | X | | -| `-fp-model=source` | | | X | | -| `-fp-model=strict` | | | X | | -| `-fp-port` | | | X | | -| `-freciprocal-math` | X | X | | | -| `-frounding-math` | X | X | X | | -| `-fsignaling-nans` | X | X | | | -| `-fsingle-precision-constant` | | X | X | | -| `-ftz` | | | X | | -| `-funsafe-math-optimizations` | X | X | | | -| `-march=core-avx2` | | X | X | | -| `-mavx` | X | X | X | | -| `-mavx2 -mfma` | X | X | X | | -| `-mfpmath=sse -mtune=native` | X | X | X | | -| `-mp1` | | | X | | -| `-no-fma` | | | X | | -| `-no-ftz` | | | X | | -| `-no-prec-div` | | | X | | -| `-prec-div` | | | X | | -| `--fmad=false` | | | | X | -| `--fmad=true` | | | | X | -| `--ftz=false` | | | | X | -| `--ftz=true` | | | | X | -| `--prec-div=false` | | | | X | -| `--prec-div=true` | | | | X | -| `--prec-sqrt=false` | | | | X | -| `--prec-sqrt=true` | | | | X | -| `--use_fast_math` | | | X | X | +| Flag | GCC | Clang | Intel | +| ----------------------------- |:-----:|:-----:|:-----:| +| `-fassociative-math` | X | X | | +| `-fcx-fortran-rules` | X | | | +| `-fcx-limited-range` | X | | X | +| `-fexcess-precision=fast` | X | X | | +| `-fexcess-precision=standard` | | X | | +| `-ffinite-math-only` | X | X | | +| `-ffloat-store` | X | X | X | +| `-ffp-contract=on` | X | X | | +| `-fma` | | | X | +| `-fmerge-all-constants` | X | X | X | +| `-fno-trapping-math` | X | X | | +| `-fp-model fast=1` | | | X | +| `-fp-model fast=2` | | | X | +| `-fp-model=double` | | | X | +| `-fp-model=extended` | | | X | +| `-fp-model=precise` | | | X | +| `-fp-model=source` | | | X | +| `-fp-model=strict` | | | X | +| `-fp-port` | | | X | +| `-freciprocal-math` | X | X | | +| `-frounding-math` | X | X | X | +| `-fsignaling-nans` | X | X | | +| `-fsingle-precision-constant` | | X | X | +| `-ftz` | | | X | +| `-funsafe-math-optimizations` | X | X | | +| `-march=core-avx2` | | X | X | +| `-mavx` | X | X | X | +| `-mavx2 -mfma` | X | X | X | +| `-mfpmath=sse -mtune=native` | X | X | X | +| `-mp1` | | | X | +| `-no-fma` | | | X | +| `-no-ftz` | | | X | +| `-no-prec-div` | | | X | +| `-prec-div` | | | X | For your convenience, here are toml-style lists that can be copied into your `flit-config.toml` file directly: @@ -152,23 +143,6 @@ switches = [ ] ``` -## NVCC - -```toml -switches = [ - '', - '--use_fast_math', - '--fmad=false', - '--fmad=true', - '--ftz=false', - '--ftz=true', - '--prec-div=false', - '--prec-div=true', - '--prec-sqrt=false', - '--prec-sqrt=true', -] -``` - [Prev](flit-configuration-file.md) | [Table of Contents](README.md) diff --git a/documentation/flit-configuration-file.md b/documentation/flit-configuration-file.md index 72b88e03..a1f79cc4 100644 --- a/documentation/flit-configuration-file.md +++ b/documentation/flit-configuration-file.md @@ -21,20 +21,49 @@ to delete or comment out the values, which will cause the default values to be used._ ```toml -[database] +[hosts] +name = 'my.hostname.com' +flit_path = '/usr/bin/flit' +config_dir = '/usr/share/flit/config' +``` + +When you initialize your project with `flit init`, these fields will be +populated with values corresponding to the values on your machine: + +- `name`: hostname of the current machine +- `flit_path`: will be initialized to the path of the `flit.py` script or its + symbolic link +- `config_dir`: directory containing default configuration values. Either the + one installed (if using flit from an install) or the one from the flit + repository (if running directly from a git clone). + +**Note:** if these fields are omitted, then the values of the current machine +and `flit` executable will be used instead. This is useful if you intend to +run your tests on multiple machines and if you want to allow using different +paths for the flit executable and configuration. +The `flit_path` variable is put into the generated `Makefile` so that it can +update itself. + + +```toml +[database] type = 'sqlite3' filepath = 'results.sqlite' ``` -Above we specify the information for the database. Postgres used to be -supported, but has been replaced with SQLite3. For now, only `sqlite3` is -supported for the `type`. The only thing that needs to be specified is -`filepath`, which can be a relative or absolute path. +Above we specify the information for the database. We only support +[SQLite3](https://sqlite.org) databases currently. Therefore, there exists +only one valid value for `type`, which is `sqlite3`. If you have need of using +something other than SQLite3, please submit an +[issue](https://github.com/PRUNERS/FLiT/issues). + +The `filepath` field can be relative or absolute and specifies where to store +results for a full flit run. + ```toml [run] - timing = true timing_loops = -1 timing_repeats = 3 @@ -72,78 +101,99 @@ tests employ MPI, it is the test creator's responsibility to ensure that the test produces identical results every time. ```toml -[[hosts]] - -name = 'my.hostname.com' -flit_path = '/usr/bin/flit' -config_dir = 'project/flit-tests' -``` - -Now we start specifying information of the first host called `my.hostname.com`. -The `flit_path` is the path of the `flit` command-line tool at this host. The -`config_dir` is the directory where this configuration file is located on the -host. For now, it is expected that each machine already has a copy of the -tests with the same configuration file and that their location is documented -here. If needed, this may be revisited. - -For any variable under `hosts` that specifies a relative path, the relative -path is always with respect to the user's home directory. - -```toml -[hosts.dev_build] - +[dev_build] compiler_name = 'g++' optimization_level = '-O2' switches = '-funsafe-math-optimizations' ``` -Each host has a developer build that can be performed. The purpose of the -developer build is to try out the tests that you have developed without -committing yourself to a full FLiT run. +The `[dev_build]` section describes the developer build, or the configurations +for the `make dev` target from the autogenerated `Makefile` (which generates +the `devrun` test executable). + +- `compiler_name`: A name matching the `name` field from the `[[compiler]]` array + section. This will pull in the settings from that `compiler` for the + developer build. +- `optimization_level`: The optimization level to use in compiling `devrun` +- `switches`: Additional flags to use in compiling `devrun` -The `compiler` field here needs to match the `name` of one of the compilers -specified later in the `[[hosts.compilers]]` list. The `optimization_level` -and `switches` need not be in the `optimization_levels` and `switches` for the -compiler with the matching name. +The purpose of the developer build is to try out the tests that you have +developed without committing yourself to a full FLiT run. True, that can also +be done with the `gtrun` executable (seen below), but it may be helpful to +experiment with a build that contains higher optimizations, such as when you +are searching for inputs that demonstrate variability with a particular flag. -This does exactly one compilation with the compiler and flags that are -specified. This compilation is done using `make dev` and generates an -executable called `devrun`. You can call +For the generated `devrun` executable, you can call ```bash ./devrun --help ``` -to see the options available for the test executable, such as only running a -particular test or outputting debugging information. +to see the options available, such as only running a particular test or +outputting debugging information. ```toml -[hosts.ground_truth] - +[ground_truth] compiler_name = 'g++' optimization_level = '-O0' switches = '' ``` -Each host has a ground truth run to use as comparisons when doing analysis. -The `compiler` field here needs to match the `name` of one of the compilers specified -later in the `[[hosts.compilers]]` list. The `optimization_level` and -`switches` need not be in the `optimization_levels` and `switches` for -the compiler with the matching name. +The `[ground_truth]` build is intended to be the baseline for all other +compilations. Here, you should place the compilation that you trust, as it +will become a comparison for all other test results. + +The fields here are synonymous with those in the `[dev_build]` + +This configuration specifies the compilation of the `gtrun` executable created +from the `make gt` target in the autogenerated `Makefile`. The compiled +`gtrun` executable has the exact same command-line interface as the `devrun` +executable. ```toml - [[hosts.compilers]] +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' +``` + +Here we specify the first compiler. + +- `binary`: The executable for this compiler. The one seen above is a simple + name and will use the executable `g++` from the system `PATH`. You can + alternatively specify an absolute path or a relative path. If you specify a + relative path, it will be relative to the directory containing + `flit-config.toml`, which is the top-level directory for your FLiT tests. +- `name`: A human-readable unique name for this compiler. This could be + something like `gcc-7.4`. It is used in the `[dev_build]` and + `[ground_truth]` sections to refer to this compiler. +- `type`: The type of compiler. The supported types are `gcc`, `clang` and + `intel`. If you need an additional type supported, please submit an + [issue](https://github.com/PRUNERS/FLiT/issues). + +Note that the section has two square brackets around it instead of one. This +indicates that it is an array and subsequent instances of `[[compiler]]` will +add to that array. + +If the `[[compiler]]` section is omitted, then the default values will be used +which includes the one from above named `g++` and the following two: - binary = 'g++' - name = 'g++' +```toml +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' + +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' ``` -Here we specify the first compiler for the first host. Since binary here is a -simple name, it will get the executable `g++` from the system `PATH`. If you -really mean you want to have a compiler that is located in your home directory, -you can do `./g++`. The name field is a human-readable unique name for this -compiler. For example, the binary field can have an absolute path where the -name can be something like `gcc-7.4`. +Do not worry if you do not have all of the compilers on your system, they will +be silently ignored if they are not found in the PATH. This is to allow you to +use the default values safely. + ## Full Configuration File @@ -151,47 +201,46 @@ Combining all of the above sections together, here is the full example (and default) configuration file: ```toml -[database] +[host] +name = 'my.hostname.com' +flit_path = '/usr/bin/flit' +config_dir = '/usr/share/flit/config' +[database] type = 'sqlite' filepath = 'results.sqlite' - [run] - timing = true timing_loops = -1 timing_repeats = 3 - enable_mpi = false mpirun_args = '' - -[[hosts]] - -name = 'my.hostname.com' -flit_path = '/usr/bin/flit' -config_dir = 'project/flit-tests' - - -[hosts.dev_build] - +[dev_build] compiler_name = 'g++' optimization_level = '-O2' switches = '-funsafe-math-optimizations' - -[hosts.ground_truth] - +[ground_truth] compiler_name = 'g++' optimization_level = '-O0' switches = '' +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' - [[hosts.compilers]] +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' - binary = 'g++' - name = 'g++' +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' ``` diff --git a/scripts/flitcli/config/flit-default.toml.in b/scripts/flitcli/config/flit-default.toml.in index e79b6808..dc37017e 100644 --- a/scripts/flitcli/config/flit-default.toml.in +++ b/scripts/flitcli/config/flit-default.toml.in @@ -85,18 +85,22 @@ # General information [host] -# If you omit name, the system hostname will be used +# if you omit name, the system hostname will be used name = '{hostname}' + +# if you omit flit_path, the current flit executable will be used flit_path = '{flit_path}' + +# if you omit config_dir, it will be taken from the current flit executable config_dir = '{config_dir}' + [database] -# older versions of flit supported postgres. that has been removed. only -# sqlite is supported at the moment. +# only sqlite is supported, so this field can be safely omitted type = 'sqlite' -# if relative path, it is relative to the directory containing this +# if this is a relative path, it is relative to the directory containing this # configuration file. filepath = 'results.sqlite' @@ -124,18 +128,19 @@ enable_mpi = false mpirun_args = '' -# The settings for "make dev" +# The settings for "make dev", which generates the "devrun" executable [dev_build] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list + +# compiler_name must be found in the [[compiler]] list under the name attribute compiler_name = 'g++' optimization_level = '-O2' switches = '-funsafe-math-optimizations' -# The ground truth compilation to use in analysis, for "make gt" +# The ground truth compilation to use in analysis, for "make gt", which +# generates the "gtrun" executable [ground_truth] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list + +# compiler_name must be found in the [[compiler]] list under the name attribute compiler_name = 'g++' optimization_level = '-O0' switches = '' @@ -145,7 +150,7 @@ switches = '' # PATH). If you want to specify a compiler in the same directory as this # config file, prepend with a "./" (e.g. "./my-compiler") # - name: can be any string. Used to recognize in the other options such as -# dev_build and ground_truth +# in [dev_build] and [ground_truth] # - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') # Currently, only one of each type may be specified. # Note that these are all defaulted to use g++, clang++, and icpc from the From dacf9062e8bf0f4072ffc81f88af29d53bb52d54 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 27 Nov 2018 10:13:03 -0700 Subject: [PATCH 162/196] available-compiler-flags.md: put caveat at top put an explanatory section saying future feature --- documentation/available-compiler-flags.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/documentation/available-compiler-flags.md b/documentation/available-compiler-flags.md index c4de4c09..64006a45 100644 --- a/documentation/available-compiler-flags.md +++ b/documentation/available-compiler-flags.md @@ -11,7 +11,18 @@ Convenient TOML lists: * [GCC](#gcc) * [Clang](#clang) * [Intel](#intel) -* [NVCC](#nvcc) + +Currently, the configuration file does not specify the flags and optimization +levels to use. We plan to change this in future updates. Consider the +documentation below to relate to future desired features. See +[issue-119](https://github.com/PRUNERS/FLiT/issues/119). + +The flags below are still useful to understand because they are the current +flags that are hard-coded into the autogenerated `Makefile`. Below is a +comprehensive list of switches used. + + +## All Flags In your configuration file `flit-config.toml` (see [FLiT Configuration File](flit-configuration-file.md)), you specify compiler flags for each of the From af4a36756b348a421c6462725fa267d529e021ed Mon Sep 17 00:00:00 2001 From: JJ Garzella Date: Wed, 28 Nov 2018 05:18:13 +0000 Subject: [PATCH 163/196] Generalize flag indirection Restored the level of indirection where each flag is stored in a variable. From now on, DEFFLAGS is automatically included by FLiT, as this is almost always desired and it's hard to get out of the toml file the way the Python code works now. To process the flags at the Python level, dictionaries are used, which has the side effect of causing FLiT to run the flags in whatever order the Python dictionary decides to give it. This feels weird with optimization levels, but all the same tests still get run. --- data/Makefile.in | 142 +++----------------- scripts/flitcli/config/flit-default.toml.in | 63 ++++++++- scripts/flitcli/flit_update.py | 31 ++++- 3 files changed, 105 insertions(+), 131 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index dd36fcf8..74574c40 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -247,136 +247,28 @@ endif # more comp settings, taken from here: # https://software.intel.com/sites/default/files/article/326703/fp-control-2012-08.pdf -SWITCHES_GCC := {switches_gcc} -SWITCHES_CLANG := {switches_clang} -SWITCHES_INTEL := {switches_intel} +# individual flags + +## optls + +{opcodes_definitions} + +## switches + +DEFFLAGS := +{switches_definitions} OPCODES_GCC := {opcodes_gcc} OPCODES_CLANG := {opcodes_clang} OPCODES_INTEL := {opcodes_intel} -#individual flags -## optls - -#O0 := -O0 -#O1 := -O1 -#O2 := -O2 -#O3 := -O3 -# -##switches -# -#ASSOCMATH := -fassociative-math -#AVX := -mavx -#COMPTRANS := -mp1 -#DEFFLAGS := -#DISFMA := -no-fma -#ENAFMA := -fma -#FASTEXPREC := -fexcess-precision=fast -#FASTM := -ffast-math -#FINMATH := -ffinite-math-only -#FLUSHDEN := -ftz -#FMAGCC := -mavx2 -mfma -#FMAICC := -march=core-avx2 -#FORTRULES := -fcx-fortran-rules -#FPCONT := -ffp-contract=on -#FPMODDBL := -fp-model=double -#FPMODEXC := -fp-model=except -#FPMODEXT := -fp-model=extended -#FPMODFST1 := -fp-model fast=1 -#FPMODFST2 := -fp-model fast=2 -#FPMODPRE := -fp-model=precise -#FPMODSRC := -fp-model=source -#FPMODSTR := -fp-model=strict -#FPTRAP := -fp-trap=common -#FSTORE := -ffloat-store -#LIMITEDRANGE := -fcx-limited-range -#MCONSTS := -fmerge-all-constants -#NOFLUSHDEN := -no-ftz -#NOPRECDIV := -no-prec-div -#NOTRAP := -fno-trapping-math -#PRECDIV := -prec-div -#RECIPMATH := -freciprocal-math -#ROUNDINGMATH := -frounding-math -#ROUNDUSR := -fp-port -#SIGNALNAN := -fsignaling-nans -#SINGLEPRECCONST := -fsingle-precision-constant -#SSE := -mfpmath=sse -mtune=native -#STDEXPREC := -fexcess-precision=standard -#UNSOPTS := -funsafe-math-optimizations -#USEFASTM := --use_fast_math -# -## Collections -# -#OPCODES := O0 O1 O2 O3 -# -## NOTE: gcc disables ASSOCMATH @ O0 -#SWITCHES_GCC += ASSOCMATH -#SWITCHES_GCC += AVX -#SWITCHES_GCC += DEFFLAGS -#SWITCHES_GCC += FASTEXPREC -#SWITCHES_GCC += FINMATH -#SWITCHES_GCC += FMAGCC -#SWITCHES_GCC += FORTRULES -#SWITCHES_GCC += FPCONT -#SWITCHES_GCC += FSTORE -#SWITCHES_GCC += LIMITEDRANGE -#SWITCHES_GCC += MCONSTS -#SWITCHES_GCC += NOTRAP -#SWITCHES_GCC += RECIPMATH -#SWITCHES_GCC += ROUNDINGMATH -#SWITCHES_GCC += SIGNALNAN -#SWITCHES_GCC += SSE -#SWITCHES_GCC += UNSOPTS -# -##NOTE: Clang not honoring ASSOCMATH (issues warning with 3.9) -## see: https://llvm.org/bugs/show_bug.cgi?id=27372 -# -#SWITCHES_CLANG += ASSOCMATH -#SWITCHES_CLANG += AVX -#SWITCHES_CLANG += DEFFLAGS -#SWITCHES_CLANG += FASTEXPREC -#SWITCHES_CLANG += FINMATH -#SWITCHES_CLANG += FMAGCC -#SWITCHES_CLANG += FMAICC -#SWITCHES_CLANG += FPCONT -#SWITCHES_CLANG += FSTORE -#SWITCHES_CLANG += MCONSTS -#SWITCHES_CLANG += NOTRAP -#SWITCHES_CLANG += RECIPMATH -#SWITCHES_CLANG += ROUNDINGMATH -#SWITCHES_CLANG += SIGNALNAN -#SWITCHES_CLANG += SINGLEPRECCONST -#SWITCHES_CLANG += SSE -#SWITCHES_CLANG += STDEXPREC -#SWITCHES_CLANG += UNSOPTS -# -#SWITCHES_INTEL += AVX -#SWITCHES_INTEL += COMPTRANS -#SWITCHES_INTEL += DEFFLAGS -#SWITCHES_INTEL += DISFMA -#SWITCHES_INTEL += ENAFMA -#SWITCHES_INTEL += FLUSHDEN -#SWITCHES_INTEL += FMAGCC -#SWITCHES_INTEL += FMAICC -#SWITCHES_INTEL += FPMODDBL -#SWITCHES_INTEL += FPMODEXT -#SWITCHES_INTEL += FPMODFST1 -#SWITCHES_INTEL += FPMODFST2 -#SWITCHES_INTEL += FPMODPRE -#SWITCHES_INTEL += FPMODSRC -#SWITCHES_INTEL += FPMODSTR -#SWITCHES_INTEL += FSTORE -#SWITCHES_INTEL += LIMITEDRANGE -#SWITCHES_INTEL += MCONSTS -#SWITCHES_INTEL += NOFLUSHDEN -#SWITCHES_INTEL += NOPRECDIV -#SWITCHES_INTEL += PRECDIV -#SWITCHES_INTEL += ROUNDINGMATH -#SWITCHES_INTEL += ROUNDUSR -#SWITCHES_INTEL += SINGLEPRECCONST -#SWITCHES_INTEL += SSE -#SWITCHES_INTEL += USEFASTM +SWITCHES_GCC := DEFFLAGS +SWITCHES_CLANG := DEFFLAGS +SWITCHES_INTEL := DEFFLAGS +SWITCHES_GCC += {switches_gcc} +SWITCHES_CLANG += {switches_clang} +SWITCHES_INTEL += {switches_intel} ########################################################## # @@ -453,7 +345,7 @@ TARGET_OUTS := # @param 1: compiler variable name (e.g. CLANG) # @param 2: optimization level variable name (e.g. O2) -# @param 3: switches variable name (e.g. USEFASTM) +# @param 3: switches variable name (e.g. --use_fast_math) define RECURSION_RULE TARGETS += $$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip $2) diff --git a/scripts/flitcli/config/flit-default.toml.in b/scripts/flitcli/config/flit-default.toml.in index b9f866c0..8ed61640 100644 --- a/scripts/flitcli/config/flit-default.toml.in +++ b/scripts/flitcli/config/flit-default.toml.in @@ -162,9 +162,24 @@ switches = '' '-O2', '-O3', ] + ## NOTE: gcc disables -fassociative-math @ O0 switches = [ + '-fassociative-math', + '-mavx', + '-fexcess-precision=fast', + '-ffinite-math-only', + '-mavx2 -mfma', + '-fcx-fortran-rules', + '-ffp-contract=on', + '-ffloat-store', + '-fcx-limited-range', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-mfpmath=sse -mtune=native', '-funsafe-math-optimizations', - '' ] [[hosts.compilers]] @@ -177,9 +192,26 @@ switches = '' '-O2', '-O3', ] + ##NOTE: Clang not honoring -fassociative-math (issues warning with 3.9) + ## see: https://llvm.org/bugs/show_bug.cgi?id=27372 switches = [ + '-fassociative-math', + '-mavx', + '-fexcess-precision=fast', + '-ffinite-math-only', + '-mavx2 -mfma', + '-march=core-avx2', + '-ffp-contract=on', + '-ffloat-store', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-fsingle-precision-constant', + '-mfpmath=sse -mtune=native', + '-fexcess-precision=standard', '-funsafe-math-optimizations', - '' ] [[hosts.compilers]] @@ -193,7 +225,30 @@ switches = '' '-O3', ] switches = [ - '-funsafe-math-optimizations', - '' + '-mavx', + '-mp1', + '-no-fma', + '-fma', + '-ftz', + '-mavx2 -mfma', + '-march=core-avx2', + '-fp-model=double', + '-fp-model=extended', + '-fp-model fast=1', + '-fp-model fast=2', + '-fp-model=precise', + '-fp-model=source', + '-fp-model=strict', + '-ffloat-store', + '-fcx-limited-range', + '-fmerge-all-constants', + '-no-ftz', + '-no-prec-div', + '-prec-div', + '-frounding-math', + '-fp-port', + '-fsingle-precision-constant', + '-mfpmath=sse -mtune=native', + '--use_fast_math', ] diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index c86bcf6e..2680d6d6 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -92,6 +92,23 @@ brief_description = 'Updates the Makefile based on flit-config.toml' +def flag_name(flag): + name = flag.upper() + if name == '': + print('Ignoring empty flag.') + return '' + if name[0] == '-': + name = name[1:] + name = name.replace(' ', '_') + name = name.replace('-', '_') + name = name.replace('=', '_') + return name + +def generate_assignments(flags): + name_assignments = [name + ' := ' + flags[name] + for name in flags.keys() if name != ''] + return '\n'.join(name_assignments) + def main(arguments, prog=sys.argv[0]): parser = argparse.ArgumentParser( prog=prog, @@ -156,14 +173,22 @@ def main(arguments, prog=sys.argv[0]): base_compilers = {x: None for x in supported_compiler_types} compiler_flags = {x: None for x in supported_compiler_types} compiler_op_levels = {x: None for x in supported_compiler_types} + all_op_levels = {} + all_switches = {} for compiler in host['compilers']: assert compiler['type'] in supported_compiler_types, \ 'Unsupported compiler type: {}'.format(compiler['type']) assert base_compilers[compiler['type']] is None, \ 'You can only specify one of each type of compiler.' base_compilers[compiler['type']] = compiler['binary'] - compiler_flags[compiler['type']] = compiler['switches'] - compiler_op_levels[compiler['type']] = compiler['optimization_levels'] + + switches = {flag_name(flag): flag for flag in compiler['switches']} + compiler_flags[compiler['type']] = switches.keys() + all_switches.update(switches) + + op_levels = {flag_name(flag): flag for flag in compiler['optimization_levels']} + compiler_op_levels[compiler['type']] = op_levels.keys() + all_op_levels.update(op_levels) test_run_args = '' if not projconf['run']['timing']: @@ -192,6 +217,8 @@ def main(arguments, prog=sys.argv[0]): 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', 'mpirun_args': projconf['run']['mpirun_args'], 'compilers': ' '.join([c.upper() for c in given_compilers]), + 'opcodes_definitions': generate_assignments(all_op_levels), + 'switches_definitions': generate_assignments(all_switches), } replacements.update({key + '_compiler': val for key, val in base_compilers.items()}) From b2d2327b85f0c1ef1af5b78bab2c1c87336e2a7f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 27 Nov 2018 14:33:20 -0700 Subject: [PATCH 164/196] flit_update: handle defaults for compiler optl and switches The Makefile still has them hard-coded, but this change at least makes it possible to have the switches in the flit-config.toml file and to have them be populated and checked correctly, all without breaking existing tests. --- documentation/available-compiler-flags.md | 28 ++- .../config/flit-default-future.toml.in | 219 +++++++++++++----- scripts/flitcli/config/flit-default.toml.in | 91 +++++--- scripts/flitcli/flit_update.py | 167 ++++++++----- 4 files changed, 346 insertions(+), 159 deletions(-) diff --git a/documentation/available-compiler-flags.md b/documentation/available-compiler-flags.md index 64006a45..a7084176 100644 --- a/documentation/available-compiler-flags.md +++ b/documentation/available-compiler-flags.md @@ -12,15 +12,6 @@ Convenient TOML lists: * [Clang](#clang) * [Intel](#intel) -Currently, the configuration file does not specify the flags and optimization -levels to use. We plan to change this in future updates. Consider the -documentation below to relate to future desired features. See -[issue-119](https://github.com/PRUNERS/FLiT/issues/119). - -The flags below are still useful to understand because they are the current -flags that are hard-coded into the autogenerated `Makefile`. Below is a -comprehensive list of switches used. - ## All Flags @@ -73,9 +64,15 @@ For your convenience, here are toml-style lists that can be copied into your ## GCC +**Note:** in some versions of python-toml, there is a parsing bug when a list +has an empty string in the middle. So simply put it at the end without a +comma. This has been fixed in the latest version of python-toml. + +You will likely want the empty string in your search space as it represents the +absence of any switches. + ```toml -switches = [ - '', +switches_list = [ '-fassociative-math', '-fcx-fortran-rules', '-fcx-limited-range', @@ -92,14 +89,14 @@ switches = [ '-mavx', '-mavx2 -mfma', '-mfpmath=sse -mtune=native', + '' ] ``` ## Clang ```toml -switches = [ - '', +switches_list = [ '-fassociative-math', '-fexcess-precision=fast', '-fexcess-precision=standard', @@ -117,14 +114,14 @@ switches = [ '-mavx', '-mavx2 -mfma', '-mfpmath=sse -mtune=native', + '' ] ``` ## Intel ```toml -switches = [ - '', +switches_list = [ '--use_fast_math', '-fcx-limited-range', '-ffloat-store', @@ -151,6 +148,7 @@ switches = [ '-no-ftz', '-no-prec-div', '-prec-div', + '' ] ``` diff --git a/scripts/flitcli/config/flit-default-future.toml.in b/scripts/flitcli/config/flit-default-future.toml.in index a0873550..16bfe3e8 100644 --- a/scripts/flitcli/config/flit-default-future.toml.in +++ b/scripts/flitcli/config/flit-default-future.toml.in @@ -82,13 +82,25 @@ # Autogenerated by "flit init" # flit version {flit_version} +# General information +[host] + +# if you omit name, the system hostname will be used +name = '{hostname}' + +# if you omit flit_path, the current flit executable will be used +flit_path = '{flit_path}' + +# if you omit config_dir, it will be taken from the current flit executable +config_dir = '{config_dir}' + + [database] -# older versions of flit supported postgres. that has been removed. only -# sqlite is supported at the moment. +# only sqlite is supported, so this field can be safely omitted type = 'sqlite' -# if relative path, it is relative to the directory containing this +# if this is a relative path, it is relative to the directory containing this # configuration file. filepath = 'results.sqlite' @@ -106,70 +118,163 @@ timing_loops = -1 # will be kept. timing_repeats = 3 +# The tests can be run with MPI to test MPI applications +# Warning: FLiT assumes tests are deterministic. It is your responsability to +# ensure that your test will always produce the same result even using +# MPI. +# The mpirun_args are for any flags passed to mpirun. For example, you can do +# mpirun_args = '-n 16 --verbose' +enable_mpi = false +mpirun_args = '' -# For now, only the first host is supported, all others are ignored -[[hosts]] -# TODO: add documentation here for each element. +# The settings for "make dev", which generates the "devrun" executable +[dev_build] -name = '{hostname}' -flit_path = '{flit_path}' -config_dir = '{config_dir}' - -# The settings for "make dev" -[hosts.dev_build] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list +# compiler_name must be found in the [[compiler]] list under the name attribute +# The optimization level and switches need not match those found in the +# associated [[compiler]] compiler_name = 'g++' optimization_level = '-O2' switches = '-funsafe-math-optimizations' -# The ground truth compilation to use in analysis, for "make gt" -[hosts.ground_truth] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list +# The ground truth compilation to use in analysis, for "make gt", which +# generates the "gtrun" executable +[ground_truth] + +# compiler_name must be found in the [[compiler]] list under the name attribute +# The optimization level and switches need not match those found in the +# associated [[compiler]] compiler_name = 'g++' optimization_level = '-O0' switches = '' - # This host's list of compilers. - # For now, only used for hosts.ground_truth and hosts.dev_build. - # TODO: use this list to generate the Makefile - [[hosts.compilers]] - - # TODO: figure out how to specify path for each host machine - # TODO: what if the compilers list is part of the host? - - # binary can be an absolute path, relative path, or binary name (found in - # PATH). If you want to specify a compiler in the same directory as this - # config file, prepend with a "./" (e.g. "./my-compiler") - binary = 'g++' - # TODO: this is not yet used... - # It is recommended to include version number in the name. This is how the - # compiler will be recognized in the results, and subsequently in the - # database and analysis. - name = 'g++' - # TODO: implement these supported types - # There are a few supported types: [ gcc, intel, clang ] - type = 'gcc' - optimization_levels = [ - '-O0', - '-O1', - '-O2', - '-O3', - #'-Ofast', - #'-O...' ? - ] - # Note: in some versions of python-toml, there is a parsing bug when a list - # has an empty string in the middle. So simply put it at the end without a - # comma. This has been fixed in the latest version of python-toml. - switches_list = [ - '-fassociative-math', - '-mavx', - '-mp1', - '-mavx2 -mfma', - '' - # ... - ] +# List of compilers. +# - binary: can be an absolute path, relative path, or binary name (found in +# PATH). If you want to specify a compiler in the same directory as this +# config file, prepend with a "./" (e.g. "./my-compiler") +# - name: can be any string. Used to recognize in the other options such as +# in [dev_build] and [ground_truth] +# - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') +# Currently, only one of each type may be specified. +# Note that these are all defaulted to use g++, clang++, and icpc from the +# PATH. +# If you specify any one compiler, then these defaults are erased. If you +# specify no compiler, then these defaults take effect. + +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' +# search space of optimization levels +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +# search space of compiler switches. +# Note: in some versions of python-toml, there is a parsing bug when a list +# has an empty string in the middle. So simply put it at the end without a +# comma. This has been fixed in the latest version of python-toml. +switches_list = [ + '-fassociative-math', + '-fcx-fortran-rules', + '-fcx-limited-range', + '-fexcess-precision=fast', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-funsafe-math-optimizations', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] + +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' +# search space of optimization levels +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +# search space of compiler switches. +# Note: in some versions of python-toml, there is a parsing bug when a list +# has an empty string in the middle. So simply put it at the end without a +# comma. This has been fixed in the latest version of python-toml. +switches_list = [ + '-fassociative-math', + '-fexcess-precision=fast', + '-fexcess-precision=standard', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-fsingle-precision-constant', + '-funsafe-math-optimizations', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' +# search space of optimization levels +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +# search space of compiler switches. +# Note: in some versions of python-toml, there is a parsing bug when a list +# has an empty string in the middle. So simply put it at the end without a +# comma. This has been fixed in the latest version of python-toml. +switches_list = [ + '--use_fast_math', + '-fcx-limited-range', + '-ffloat-store', + '-fma', + '-fmerge-all-constants', + '-fp-model fast=1', + '-fp-model fast=2', + '-fp-model=double', + '-fp-model=except', + '-fp-model=extended', + '-fp-model=precise', + '-fp-model=source', + '-fp-model=strict', + '-fp-port', + '-frounding-math', + '-fsingle-precision-constant', + '-ftz', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '-mp1', + '-no-fma', + '-no-ftz', + '-no-prec-div', + '-prec-div', + '' +] diff --git a/scripts/flitcli/config/flit-default.toml.in b/scripts/flitcli/config/flit-default.toml.in index a24b60ba..5e44f117 100644 --- a/scripts/flitcli/config/flit-default.toml.in +++ b/scripts/flitcli/config/flit-default.toml.in @@ -132,6 +132,8 @@ mpirun_args = '' [dev_build] # compiler_name must be found in the [[compiler]] list under the name attribute +# The optimization level and switches need not match those found in the +# associated [[compiler]] compiler_name = 'g++' optimization_level = '-O2' switches = '-funsafe-math-optimizations' @@ -141,6 +143,8 @@ switches = '-funsafe-math-optimizations' [ground_truth] # compiler_name must be found in the [[compiler]] list under the name attribute +# The optimization level and switches need not match those found in the +# associated [[compiler]] compiler_name = 'g++' optimization_level = '-O0' switches = '' @@ -162,98 +166,117 @@ switches = '' binary = 'g++' name = 'g++' type = 'gcc' +# search space of optimization levels optimization_levels = [ '-O0', '-O1', '-O2', '-O3', ] -## NOTE: gcc disables -fassociative-math @ O0 -switches = [ +# search space of compiler switches. +# Note: in some versions of python-toml, there is a parsing bug when a list +# has an empty string in the middle. So simply put it at the end without +# a comma. This has been fixed in the latest version of python-toml. +# Note: gcc disables -fassociative-math @ O0 +switches_list = [ '-fassociative-math', - '-mavx', + '-fcx-fortran-rules', + '-fcx-limited-range', '-fexcess-precision=fast', '-ffinite-math-only', - '-mavx2 -mfma', - '-fcx-fortran-rules', - '-ffp-contract=on', '-ffloat-store', - '-fcx-limited-range', + '-ffp-contract=on', '-fmerge-all-constants', '-fno-trapping-math', '-freciprocal-math', '-frounding-math', '-fsignaling-nans', - '-mfpmath=sse -mtune=native', '-funsafe-math-optimizations', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' ] [[compiler]] binary = 'clang++' name = 'clang++' type = 'clang' +# search space of optimization levels optimization_levels = [ '-O0', '-O1', '-O2', '-O3', ] -##NOTE: Clang not honoring -fassociative-math (issues warning with 3.9) -## see: https://llvm.org/bugs/show_bug.cgi?id=27372 -switches = [ +# search space of compiler switches. +# Note: in some versions of python-toml, there is a parsing bug when a list +# has an empty string in the middle. So simply put it at the end without +# a comma. This has been fixed in the latest version of python-toml. +# Note: Clang not honoring -fassociative-math (issues warning with 3.9) +# see: https://llvm.org/bugs/show_bug.cgi?id=27372 +switches_list = [ '-fassociative-math', - '-mavx', '-fexcess-precision=fast', + '-fexcess-precision=standard', '-ffinite-math-only', - '-mavx2 -mfma', - '-march=core-avx2', - '-ffp-contract=on', '-ffloat-store', + '-ffp-contract=on', '-fmerge-all-constants', '-fno-trapping-math', '-freciprocal-math', '-frounding-math', '-fsignaling-nans', '-fsingle-precision-constant', - '-mfpmath=sse -mtune=native', - '-fexcess-precision=standard', '-funsafe-math-optimizations', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' ] [[compiler]] binary = 'icpc' name = 'icpc' type = 'intel' +# search space of optimization levels optimization_levels = [ '-O0', '-O1', '-O2', '-O3', ] -switches = [ - '-mavx', - '-mp1', - '-no-fma', +# search space of compiler switches. +# Note: in some versions of python-toml, there is a parsing bug when a list +# has an empty string in the middle. So simply put it at the end without +# a comma. This has been fixed in the latest version of python-toml. +switches_list = [ + '--use_fast_math', + '-fcx-limited-range', + '-ffloat-store', '-fma', - '-ftz', - '-mavx2 -mfma', - '-march=core-avx2', - '-fp-model=double', - '-fp-model=extended', + '-fmerge-all-constants', '-fp-model fast=1', '-fp-model fast=2', + '-fp-model=double', + '-fp-model=except', + '-fp-model=extended', '-fp-model=precise', '-fp-model=source', '-fp-model=strict', - '-ffloat-store', - '-fcx-limited-range', - '-fmerge-all-constants', - '-no-ftz', - '-no-prec-div', - '-prec-div', - '-frounding-math', '-fp-port', + '-frounding-math', '-fsingle-precision-constant', + '-ftz', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', '-mfpmath=sse -mtune=native', - '--use_fast_math', + '-mp1', + '-no-fma', + '-no-ftz', + '-no-prec-div', + '-prec-div', + '' ] diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 61560ebb..5dde4302 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -91,6 +91,90 @@ import flitutil brief_description = 'Updates the Makefile based on flit-config.toml' +_supported_compiler_types = ('clang', 'gcc', 'intel') + +def parse_args(arguments, prog=sys.argv[0]): + 'Return parsed arugments' + parser = argparse.ArgumentParser( + prog=prog, + description=''' + Updates the Makefile based on flit-config.toml. The Makefile + is autogenerated and should not be modified manually. If there + are things you want to replace or add, you can use custom.mk + which is included at the end of the Makefile. So, you may add + rules, add to variables, or override variables. + ''', + ) + parser.add_argument('-C', '--directory', default='.', + help='The directory to initialize') + args = parser.parse_args(arguments) + return args + +def load_projconf(directory): + ''' + Loads and returns the project configuration found in the given tomlfile. + This function checks for validity of that tomlfile and fills it with + default values. + + @param directory: directory containing 'flit-config.toml'. + + @return project configuration as a struct of dicts and lists depending on + the structure of the given tomlfile. + ''' + tomlfile = os.path.join(directory, 'flit-config.toml') + try: + projconf = toml.load(tomlfile) + except FileNotFoundError: + print('Error: {0} not found. Run "flit init"'.format(tomlfile), + file=sys.stderr) + raise + + defaults = flitutil.get_default_toml() + + if 'compiler' in projconf: + assert isinstance(projconf['compiler'], list), \ + 'flit-config.toml improperly configured, ' \ + 'needs [[compiler]] section' + + default_type_map = {c['type']: c for c in defaults['compiler']} + type_map = {} # type -> compiler + name_map = {} # name -> compiler + for compiler in projconf['compiler']: + + # make sure each compiler has a name, type, and binary + for field in ('name', 'type', 'binary'): + assert field in compiler, \ + 'flit-config.toml: compiler "{0}"'.format(compiler) + \ + ' is missing the "{0}" field'.format(field) + + # check that the type is valid + assert compiler['type'] in _supported_compiler_types, \ + 'flit-config.toml: unsupported compiler type "{0}"' \ + .format(compiler['type']) + + # check that we only have one of each type specified + assert compiler['type'] not in type_map, \ + 'flit-config.toml: cannot have multiple compilers of the ' \ + 'same type ({0})'.format(compiler['type']) + type_map[compiler['type']] = compiler + + # check that we only have one of each name specified + assert compiler['name'] not in name_map, \ + 'flit-config.toml: cannot have multiple compilers of the ' \ + 'same name ({0})'.format(compiler['name']) + name_map[compiler['name']] = compiler + + # if optimization_levels or switches_list are missing for any + # compiler, put in the default flags for that compiler + default = default_type_map[compiler['type']] + for field in ('optimization_levels', 'switches_list'): + if field not in compiler: + compiler[field] = default[field] + + # Fill in the rest of the default values + flitutil.fill_defaults(projconf, defaults) + + return projconf def flag_name(flag): name = flag.upper() @@ -111,28 +195,15 @@ def generate_assignments(flags): def main(arguments, prog=sys.argv[0]): 'Main logic here' - parser = argparse.ArgumentParser( - prog=prog, - description=''' - Updates the Makefile based on flit-config.toml. The Makefile - is autogenerated and should not be modified manually. If there - are things you want to replace or add, you can use custom.mk - which is included at the end of the Makefile. So, you may add - rules, add to variables, or override variables. - ''', - ) - parser.add_argument('-C', '--directory', default='.', - help='The directory to initialize') - args = parser.parse_args(arguments) + args = parse_args(arguments, prog=prog) - tomlfile = os.path.join(args.directory, 'flit-config.toml') try: - projconf = toml.load(tomlfile) + projconf = load_projconf(args.directory) except FileNotFoundError: - print('Error: {0} not found. Run "flit init"'.format(tomlfile), - file=sys.stderr) return 1 - flitutil.fill_defaults(projconf) + except AssertionError as ex: + print('Error: ' + ex.args[0], file=sys.stderr) + return 1 makefile = os.path.join(args.directory, 'Makefile') if os.path.exists(makefile): @@ -141,52 +212,42 @@ def main(arguments, prog=sys.argv[0]): print('Creating {0}'.format(makefile)) dev_build = projconf['dev_build'] - dev_compiler_name = dev_build['compiler_name'] - dev_optl = dev_build['optimization_level'] - dev_switches = dev_build['switches'] matching_dev_compilers = [x for x in projconf['compiler'] - if x['name'] == dev_compiler_name] + if x['name'] == dev_build['compiler_name']] assert len(matching_dev_compilers) > 0, \ - 'Compiler name {0} not found'.format(dev_compiler_name) + 'Compiler name {0} not found'.format(dev_build['compiler_name']) assert len(matching_dev_compilers) < 2, \ - 'Multiple compilers with name {0} found'.format(dev_compiler_name) - dev_compiler_bin = matching_dev_compilers[0]['binary'] - #if '/' in dev_compiler_bin: - # dev_compiler_bin = os.path.realpath(dev_compiler_bin) + 'Multiple compilers with name {0} found' \ + .format(dev_build['compiler_name']) ground_truth = projconf['ground_truth'] - gt_compiler_name = ground_truth['compiler_name'] - gt_optl = ground_truth['optimization_level'] - gt_switches = ground_truth['switches'] matching_gt_compilers = [x for x in projconf['compiler'] - if x['name'] == gt_compiler_name] - assert len(matching_dev_compilers) > 0, \ - 'Compiler name {0} not found'.format(gt_compiler_name) - assert len(matching_dev_compilers) < 2, \ - 'Multiple compilers with name {0} found'.format(gt_compiler_name) - # TODO: use the compiler mnemonic rather than the path - gt_compiler_bin = matching_gt_compilers[0]['binary'] - #if '/' in dev_compiler_bin: - # gt_compiler_bin = os.path.realpath(gt_compiler_bin) - - supported_compiler_types = ('clang', 'gcc', 'intel') - base_compilers = {x: None for x in supported_compiler_types} - compiler_flags = {x: None for x in supported_compiler_types} - compiler_op_levels = {x: None for x in supported_compiler_types} + if x['name'] == ground_truth['compiler_name']] + assert len(matching_gt_compilers) > 0, \ + 'Compiler name {0} not found'.format(ground_truth['compiler_name']) + assert len(matching_gt_compilers) < 2, \ + 'Multiple compilers with name {0} found' \ + .format(ground_truth['compiler_name']) + + _supported_compiler_types = ('clang', 'gcc', 'intel') + base_compilers = {x: None for x in _supported_compiler_types} + compiler_flags = {x: None for x in _supported_compiler_types} + compiler_op_levels = {x: None for x in _supported_compiler_types} all_op_levels = {} all_switches = {} for compiler in projconf['compiler']: - assert compiler['type'] in supported_compiler_types, \ + assert compiler['type'] in _supported_compiler_types, \ 'Unsupported compiler type: {}'.format(compiler['type']) assert base_compilers[compiler['type']] is None, \ 'You can only specify one of each type of compiler.' base_compilers[compiler['type']] = compiler['binary'] - switches = {flag_name(flag): flag for flag in compiler['switches']} + switches = {flag_name(flag): flag for flag in compiler['switches_list']} compiler_flags[compiler['type']] = switches.keys() all_switches.update(switches) - op_levels = {flag_name(flag): flag for flag in compiler['optimization_levels']} + op_levels = {flag_name(flag): flag + for flag in compiler['optimization_levels']} compiler_op_levels[compiler['type']] = op_levels.keys() all_op_levels.update(op_levels) @@ -202,12 +263,12 @@ def main(arguments, prog=sys.argv[0]): given_compilers = [key for key, val in base_compilers.items() if val is not None] replacements = { - 'dev_compiler': dev_compiler_bin, - 'dev_optl': dev_optl, - 'dev_switches': dev_switches, - 'ground_truth_compiler': gt_compiler_bin, - 'ground_truth_optl': gt_optl, - 'ground_truth_switches': gt_switches, + 'dev_compiler': matching_dev_compilers[0]['binary'], + 'dev_optl': dev_build['optimization_level'], + 'dev_switches': dev_build['switches'], + 'ground_truth_compiler': matching_gt_compilers[0]['binary'], + 'ground_truth_optl': ground_truth['optimization_level'], + 'ground_truth_switches': ground_truth['switches'], 'flit_include_dir': conf.include_dir, 'flit_lib_dir': conf.lib_dir, 'flit_data_dir': conf.data_dir, From b7c432e114a76207e1eeb3069102389d53d92a9f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 27 Nov 2018 14:39:17 -0700 Subject: [PATCH 165/196] Fix python doctest findings --- gensrc/expression.py | 4 ---- scripts/flitcli/flit_bisect.py | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/gensrc/expression.py b/gensrc/expression.py index 0d55d27a..754f55b4 100644 --- a/gensrc/expression.py +++ b/gensrc/expression.py @@ -158,10 +158,6 @@ def __repr__(self): def random_expression(env, length, vars_only=False): ''' Generates a random mathematical expression as a string - - >>> env = Environment({'x'; Variable('x', 'int'}) - >>> random_expression(env, 3) - Expression((x + 3.25124) * x) ''' # Populate the expression with operations expr = Expression() diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index 17f1292a..f7028c21 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -309,10 +309,10 @@ def run_make(makefilename='Makefile', directory='.', verbose=False, ... except: ... pass ERROR:root:make error occurred. Here is the output: - make: Entering directory `...' + make: Entering directory ... hello - make: *** [default] Error 1 - make: Leaving directory `...' + make: *** [...default] Error 1 + make: Leaving directory ... Undo the logger configurations From 1ac371a275b9564876b887fa4a45136d15589029 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 08:29:53 -0700 Subject: [PATCH 166/196] Put in an empty function that generates the optimization levels and switches --- scripts/flitcli/flit_update.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 5dde4302..5548bb43 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -193,6 +193,37 @@ def generate_assignments(flags): for name in flags.keys() if name != ''] return '\n'.join(name_assignments) +def gen_optl_switches(compiler): + ''' + From the compiler specification, generate Makefile strings for optimization + levels and switches. + + @param compiler {'type': str, + 'optimization_levels': list, + 'switches_list': list} + + @return string to insert into the Makefile + + >>> gen_optl_switches({ + ... 'type': 'clang', + ... 'optimization_levels': ['-O2', '-O3'], + ... 'switches_list': ['-hi there', '-hello', ''] + ... }) + CLANG_OPTL01 := -O2 + CLANG_OPTL02 := -O3 + CLANG_SWITCH01 := -hi there + CLANG_SWITCH02 := -hello + CLANG_SWITCH03 := + OPCODES_CLANG := + OPCODES_CLANG += CLANG_OPTL01 + OPCODES_CLANG += CLANG_OPTL02 + SWITCHES_CLANG := + SWITCHES_CLANG += CLANG_SWITCH01 + SWITCHES_CLANG += CLANG_SWITCH02 + SWITCHES_CLANG += CLANG_SWITCH03 + ''' + pass + def main(arguments, prog=sys.argv[0]): 'Main logic here' args = parse_args(arguments, prog=prog) From b49bc26a0d2cea6eb5fec3001f843c87cf199232 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 11:08:44 -0700 Subject: [PATCH 167/196] docs: update flit-configuration-file.md Update it for new switches_list and optimization_levels fields --- documentation/flit-configuration-file.md | 181 +++++++++++++++++++++++ 1 file changed, 181 insertions(+) diff --git a/documentation/flit-configuration-file.md b/documentation/flit-configuration-file.md index a1f79cc4..e5718003 100644 --- a/documentation/flit-configuration-file.md +++ b/documentation/flit-configuration-file.md @@ -155,6 +155,31 @@ executable. binary = 'g++' name = 'g++' type = 'gcc' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +switches_list = [ + '-fassociative-math', + '-fcx-fortran-rules', + '-fcx-limited-range', + '-fexcess-precision=fast', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-funsafe-math-optimizations', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] ``` Here we specify the first compiler. @@ -170,6 +195,15 @@ Here we specify the first compiler. - `type`: The type of compiler. The supported types are `gcc`, `clang` and `intel`. If you need an additional type supported, please submit an [issue](https://github.com/PRUNERS/FLiT/issues). +- `optimization_levels`: List of optimization levels to search over. You may + remove from or add to this list. If you omit this list, the default list + will be used (which is the same as the one shown here). The defaults are + specific to the type of compiler. See below for the default list for the + other supported compilers. +- `switches_list`: List of switches to search over. You may remove from or add + to this list. If you omit this list, the default list will be used (which is + the same as the one shown here). The defaults are specific to the type of + compiler. See below for the default list for the other supported compilers. Note that the section has two square brackets around it instead of one. This indicates that it is an array and subsequent instances of `[[compiler]]` will @@ -183,11 +217,72 @@ which includes the one from above named `g++` and the following two: binary = 'clang++' name = 'clang++' type = 'clang' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +switches_list = [ + '-fassociative-math', + '-fexcess-precision=fast', + '-fexcess-precision=standard', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-fsingle-precision-constant', + '-funsafe-math-optimizations', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] [[compiler]] binary = 'icpc' name = 'icpc' type = 'intel' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +switches_list = [ + '--use_fast_math', + '-fcx-limited-range', + '-ffloat-store', + '-fma', + '-fmerge-all-constants', + '-fp-model fast=1', + '-fp-model fast=2', + '-fp-model=double', + '-fp-model=except', + '-fp-model=extended', + '-fp-model=precise', + '-fp-model=source', + '-fp-model=strict', + '-fp-port', + '-frounding-math', + '-fsingle-precision-constant', + '-ftz', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '-mp1', + '-no-fma', + '-no-ftz', + '-no-prec-div', + '-prec-div', + '' +] ``` Do not worry if you do not have all of the compilers on your system, they will @@ -231,16 +326,102 @@ switches = '' binary = 'g++' name = 'g++' type = 'gcc' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +switches_list = [ + '-fassociative-math', + '-fcx-fortran-rules', + '-fcx-limited-range', + '-fexcess-precision=fast', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-funsafe-math-optimizations', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] [[compiler]] binary = 'clang++' name = 'clang++' type = 'clang' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +switches_list = [ + '-fassociative-math', + '-fexcess-precision=fast', + '-fexcess-precision=standard', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-fsingle-precision-constant', + '-funsafe-math-optimizations', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] [[compiler]] binary = 'icpc' name = 'icpc' type = 'intel' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] +switches_list = [ + '--use_fast_math', + '-fcx-limited-range', + '-ffloat-store', + '-fma', + '-fmerge-all-constants', + '-fp-model fast=1', + '-fp-model fast=2', + '-fp-model=double', + '-fp-model=except', + '-fp-model=extended', + '-fp-model=precise', + '-fp-model=source', + '-fp-model=strict', + '-fp-port', + '-frounding-math', + '-fsingle-precision-constant', + '-ftz', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '-mp1', + '-no-fma', + '-no-ftz', + '-no-prec-div', + '-prec-div', + '' +] ``` From 44981e427775f9dda3401733dabb403348f99b76 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 13:42:33 -0700 Subject: [PATCH 168/196] flit-update: do not ignore empty switches Instead of having the empty switches always part of the search space handle it from the switches_list within flit-config.toml --- data/Makefile.in | 7 +++---- scripts/flitcli/flit_update.py | 16 +++++++--------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index f52de007..de89ec64 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -255,16 +255,15 @@ endif ## switches -DEFFLAGS := {switches_definitions} OPCODES_GCC := {opcodes_gcc} OPCODES_CLANG := {opcodes_clang} OPCODES_INTEL := {opcodes_intel} -SWITCHES_GCC := DEFFLAGS -SWITCHES_CLANG := DEFFLAGS -SWITCHES_INTEL := DEFFLAGS +SWITCHES_GCC := +SWITCHES_CLANG := +SWITCHES_INTEL := SWITCHES_GCC += {switches_gcc} SWITCHES_CLANG += {switches_clang} diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 5548bb43..fbab9e07 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -84,6 +84,7 @@ import argparse import os +import re import sys import toml @@ -177,15 +178,12 @@ def load_projconf(directory): return projconf def flag_name(flag): - name = flag.upper() - if name == '': - print('Ignoring empty flag.') - return '' - if name[0] == '-': - name = name[1:] - name = name.replace(' ', '_') - name = name.replace('-', '_') - name = name.replace('=', '_') + if flag == '': + return 'NO_FLAGS' + name = re.sub('[^0-9A-Za-z]', '_', flag.upper().strip('-')) + assert re.match('^[0-9]', name) is None, \ + 'Error: cannot handle flag that starts with a number' + assert len(name) > 0, 'Error: cannot handle flag only made of dashes' return name def generate_assignments(flags): From 03f0976d575221526e948a6f53736dc84428eb5c Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 13:43:02 -0700 Subject: [PATCH 169/196] flit-update: fix handling of missing compilers --- scripts/flitcli/flit_update.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index fbab9e07..7d7b950b 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -312,10 +312,16 @@ def main(arguments, prog=sys.argv[0]): } replacements.update({key + '_compiler': val for key, val in base_compilers.items()}) - replacements.update({'opcodes_' + compiler: ' '.join(compiler_op_levels[compiler]) - for compiler in given_compilers}) + replacements.update({'opcodes_' + x: ' '.join(compiler_op_levels[x]) + for x in given_compilers}) + replacements.update({'opcodes_' + x: None + for x in _supported_compiler_types + if x not in given_compilers}) replacements.update({'switches_' + compiler: ' '.join(compiler_flags[compiler]) - for compiler in given_compilers}) + for compiler in given_compilers}) + replacements.update({'switches_' + x: None + for x in _supported_compiler_types + if x not in given_compilers}) flitutil.process_in_file(os.path.join(conf.data_dir, 'Makefile.in'), makefile, replacements, overwrite=True) From fcb705ec0709f4fb5a55ec58ce6251aa5542ef92 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 14:18:49 -0700 Subject: [PATCH 170/196] flit-update: docstring + doctest for gen_assignments --- scripts/flitcli/flit_update.py | 106 +++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 38 deletions(-) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 7d7b950b..10cdee07 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -178,6 +178,32 @@ def load_projconf(directory): return projconf def flag_name(flag): + ''' + Returns an associated Makefile variable name for the given compiler flag + + @param flag: (str) switches for the compiler + + @return (str) a valid Makefile variable unique to the given flag + + >>> flag_name('') + 'NO_FLAGS' + + >>> flag_name('-') + Traceback (most recent call last): + ... + AssertionError: Error: cannot handle flag only made of dashes + + >>> flag_name('----') + Traceback (most recent call last): + ... + AssertionError: Error: cannot handle flag only made of dashes + + >>> flag_name('-funsafe-math-optimizations') + 'FUNSAFE_MATH_OPTIMIZATIONS' + + >>> flag_name('-Ofast -march=32bit') + 'OFAST__MARCH_32BIT' + ''' if flag == '': return 'NO_FLAGS' name = re.sub('[^0-9A-Za-z]', '_', flag.upper().strip('-')) @@ -186,41 +212,45 @@ def flag_name(flag): assert len(name) > 0, 'Error: cannot handle flag only made of dashes' return name -def generate_assignments(flags): - name_assignments = [name + ' := ' + flags[name] - for name in flags.keys() if name != ''] - return '\n'.join(name_assignments) - -def gen_optl_switches(compiler): +def gen_assignments(flag_map): ''' - From the compiler specification, generate Makefile strings for optimization - levels and switches. - - @param compiler {'type': str, - 'optimization_levels': list, - 'switches_list': list} - - @return string to insert into the Makefile - - >>> gen_optl_switches({ - ... 'type': 'clang', - ... 'optimization_levels': ['-O2', '-O3'], - ... 'switches_list': ['-hi there', '-hello', ''] - ... }) - CLANG_OPTL01 := -O2 - CLANG_OPTL02 := -O3 - CLANG_SWITCH01 := -hi there - CLANG_SWITCH02 := -hello - CLANG_SWITCH03 := - OPCODES_CLANG := - OPCODES_CLANG += CLANG_OPTL01 - OPCODES_CLANG += CLANG_OPTL02 - SWITCHES_CLANG := - SWITCHES_CLANG += CLANG_SWITCH01 - SWITCHES_CLANG += CLANG_SWITCH02 - SWITCHES_CLANG += CLANG_SWITCH03 + Given a mapping of Makefile variable name to value, create a single string + of assignments suitable for placing within a Makefile + + @note no checking is performed on the keys of the map. They are assumed to + be valid Makefile variables + + @param flag_map: ({str: str}) mapping from Makefile variable name to + Makefile value. + @return (str) The string to insert into a Makefile to create the + assignments + + >>> gen_assignments({}) + '' + + >>> gen_assignments({'single_name': 'single_value'}) + 'single_name := single_value' + + Here we use an OrderedDict for the test to be robust. If we used a normal + dict, then the output lines could show up in a different order. + >>> from collections import OrderedDict + >>> print(gen_assignments( + ... OrderedDict([('hello', 'there'), ('my', 'friend')]))) + hello := there + my := friend + + >>> print(gen_assignments(OrderedDict([ + ... ('REALLY_A_VERY_LONG_VARIABLE_NAME_HERE', 'bob'), + ... ('not_so_long_32', 'harry'), + ... ('short', 'very long value here'), + ... ]))) + REALLY_A_VERY_LONG_VARIABLE_NAME_HERE := bob + not_so_long_32 := harry + short := very long value here ''' - pass + name_assignments = ['{} := {}'.format(name.ljust(15), flag) + for name, flag in flag_map.items()] + return '\n'.join(name_assignments) def main(arguments, prog=sys.argv[0]): 'Main logic here' @@ -270,7 +300,7 @@ def main(arguments, prog=sys.argv[0]): assert base_compilers[compiler['type']] is None, \ 'You can only specify one of each type of compiler.' base_compilers[compiler['type']] = compiler['binary'] - + switches = {flag_name(flag): flag for flag in compiler['switches_list']} compiler_flags[compiler['type']] = switches.keys() all_switches.update(switches) @@ -307,8 +337,8 @@ def main(arguments, prog=sys.argv[0]): 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', 'mpirun_args': projconf['run']['mpirun_args'], 'compilers': ' '.join([c.upper() for c in given_compilers]), - 'opcodes_definitions': generate_assignments(all_op_levels), - 'switches_definitions': generate_assignments(all_switches), + 'opcodes_definitions': gen_assignments(all_op_levels), + 'switches_definitions': gen_assignments(all_switches), } replacements.update({key + '_compiler': val for key, val in base_compilers.items()}) @@ -317,8 +347,8 @@ def main(arguments, prog=sys.argv[0]): replacements.update({'opcodes_' + x: None for x in _supported_compiler_types if x not in given_compilers}) - replacements.update({'switches_' + compiler: ' '.join(compiler_flags[compiler]) - for compiler in given_compilers}) + replacements.update({'switches_' + x: ' '.join(compiler_flags[x]) + for x in given_compilers}) replacements.update({'switches_' + x: None for x in _supported_compiler_types if x not in given_compilers}) From e1c37a5a525021adb2f4920879e03d3bf8677927 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 15:02:08 -0700 Subject: [PATCH 171/196] flit-update: simplify a bit with gen_multi_assignment --- data/Makefile.in | 16 ++------ scripts/flitcli/flit_update.py | 69 ++++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index de89ec64..4929ffe3 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -90,9 +90,7 @@ GT_OUT := ground-truth.csv UNAME_S := $(shell uname -s) # will be None if not specified in flit-config.toml -CLANG := {clang_compiler} -INTEL := {intel_compiler} -GCC := {gcc_compiler} +{compiler_defs} # keep only the compilers that are not None and are in the path COMPILERS := {compilers} @@ -257,17 +255,9 @@ endif {switches_definitions} -OPCODES_GCC := {opcodes_gcc} -OPCODES_CLANG := {opcodes_clang} -OPCODES_INTEL := {opcodes_intel} +{compiler_opcodes} -SWITCHES_GCC := -SWITCHES_CLANG := -SWITCHES_INTEL := - -SWITCHES_GCC += {switches_gcc} -SWITCHES_CLANG += {switches_clang} -SWITCHES_INTEL += {switches_intel} +{compiler_switches} ########################################################## # diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 10cdee07..0c6028bc 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -252,6 +252,36 @@ def gen_assignments(flag_map): for name, flag in flag_map.items()] return '\n'.join(name_assignments) +def gen_multi_assignment(name, values): + ''' + Generates a multi-line assignment string for a Makefile + + @note no checking is done on the name or values to see if they are valid to + place within a Makefile. + + @param name: (str) Makefile variable name + @param values: (iter(str)) iterable of values to assign, one per line + + @return (str) a single string with the multi-line assignment suitable for a + Makefile. + + >>> gen_multi_assignment('CLANG', None) + 'CLANG :=' + + >>> gen_multi_assignment('CLANG', []) + 'CLANG :=' + + >>> print(gen_multi_assignment('hello_there', ['my friend', 'my enemy'])) + hello_there := + hello_there += my friend + hello_there += my enemy + ''' + values = values or tuple() # if None, set to an empty tuple + justified = name.ljust(15) + beginning = justified + ' :=' + return '\n'.join( + [beginning] + ['{} += {}'.format(justified, x) for x in values]) + def main(arguments, prog=sys.argv[0]): 'Main logic here' args = parse_args(arguments, prog=prog) @@ -289,25 +319,23 @@ def main(arguments, prog=sys.argv[0]): .format(ground_truth['compiler_name']) _supported_compiler_types = ('clang', 'gcc', 'intel') - base_compilers = {x: None for x in _supported_compiler_types} - compiler_flags = {x: None for x in _supported_compiler_types} - compiler_op_levels = {x: None for x in _supported_compiler_types} + base_compilers = {x.upper(): None for x in _supported_compiler_types} + compiler_flags = {x.upper(): None for x in _supported_compiler_types} + compiler_op_levels = {x.upper(): None for x in _supported_compiler_types} all_op_levels = {} all_switches = {} for compiler in projconf['compiler']: assert compiler['type'] in _supported_compiler_types, \ 'Unsupported compiler type: {}'.format(compiler['type']) - assert base_compilers[compiler['type']] is None, \ - 'You can only specify one of each type of compiler.' - base_compilers[compiler['type']] = compiler['binary'] + base_compilers[compiler['type'].upper()] = compiler['binary'] switches = {flag_name(flag): flag for flag in compiler['switches_list']} - compiler_flags[compiler['type']] = switches.keys() + compiler_flags[compiler['type'].upper()] = switches.keys() all_switches.update(switches) op_levels = {flag_name(flag): flag for flag in compiler['optimization_levels']} - compiler_op_levels[compiler['type']] = op_levels.keys() + compiler_op_levels[compiler['type'].upper()] = op_levels.keys() all_op_levels.update(op_levels) test_run_args = '' @@ -319,8 +347,6 @@ def main(arguments, prog=sys.argv[0]): '--timing-repeats', str(projconf['run']['timing_repeats']), ]) - given_compilers = [key for key, val in base_compilers.items() - if val is not None] replacements = { 'dev_compiler': matching_dev_compilers[0]['binary'], 'dev_optl': dev_build['optimization_level'], @@ -336,22 +362,19 @@ def main(arguments, prog=sys.argv[0]): 'test_run_args': test_run_args, 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', 'mpirun_args': projconf['run']['mpirun_args'], - 'compilers': ' '.join([c.upper() for c in given_compilers]), + 'compiler_defs': gen_assignments({ + key.upper(): val for key, val in base_compilers.items()}), + 'compilers': ' '.join([x.upper() for x in base_compilers + if base_compilers[x] is not None]), 'opcodes_definitions': gen_assignments(all_op_levels), 'switches_definitions': gen_assignments(all_switches), + 'compiler_opcodes': '\n\n'.join([ + gen_multi_assignment('OPCODES_' + key, vals) + for key, vals in compiler_op_levels.items()]), + 'compiler_switches': '\n\n'.join([ + gen_multi_assignment('SWITCHES_' + key, vals) + for key, vals in compiler_flags.items()]), } - replacements.update({key + '_compiler': val - for key, val in base_compilers.items()}) - replacements.update({'opcodes_' + x: ' '.join(compiler_op_levels[x]) - for x in given_compilers}) - replacements.update({'opcodes_' + x: None - for x in _supported_compiler_types - if x not in given_compilers}) - replacements.update({'switches_' + x: ' '.join(compiler_flags[x]) - for x in given_compilers}) - replacements.update({'switches_' + x: None - for x in _supported_compiler_types - if x not in given_compilers}) flitutil.process_in_file(os.path.join(conf.data_dir, 'Makefile.in'), makefile, replacements, overwrite=True) From 48b4d9eede20638dcd92969505794c23a86e903d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 15:29:01 -0700 Subject: [PATCH 172/196] flit-update: solve pylint findings --- scripts/flitcli/flit_update.py | 48 +++++++++++++++------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 0c6028bc..70c330c0 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -318,25 +318,9 @@ def main(arguments, prog=sys.argv[0]): 'Multiple compilers with name {0} found' \ .format(ground_truth['compiler_name']) - _supported_compiler_types = ('clang', 'gcc', 'intel') base_compilers = {x.upper(): None for x in _supported_compiler_types} - compiler_flags = {x.upper(): None for x in _supported_compiler_types} - compiler_op_levels = {x.upper(): None for x in _supported_compiler_types} - all_op_levels = {} - all_switches = {} - for compiler in projconf['compiler']: - assert compiler['type'] in _supported_compiler_types, \ - 'Unsupported compiler type: {}'.format(compiler['type']) - base_compilers[compiler['type'].upper()] = compiler['binary'] - - switches = {flag_name(flag): flag for flag in compiler['switches_list']} - compiler_flags[compiler['type'].upper()] = switches.keys() - all_switches.update(switches) - - op_levels = {flag_name(flag): flag - for flag in compiler['optimization_levels']} - compiler_op_levels[compiler['type'].upper()] = op_levels.keys() - all_op_levels.update(op_levels) + base_compilers.update({compiler['type'].upper(): compiler['binary'] + for compiler in projconf['compiler']}) test_run_args = '' if not projconf['run']['timing']: @@ -363,17 +347,27 @@ def main(arguments, prog=sys.argv[0]): 'enable_mpi': 'yes' if projconf['run']['enable_mpi'] else 'no', 'mpirun_args': projconf['run']['mpirun_args'], 'compiler_defs': gen_assignments({ - key.upper(): val for key, val in base_compilers.items()}), - 'compilers': ' '.join([x.upper() for x in base_compilers - if base_compilers[x] is not None]), - 'opcodes_definitions': gen_assignments(all_op_levels), - 'switches_definitions': gen_assignments(all_switches), + key: val for key, val in base_compilers.items()}), + 'compilers': ' '.join([compiler['type'].upper() + for compiler in projconf['compiler']]), + 'opcodes_definitions': gen_assignments({ + flag_name(x): x + for compiler in projconf['compiler'] + for x in compiler['optimization_levels']}), + 'switches_definitions': gen_assignments({ + flag_name(x): x + for compiler in projconf['compiler'] + for x in compiler['switches_list']}), 'compiler_opcodes': '\n\n'.join([ - gen_multi_assignment('OPCODES_' + key, vals) - for key, vals in compiler_op_levels.items()]), + gen_multi_assignment( + 'OPCODES_' + compiler['type'].upper(), + [flag_name(x) for x in compiler['optimization_levels']]) + for compiler in projconf['compiler']]), 'compiler_switches': '\n\n'.join([ - gen_multi_assignment('SWITCHES_' + key, vals) - for key, vals in compiler_flags.items()]), + gen_multi_assignment( + 'SWITCHES_' + compiler['type'].upper(), + [flag_name(x) for x in compiler['switches_list']]) + for compiler in projconf['compiler']]), } flitutil.process_in_file(os.path.join(conf.data_dir, 'Makefile.in'), From c6128407a42cfd21c650ce4652b7e4cc412e44c1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 15:38:48 -0700 Subject: [PATCH 173/196] Makefile.in: have python give uname --- data/Makefile.in | 2 +- scripts/flitcli/flit_update.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/data/Makefile.in b/data/Makefile.in index 4929ffe3..3e94c078 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -87,7 +87,7 @@ DEV_TARGET ?= devrun GT_TARGET ?= gtrun GT_OUT := ground-truth.csv -UNAME_S := $(shell uname -s) +UNAME_S := {uname} # will be None if not specified in flit-config.toml {compiler_defs} diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 70c330c0..7969b815 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -332,6 +332,7 @@ def main(arguments, prog=sys.argv[0]): ]) replacements = { + 'uname': os.uname().sysname, 'dev_compiler': matching_dev_compilers[0]['binary'], 'dev_optl': dev_build['optimization_level'], 'dev_switches': dev_build['switches'], From 2031169592e1c56e408dcbf1a927566618fe0a5b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 29 Nov 2018 15:47:15 -0700 Subject: [PATCH 174/196] Makefile.in: have hostname come from python --- data/Makefile.in | 2 +- scripts/flitcli/flit_update.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/data/Makefile.in b/data/Makefile.in index 3e94c078..32f82023 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -227,7 +227,7 @@ GT_OBJ = $(addprefix $(OBJ_DIR)/,$(notdir $(SOURCE:%.cpp=%_gt.o))) GT_DEPS = $(GT_OBJ:%.o=%.d) GT_OBJ_FPIC = $(GT_OBJ:%.o=%_fPIC.o) -HOSTNAME := $(shell hostname) +HOSTNAME := {hostname} RESULTS_DIR := results diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 7969b815..319a86b5 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -333,6 +333,7 @@ def main(arguments, prog=sys.argv[0]): replacements = { 'uname': os.uname().sysname, + 'hostname': os.uname().nodename, 'dev_compiler': matching_dev_compilers[0]['binary'], 'dev_optl': dev_build['optimization_level'], 'dev_switches': dev_build['switches'], From 4b1f3715e5844d2fe1bfd5e2f93a7edab52601e1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 11 Dec 2018 22:39:19 -0700 Subject: [PATCH 175/196] flit-update: test for no compilers specified tst_nocompilers.py flitutil: add extract_make_vars() function This function returns ALL makefile variables as a dictionary instead of the other extract_make_var() function that extracts only one at a time. This is useful for introspection and if many variables are desired --- scripts/flitcli/flitutil.py | 59 ++++++ tests/flit_cli/flit_update/Makefile | 23 ++ tests/flit_cli/flit_update/README.md | 28 +++ .../flit_update/data/nocompilers.toml | 2 + tests/flit_cli/flit_update/tst_nocompilers.py | 196 ++++++++++++++++++ tests/test_harness.py | 1 + 6 files changed, 309 insertions(+) create mode 100644 tests/flit_cli/flit_update/Makefile create mode 100644 tests/flit_cli/flit_update/README.md create mode 100644 tests/flit_cli/flit_update/data/nocompilers.toml create mode 100644 tests/flit_cli/flit_update/tst_nocompilers.py diff --git a/scripts/flitcli/flitutil.py b/scripts/flitcli/flitutil.py index 2bc35a90..2adeff64 100644 --- a/scripts/flitcli/flitutil.py +++ b/scripts/flitcli/flitutil.py @@ -350,6 +350,65 @@ def extract_make_var(var, makefile='Makefile', directory='.'): var_values = output.split('=', maxsplit=1)[1].split() return var_values +def extract_make_vars(makefile='Makefile', directory='.'): + ''' + Extracts all GNU Make variables from the given Makefile, except for those + that are built-in. It is returned as a dictionary of + {'var': ['val', ...]} + + @note, all variables are returned, including internal Makefile + variables. + + >>> from tempfile import NamedTemporaryFile as NTF + >>> with NTF(mode='w+') as fout: + ... print('A := hello there sweetheart\\n' + ... 'B = \\n', + ... file=fout, flush=True) + ... allvars = extract_make_vars(fout.name) + + >>> allvars['A'] + ['hello', 'there', 'sweetheart'] + >>> allvars['B'] + [] + + What if the file does not exist? It throws an exception: + + >>> extract_make_var('A', 'file-should-not-exist.mk') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + subprocess.CalledProcessError: Command ... returned non-zero exit status 2. + ''' + with tempfile.NamedTemporaryFile(mode='w+') as fout: + print('$(foreach v,$(.VARIABLES),$(info $(v)=$($(v))**==**))\n' + '.PHONY: empty-target\n' + 'empty-target:\n' + "\t@true\n", file=fout, flush=True) + output = subp.check_output( + ['make', '-f', makefile, '-f', fout.name, 'empty-target', + '--directory', directory, '--no-print-directory'], + stderr=subp.DEVNULL) + lines = output.strip().decode('utf-8').splitlines() + var_values = {} + prevkey = None + for line in lines: + if prevkey is None: + split = line.split('=', maxsplit=1) + prevkey = split[0] + values = split[1] + var_values[prevkey] = [] + else: + values = line + + key = prevkey + + if values.endswith('**==**'): + values = values.replace('**==**', '') + prevkey = None + + var_values[key].extend(values.split()) + + return var_values + def printlog(message): ''' Prints the message to stdout and then logs the message at the info level. diff --git a/tests/flit_cli/flit_update/Makefile b/tests/flit_cli/flit_update/Makefile new file mode 100644 index 00000000..ce0c8e04 --- /dev/null +++ b/tests/flit_cli/flit_update/Makefile @@ -0,0 +1,23 @@ +RUNNER := python3 +SRC := $(wildcard tst_*.py) +RUN_TARGETS := $(SRC:%.py=run_%) + +include ../../color_out.mk + +.PHONY: check help clean build run_% +check: $(TARGETS) $(RUN_TARGETS) + +help: + @echo "Makefile for running tests on FLiT framework" + @echo " help print this help documentation and exit" + @echo " build just compile the targets" + @echo " check run tests and print results to the console" + @echo " clean remove all generated files" + +build: +clean: + +run_% : %.py + @$(call color_out_noline,BROWN, running) + @echo " $<" + @$(RUNNER) $< diff --git a/tests/flit_cli/flit_update/README.md b/tests/flit_cli/flit_update/README.md new file mode 100644 index 00000000..e152bb0d --- /dev/null +++ b/tests/flit_cli/flit_update/README.md @@ -0,0 +1,28 @@ +# Tests + +## Tests covering `[[compiler]]` section + +[ ] 1. `tst_nocompilers.py`: Test that not specifying the `[[compiler]]` + section gives the default values +[ ] 2. Test that specifying a compiler, but not specifying the optimization + levels gives the default values +[ ] 3. Test that specifying a compiler, but not specifying the switches list + gives the default values +[ ] 4. Test that the provided list of optimization levels and switches are + used, and nothing more. +[ ] 5. Test that by only specifying one or two compilers, only those specified + are used +[ ] 6. Test error cases, such as specifying more than one type of a compiler + +# Needed tests + +1. `FLIT_INC_DIR`, `FLIT_LIB_DIR`, `FLIT_DATA_DIR`, and `FLIT_SCRIPT_DIR`, for + both from git repository and for an installed FLiT +2. `DEV_CC`, `DEV_OPTL`, and `DEV_SWITCHES` for both provided and non-provided +3. `GT_CC`, `GT_OPTL`, and `GT_SWITCHES` for both provided and non-provided +4. `TEST_RUN_ARGS` from `timing`, `timing_loops`, and `timing_repeats` for both + provided and non-provided +5. `ENABLE_MPI` and `MPIRUN_ARGS` for both provided and non-provided +6. `HOSTNAME` +7. `UNAME_S` + diff --git a/tests/flit_cli/flit_update/data/nocompilers.toml b/tests/flit_cli/flit_update/data/nocompilers.toml new file mode 100644 index 00000000..f0d03294 --- /dev/null +++ b/tests/flit_cli/flit_update/data/nocompilers.toml @@ -0,0 +1,2 @@ +# Test that with no compilers specified the default three compilers with their +# default flags are used. diff --git a/tests/flit_cli/flit_update/tst_nocompilers.py b/tests/flit_cli/flit_update/tst_nocompilers.py new file mode 100644 index 00000000..2c72fec2 --- /dev/null +++ b/tests/flit_cli/flit_update/tst_nocompilers.py @@ -0,0 +1,196 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests that specifying no compilers results in the default compilers with the +default flags. + +>>> from io import StringIO +>>> import shutil +>>> import itertools + +>>> testconf = 'data/nocompilers.toml' +>>> class UpdateTestError(RuntimeError): pass + +>>> def flatten(lists): return list(itertools.chain(*lists)) +>>> def deref_makelist(name): +... return sorted([' '.join(makevars[x]) for x in makevars[name]]) +>>> def deref_switches(name): +... switches = deref_makelist(name) +... if 'NO_FLAGS' in makevars[name]: +... switches = sorted(switches + ['']) +... return switches + +>>> with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to initialize flit directory') +... _ = shutil.copy(testconf, temp_dir) +... with StringIO() as ostream: +... retval = th.flit.main(['update', '-C', temp_dir], +... outstream=ostream) +... update_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to update Makefile') +... makevars = th.util.extract_make_vars(directory=temp_dir) + +Get default values for each compiler from the default configuration +>>> defaults = th.util.get_default_toml() +>>> default_gcc = [x for x in defaults['compiler'] if x['type'] == 'gcc'] +>>> default_clang = [x for x in defaults['compiler'] if x['type'] == 'clang'] +>>> default_intel = [x for x in defaults['compiler'] if x['type'] == 'intel'] +>>> len(default_gcc) == 1 +True +>>> len(default_clang) == 1 +True +>>> len(default_intel) == 1 +True +>>> default_gcc = default_gcc[0] +>>> default_clang = default_clang[0] +>>> default_intel = default_intel[0] + +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile + +>>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS +Updating .../Makefile + +Check that the compiler binaries are the default values +>>> gcc = makevars['GCC'] +>>> len(gcc) == 1 +True +>>> gcc[0] == default_gcc['binary'] +True + +>>> clang = makevars['CLANG'] +>>> len(clang) == 1 +True +>>> clang[0] == default_clang['binary'] +True + +>>> intel = makevars['INTEL'] +>>> len(intel) == 1 +True +>>> intel[0] == default_intel['binary'] +True + +>>> sorted(makevars['COMPILERS']) +['CLANG', 'GCC', 'INTEL'] + +>>> deref_makelist('OPCODES_GCC') == sorted(default_gcc['optimization_levels']) +True + +>>> deref_makelist('OPCODES_CLANG') == \\ +... sorted(default_clang['optimization_levels']) +True + +>>> deref_makelist('OPCODES_INTEL') == \\ +... sorted(default_intel['optimization_levels']) +True + +>>> deref_makelist('SWITCHES_GCC') == sorted(default_gcc['switches_list']) +True + +>>> deref_makelist('SWITCHES_CLANG') == sorted(default_clang['switches_list']) +True + +>>> deref_makelist('SWITCHES_INTEL') == sorted(default_intel['switches_list']) +True +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) diff --git a/tests/test_harness.py b/tests/test_harness.py index 88873817..4df30665 100644 --- a/tests/test_harness.py +++ b/tests/test_harness.py @@ -227,6 +227,7 @@ def touch(filename): flit = _path_import(_script_dir, 'flit') config = _path_import(_script_dir, 'flitconfig') +util = _path_import(_script_dir, 'flitutil') # Remove the things that are no longer necessary del contextmanager From a4b09e19c441047e91ee90d2e9868059e8c01116 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 11:39:08 -0700 Subject: [PATCH 176/196] fix hosts for merge --- documentation/flit-configuration-file.md | 2 +- .../config/flit-default-future.toml.in | 116 +++++++++--------- tests/flit_makefile/tst_clang34.py | 7 +- tests/flit_makefile/tst_gcc4.py | 7 +- 4 files changed, 65 insertions(+), 67 deletions(-) diff --git a/documentation/flit-configuration-file.md b/documentation/flit-configuration-file.md index a1f79cc4..acb6deec 100644 --- a/documentation/flit-configuration-file.md +++ b/documentation/flit-configuration-file.md @@ -21,7 +21,7 @@ to delete or comment out the values, which will cause the default values to be used._ ```toml -[hosts] +[host] name = 'my.hostname.com' flit_path = '/usr/bin/flit' config_dir = '/usr/share/flit/config' diff --git a/scripts/flitcli/config/flit-default-future.toml.in b/scripts/flitcli/config/flit-default-future.toml.in index a0873550..dc37017e 100644 --- a/scripts/flitcli/config/flit-default-future.toml.in +++ b/scripts/flitcli/config/flit-default-future.toml.in @@ -82,13 +82,25 @@ # Autogenerated by "flit init" # flit version {flit_version} +# General information +[host] + +# if you omit name, the system hostname will be used +name = '{hostname}' + +# if you omit flit_path, the current flit executable will be used +flit_path = '{flit_path}' + +# if you omit config_dir, it will be taken from the current flit executable +config_dir = '{config_dir}' + + [database] -# older versions of flit supported postgres. that has been removed. only -# sqlite is supported at the moment. +# only sqlite is supported, so this field can be safely omitted type = 'sqlite' -# if relative path, it is relative to the directory containing this +# if this is a relative path, it is relative to the directory containing this # configuration file. filepath = 'results.sqlite' @@ -106,70 +118,58 @@ timing_loops = -1 # will be kept. timing_repeats = 3 +# The tests can be run with MPI to test MPI applications +# Warning: FLiT assumes tests are deterministic. It is your responsability to +# ensure that your test will always produce the same result even using +# MPI. +# The mpirun_args are for any flags passed to mpirun. For example, you can do +# mpirun_args = '-n 16 --verbose' +enable_mpi = false +mpirun_args = '' -# For now, only the first host is supported, all others are ignored -[[hosts]] -# TODO: add documentation here for each element. +# The settings for "make dev", which generates the "devrun" executable +[dev_build] -name = '{hostname}' -flit_path = '{flit_path}' -config_dir = '{config_dir}' - -# The settings for "make dev" -[hosts.dev_build] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list +# compiler_name must be found in the [[compiler]] list under the name attribute compiler_name = 'g++' optimization_level = '-O2' switches = '-funsafe-math-optimizations' -# The ground truth compilation to use in analysis, for "make gt" -[hosts.ground_truth] -# compiler_name must be found in [[hosts.compilers]] list under name attribute -# but the optimization level and switches do not need to be in the compiler list +# The ground truth compilation to use in analysis, for "make gt", which +# generates the "gtrun" executable +[ground_truth] + +# compiler_name must be found in the [[compiler]] list under the name attribute compiler_name = 'g++' optimization_level = '-O0' switches = '' - # This host's list of compilers. - # For now, only used for hosts.ground_truth and hosts.dev_build. - # TODO: use this list to generate the Makefile - [[hosts.compilers]] - - # TODO: figure out how to specify path for each host machine - # TODO: what if the compilers list is part of the host? - - # binary can be an absolute path, relative path, or binary name (found in - # PATH). If you want to specify a compiler in the same directory as this - # config file, prepend with a "./" (e.g. "./my-compiler") - binary = 'g++' - # TODO: this is not yet used... - # It is recommended to include version number in the name. This is how the - # compiler will be recognized in the results, and subsequently in the - # database and analysis. - name = 'g++' - # TODO: implement these supported types - # There are a few supported types: [ gcc, intel, clang ] - type = 'gcc' - optimization_levels = [ - '-O0', - '-O1', - '-O2', - '-O3', - #'-Ofast', - #'-O...' ? - ] - # Note: in some versions of python-toml, there is a parsing bug when a list - # has an empty string in the middle. So simply put it at the end without a - # comma. This has been fixed in the latest version of python-toml. - switches_list = [ - '-fassociative-math', - '-mavx', - '-mp1', - '-mavx2 -mfma', - '' - # ... - ] - +# List of compilers. +# - binary: can be an absolute path, relative path, or binary name (found in +# PATH). If you want to specify a compiler in the same directory as this +# config file, prepend with a "./" (e.g. "./my-compiler") +# - name: can be any string. Used to recognize in the other options such as +# in [dev_build] and [ground_truth] +# - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') +# Currently, only one of each type may be specified. +# Note that these are all defaulted to use g++, clang++, and icpc from the +# PATH. +# If you specify any one compiler, then these defaults are erased. If you +# specify no compiler, then these defaults take effect. + +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' + +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' + +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' diff --git a/tests/flit_makefile/tst_clang34.py b/tests/flit_makefile/tst_clang34.py index 443848b5..3366c785 100644 --- a/tests/flit_makefile/tst_clang34.py +++ b/tests/flit_makefile/tst_clang34.py @@ -98,12 +98,11 @@ ... init_out = ostream.getvalue().splitlines() ... os.remove(os.path.join(temp_dir, 'flit-config.toml')) ... with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as conf: -... _ = conf.write('[[hosts]]\\n') -... _ = conf.write('[hosts.dev_build]\\n') +... _ = conf.write('[dev_build]\\n') ... _ = conf.write("compiler_name = 'fake-clang'\\n") -... _ = conf.write('[hosts.ground_truth]\\n') +... _ = conf.write('[ground_truth]\\n') ... _ = conf.write("compiler_name = 'fake-clang'\\n") -... _ = conf.write('[[hosts.compilers]]\\n') +... _ = conf.write('[[compiler]]\\n') ... _ = conf.write("binary = './fake_clang34.py'\\n") ... _ = conf.write("name = 'fake-clang'\\n") ... _ = conf.write("type = 'clang'\\n") diff --git a/tests/flit_makefile/tst_gcc4.py b/tests/flit_makefile/tst_gcc4.py index 2398e8e5..fb783ffa 100644 --- a/tests/flit_makefile/tst_gcc4.py +++ b/tests/flit_makefile/tst_gcc4.py @@ -98,12 +98,11 @@ ... init_out = ostream.getvalue().splitlines() ... os.remove(os.path.join(temp_dir, 'flit-config.toml')) ... with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as conf: -... _ = conf.write('[[hosts]]\\n') -... _ = conf.write('[hosts.dev_build]\\n') +... _ = conf.write('[dev_build]\\n') ... _ = conf.write("compiler_name = 'fake-gcc'\\n") -... _ = conf.write('[hosts.ground_truth]\\n') +... _ = conf.write('[ground_truth]\\n') ... _ = conf.write("compiler_name = 'fake-gcc'\\n") -... _ = conf.write('[[hosts.compilers]]\\n') +... _ = conf.write('[[compiler]]\\n') ... _ = conf.write("binary = './fake_gcc4.py'\\n") ... _ = conf.write("name = 'fake-gcc'\\n") ... _ = conf.write("type = 'gcc'\\n") From 7fd56f69a473bddc8deb54c1ee5fe874adc3946a Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 11:46:44 -0700 Subject: [PATCH 177/196] Remove flit-default-future.toml.in It was intended to have what was intended in future versions of the configuration file, but it provides little purpose now that the issues on github are used --- .../config/flit-default-future.toml.in | 175 ------------------ 1 file changed, 175 deletions(-) delete mode 100644 scripts/flitcli/config/flit-default-future.toml.in diff --git a/scripts/flitcli/config/flit-default-future.toml.in b/scripts/flitcli/config/flit-default-future.toml.in deleted file mode 100644 index dc37017e..00000000 --- a/scripts/flitcli/config/flit-default-future.toml.in +++ /dev/null @@ -1,175 +0,0 @@ -# -- LICENSE BEGIN -- -# -# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. -# -# Produced at the Lawrence Livermore National Laboratory -# -# Written by -# Michael Bentley (mikebentley15@gmail.com), -# Geof Sawaya (fredricflinstone@gmail.com), -# and Ian Briggs (ian.briggs@utah.edu) -# under the direction of -# Ganesh Gopalakrishnan -# and Dong H. Ahn. -# -# LLNL-CODE-743137 -# -# All rights reserved. -# -# This file is part of FLiT. For details, see -# https://pruners.github.io/flit -# Please also read -# https://github.com/PRUNERS/FLiT/blob/master/LICENSE -# -# Redistribution and use in source and binary forms, with or -# without modification, are permitted provided that the following -# conditions are met: -# -# - Redistributions of source code must retain the above copyright -# notice, this list of conditions and the disclaimer below. -# -# - Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the disclaimer -# (as noted below) in the documentation and/or other materials -# provided with the distribution. -# -# - Neither the name of the LLNS/LLNL nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL -# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE -# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF -# THE POSSIBILITY OF SUCH DAMAGE. -# -# Additional BSD Notice -# -# 1. This notice is required to be provided under our contract -# with the U.S. Department of Energy (DOE). This work was -# produced at Lawrence Livermore National Laboratory under -# Contract No. DE-AC52-07NA27344 with the DOE. -# -# 2. Neither the United States Government nor Lawrence Livermore -# National Security, LLC nor any of their employees, makes any -# warranty, express or implied, or assumes any liability or -# responsibility for the accuracy, completeness, or usefulness of -# any information, apparatus, product, or process disclosed, or -# represents that its use would not infringe privately-owned -# rights. -# -# 3. Also, reference herein to any specific commercial products, -# process, or services by trade name, trademark, manufacturer or -# otherwise does not necessarily constitute or imply its -# endorsement, recommendation, or favoring by the United States -# Government or Lawrence Livermore National Security, LLC. The -# views and opinions of authors expressed herein do not -# necessarily state or reflect those of the United States -# Government or Lawrence Livermore National Security, LLC, and -# shall not be used for advertising or product endorsement -# purposes. -# -# -- LICENSE END -- -# Autogenerated by "flit init" -# flit version {flit_version} - -# General information -[host] - -# if you omit name, the system hostname will be used -name = '{hostname}' - -# if you omit flit_path, the current flit executable will be used -flit_path = '{flit_path}' - -# if you omit config_dir, it will be taken from the current flit executable -config_dir = '{config_dir}' - - -[database] - -# only sqlite is supported, so this field can be safely omitted -type = 'sqlite' - -# if this is a relative path, it is relative to the directory containing this -# configuration file. -filepath = 'results.sqlite' - - -[run] - -# Set this to false to not do any timing at all -timing = true - -# The number of loops to run with the timing. For values < 0, the number of -# loops to run will be determined automatically. -timing_loops = -1 - -# How many times to repeat the timing. The minimum of the repeated timings -# will be kept. -timing_repeats = 3 - -# The tests can be run with MPI to test MPI applications -# Warning: FLiT assumes tests are deterministic. It is your responsability to -# ensure that your test will always produce the same result even using -# MPI. -# The mpirun_args are for any flags passed to mpirun. For example, you can do -# mpirun_args = '-n 16 --verbose' -enable_mpi = false -mpirun_args = '' - - -# The settings for "make dev", which generates the "devrun" executable -[dev_build] - -# compiler_name must be found in the [[compiler]] list under the name attribute -compiler_name = 'g++' -optimization_level = '-O2' -switches = '-funsafe-math-optimizations' - -# The ground truth compilation to use in analysis, for "make gt", which -# generates the "gtrun" executable -[ground_truth] - -# compiler_name must be found in the [[compiler]] list under the name attribute -compiler_name = 'g++' -optimization_level = '-O0' -switches = '' - -# List of compilers. -# - binary: can be an absolute path, relative path, or binary name (found in -# PATH). If you want to specify a compiler in the same directory as this -# config file, prepend with a "./" (e.g. "./my-compiler") -# - name: can be any string. Used to recognize in the other options such as -# in [dev_build] and [ground_truth] -# - type: the brand of the compiler. We support ('gcc', 'clang', 'intel') -# Currently, only one of each type may be specified. -# Note that these are all defaulted to use g++, clang++, and icpc from the -# PATH. -# If you specify any one compiler, then these defaults are erased. If you -# specify no compiler, then these defaults take effect. - -[[compiler]] -binary = 'g++' -name = 'g++' -type = 'gcc' - -[[compiler]] -binary = 'clang++' -name = 'clang++' -type = 'clang' - -[[compiler]] -binary = 'icpc' -name = 'icpc' -type = 'intel' - From 40659d64ab3fda7a5ee64d41bc79a992a83427d8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 16:44:57 -0700 Subject: [PATCH 178/196] tests/flit_update: fix tst_nocompilers and tst_nooptl They weren't testing with thier actual needed configuration file, but rather with the default configuration file, of which causes all tests to pass anyway. --- tests/flit_cli/flit_update/README.md | 12 +- tests/flit_cli/flit_update/data/nooptl.toml | 93 +++++++++++ tests/flit_cli/flit_update/tst_nocompilers.py | 33 ++-- tests/flit_cli/flit_update/tst_nooptl.py | 154 ++++++++++++++++++ 4 files changed, 265 insertions(+), 27 deletions(-) create mode 100644 tests/flit_cli/flit_update/data/nooptl.toml create mode 100644 tests/flit_cli/flit_update/tst_nooptl.py diff --git a/tests/flit_cli/flit_update/README.md b/tests/flit_cli/flit_update/README.md index e152bb0d..8a3d8517 100644 --- a/tests/flit_cli/flit_update/README.md +++ b/tests/flit_cli/flit_update/README.md @@ -2,12 +2,12 @@ ## Tests covering `[[compiler]]` section -[ ] 1. `tst_nocompilers.py`: Test that not specifying the `[[compiler]]` - section gives the default values -[ ] 2. Test that specifying a compiler, but not specifying the optimization - levels gives the default values -[ ] 3. Test that specifying a compiler, but not specifying the switches list - gives the default values +1. `tst_nocompilers.py`: Test that not specifying the `[[compiler]]` section + gives the default values +2. `tst_nooptl.py`: Test that specifying a compiler, but not specifying the + optimization levels gives the default values +3. `tst_noswitches.py`: Test that specifying a compiler, but not specifying the + switches list gives the default values [ ] 4. Test that the provided list of optimization levels and switches are used, and nothing more. [ ] 5. Test that by only specifying one or two compilers, only those specified diff --git a/tests/flit_cli/flit_update/data/nooptl.toml b/tests/flit_cli/flit_update/data/nooptl.toml new file mode 100644 index 00000000..445b031e --- /dev/null +++ b/tests/flit_cli/flit_update/data/nooptl.toml @@ -0,0 +1,93 @@ +# Test that missing optimization levels causes the defaults to be used + +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' + +# missing optimization levels + +switches_list = [ + '-fassociative-math', + '-fcx-fortran-rules', + '-fcx-limited-range', + '-fexcess-precision=fast', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-funsafe-math-optimizations', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] + +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' + +# missing optimization levels + +switches_list = [ + '-fassociative-math', + '-fexcess-precision=fast', + '-fexcess-precision=standard', + '-ffinite-math-only', + '-ffloat-store', + '-ffp-contract=on', + '-fmerge-all-constants', + '-fno-trapping-math', + '-freciprocal-math', + '-frounding-math', + '-fsignaling-nans', + '-fsingle-precision-constant', + '-funsafe-math-optimizations', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '' +] + +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' + +# missing optimization levels + +switches_list = [ + '--use_fast_math', + '-fcx-limited-range', + '-ffloat-store', + '-fma', + '-fmerge-all-constants', + '-fp-model fast=1', + '-fp-model fast=2', + '-fp-model=double', + '-fp-model=except', + '-fp-model=extended', + '-fp-model=precise', + '-fp-model=source', + '-fp-model=strict', + '-fp-port', + '-frounding-math', + '-fsingle-precision-constant', + '-ftz', + '-march=core-avx2', + '-mavx', + '-mavx2 -mfma', + '-mfpmath=sse -mtune=native', + '-mp1', + '-no-fma', + '-no-ftz', + '-no-prec-div', + '-prec-div', + '' +] diff --git a/tests/flit_cli/flit_update/tst_nocompilers.py b/tests/flit_cli/flit_update/tst_nocompilers.py index 2c72fec2..b6f464af 100644 --- a/tests/flit_cli/flit_update/tst_nocompilers.py +++ b/tests/flit_cli/flit_update/tst_nocompilers.py @@ -85,20 +85,20 @@ default flags. >>> from io import StringIO +>>> import os >>> import shutil ->>> import itertools >>> testconf = 'data/nocompilers.toml' >>> class UpdateTestError(RuntimeError): pass ->>> def flatten(lists): return list(itertools.chain(*lists)) >>> def deref_makelist(name): ... return sorted([' '.join(makevars[x]) for x in makevars[name]]) ->>> def deref_switches(name): -... switches = deref_makelist(name) -... if 'NO_FLAGS' in makevars[name]: -... switches = sorted(switches + ['']) -... return switches +>>> def get_default_compiler(typename): +... defaults = th.util.get_default_toml() +... default_compiler = [x for x in defaults['compiler'] +... if x['type'] == typename] +... assert len(default_compiler) == 1 +... return default_compiler[0] >>> with th.tempdir() as temp_dir: ... with StringIO() as ostream: @@ -106,7 +106,7 @@ ... init_out = ostream.getvalue().splitlines() ... if retval != 0: ... raise UpdateTestError('Failed to initialize flit directory') -... _ = shutil.copy(testconf, temp_dir) +... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) ... with StringIO() as ostream: ... retval = th.flit.main(['update', '-C', temp_dir], ... outstream=ostream) @@ -116,19 +116,10 @@ ... makevars = th.util.extract_make_vars(directory=temp_dir) Get default values for each compiler from the default configuration ->>> defaults = th.util.get_default_toml() ->>> default_gcc = [x for x in defaults['compiler'] if x['type'] == 'gcc'] ->>> default_clang = [x for x in defaults['compiler'] if x['type'] == 'clang'] ->>> default_intel = [x for x in defaults['compiler'] if x['type'] == 'intel'] ->>> len(default_gcc) == 1 -True ->>> len(default_clang) == 1 -True ->>> len(default_intel) == 1 -True ->>> default_gcc = default_gcc[0] ->>> default_clang = default_clang[0] ->>> default_intel = default_intel[0] + +>>> default_gcc = get_default_compiler('gcc') +>>> default_clang = get_default_compiler('clang') +>>> default_intel = get_default_compiler('intel') >>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS Creating .../flit-config.toml diff --git a/tests/flit_cli/flit_update/tst_nooptl.py b/tests/flit_cli/flit_update/tst_nooptl.py new file mode 100644 index 00000000..2d409ea0 --- /dev/null +++ b/tests/flit_cli/flit_update/tst_nooptl.py @@ -0,0 +1,154 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Test that missing optimization levels causes the defaults to be used + +>>> from io import StringIO +>>> import os +>>> import shutil + +>>> testconf = 'data/nooptl.toml' +>>> class UpdateTestError(RuntimeError): pass + +>>> def deref_makelist(name): +... return sorted([' '.join(makevars[x]) for x in makevars[name]]) +>>> def get_default_compiler(typename): +... defaults = th.util.get_default_toml() +... default_compiler = [x for x in defaults['compiler'] +... if x['type'] == typename] +... assert len(default_compiler) == 1 +... return default_compiler[0] + +>>> with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to initialize flit directory') +... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) +... with StringIO() as ostream: +... retval = th.flit.main(['update', '-C', temp_dir], +... outstream=ostream) +... update_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to update Makefile') +... makevars = th.util.extract_make_vars(directory=temp_dir) + +Get default values for each compiler from the default configuration +>>> default_gcc = get_default_compiler('gcc') +>>> default_clang = get_default_compiler('clang') +>>> default_intel = get_default_compiler('intel') + +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile + +>>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS +Updating .../Makefile + +>>> deref_makelist('OPCODES_GCC') == sorted(default_gcc['optimization_levels']) +True + +>>> deref_makelist('OPCODES_CLANG') == \\ +... sorted(default_clang['optimization_levels']) +True + +>>> deref_makelist('OPCODES_INTEL') == \\ +... sorted(default_intel['optimization_levels']) +True +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From 171c47d4ffb9220c0c615d846a8336e1f6f6658f Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 16:46:46 -0700 Subject: [PATCH 179/196] tests/flit_update: add two new tests --- .../flit_cli/flit_update/data/noswitches.toml | 40 +++++ .../data/onlyprovidedoptlswitches.toml | 46 +++++ tests/flit_cli/flit_update/tst_noswitches.py | 152 ++++++++++++++++ .../tst_onlyprovidedoptlswitches.py | 166 ++++++++++++++++++ 4 files changed, 404 insertions(+) create mode 100644 tests/flit_cli/flit_update/data/noswitches.toml create mode 100644 tests/flit_cli/flit_update/data/onlyprovidedoptlswitches.toml create mode 100644 tests/flit_cli/flit_update/tst_noswitches.py create mode 100644 tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py diff --git a/tests/flit_cli/flit_update/data/noswitches.toml b/tests/flit_cli/flit_update/data/noswitches.toml new file mode 100644 index 00000000..da8e8f02 --- /dev/null +++ b/tests/flit_cli/flit_update/data/noswitches.toml @@ -0,0 +1,40 @@ +# Test that missing switches causes the compiler-specific defaults to be used + +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] + +# Missing switches + +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] + +# Missing switches + +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' +optimization_levels = [ + '-O0', + '-O1', + '-O2', + '-O3', +] + +# Missing switches diff --git a/tests/flit_cli/flit_update/data/onlyprovidedoptlswitches.toml b/tests/flit_cli/flit_update/data/onlyprovidedoptlswitches.toml new file mode 100644 index 00000000..838b770e --- /dev/null +++ b/tests/flit_cli/flit_update/data/onlyprovidedoptlswitches.toml @@ -0,0 +1,46 @@ +# Test that only the provided optimization levels and switches are used + +[[compiler]] +binary = 'g++' +name = 'g++' +type = 'gcc' + +optimization_levels = [ + '-O2', + '-O3', +] +switches_list = [ + '-funsafe-math-optimizations', + '-mavx', + '' +] + +[[compiler]] +binary = 'clang++' +name = 'clang++' +type = 'clang' + +optimization_levels = [ + '-O0', + '-O1', +] +switches_list = [ + '-ffinite-math-only', + '-ffloat-store', +] + +[[compiler]] +binary = 'icpc' +name = 'icpc' +type = 'intel' + +optimization_levels = [ + '-Ofast', + '-Og', +] +switches_list = [ + '-fmerge-all-constants', + '-fp-model fast=1', + '-fp-model fast=2', + '-DUSE_MPI' +] diff --git a/tests/flit_cli/flit_update/tst_noswitches.py b/tests/flit_cli/flit_update/tst_noswitches.py new file mode 100644 index 00000000..5fe2a6c3 --- /dev/null +++ b/tests/flit_cli/flit_update/tst_noswitches.py @@ -0,0 +1,152 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Test that missing switches causes the compiler-specific defaults to be used + +>>> from io import StringIO +>>> import shutil + +>>> testconf = 'data/noswitches.toml' +>>> class UpdateTestError(RuntimeError): pass + +>>> def deref_makelist(name): +... return sorted([' '.join(makevars[x]) for x in makevars[name]]) +>>> def get_default_compiler(typename): +... defaults = th.util.get_default_toml() +... default_compiler = [x for x in defaults['compiler'] +... if x['type'] == typename] +... assert len(default_compiler) == 1 +... return default_compiler[0] + +>>> with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to initialize flit directory') +... _ = shutil.copy(testconf, temp_dir) +... with StringIO() as ostream: +... retval = th.flit.main(['update', '-C', temp_dir], +... outstream=ostream) +... update_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to update Makefile') +... makevars = th.util.extract_make_vars(directory=temp_dir) + +Get default values for each compiler from the default configuration + +>>> default_gcc = get_default_compiler('gcc') +>>> default_clang = get_default_compiler('clang') +>>> default_intel = get_default_compiler('intel') + +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile + +>>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS +Updating .../Makefile + +>>> deref_makelist('SWITCHES_GCC') == sorted(default_gcc['switches_list']) +True + +>>> deref_makelist('SWITCHES_CLANG') == sorted(default_clang['switches_list']) +True + +>>> deref_makelist('SWITCHES_INTEL') == sorted(default_intel['switches_list']) +True +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) diff --git a/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py b/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py new file mode 100644 index 00000000..c66e12e3 --- /dev/null +++ b/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py @@ -0,0 +1,166 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Test that only the provided optimization levels and switches are used + +>>> from io import StringIO +>>> import shutil +>>> import os + +>>> testconf = 'data/onlyprovidedoptlswitches.toml' +>>> class UpdateTestError(RuntimeError): pass + +>>> def deref_makelist(name): +... return sorted([' '.join(makevars[x]) for x in makevars[name]]) +>>> def get_default_compiler(typename): +... defaults = th.util.get_default_toml() +... default_compiler = [x for x in defaults['compiler'] +... if x['type'] == typename] +... assert len(default_compiler) == 1 +... return default_compiler[0] + +>>> with th.tempdir() as temp_dir: +... temp_dir = 'tmp' +... if os.path.exists(temp_dir): +... shutil.rmtree(temp_dir) +... os.mkdir(temp_dir) +... with StringIO() as ostream: +... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to initialize flit directory') +... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) +... with StringIO() as ostream: +... retval = th.flit.main(['update', '-C', temp_dir], +... outstream=ostream) +... update_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to update Makefile') +... makevars = th.util.extract_make_vars(directory=temp_dir) + +Get default values for each compiler from the default configuration + +>>> default_gcc = get_default_compiler('gcc') +>>> default_clang = get_default_compiler('clang') +>>> default_intel = get_default_compiler('intel') + +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile + +>>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS +Updating .../Makefile + +>>> deref_makelist('OPCODES_GCC') +['-O2', '-O3'] + +>>> deref_makelist('OPCODES_CLANG') +['-O0', '-O1'] + +>>> deref_makelist('OPCODES_INTEL') +['-Ofast', '-Og'] + +>>> deref_makelist('SWITCHES_GCC') +['', '-funsafe-math-optimizations', '-mavx'] + +>>> deref_makelist('SWITCHES_CLANG') +['-ffinite-math-only', '-ffloat-store'] + +>>> deref_makelist('SWITCHES_INTEL') +['-DUSE_MPI', '-fmerge-all-constants', '-fp-model fast=1', '-fp-model fast=2'] +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From f36e9e19f5bf4da21c25f5bc862877166f06e83b Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 16:49:05 -0700 Subject: [PATCH 180/196] tests/flit_update: remove debug code from test --- tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py b/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py index c66e12e3..c0fe2530 100644 --- a/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py +++ b/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py @@ -100,10 +100,6 @@ ... return default_compiler[0] >>> with th.tempdir() as temp_dir: -... temp_dir = 'tmp' -... if os.path.exists(temp_dir): -... shutil.rmtree(temp_dir) -... os.mkdir(temp_dir) ... with StringIO() as ostream: ... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) ... init_out = ostream.getvalue().splitlines() From a918881309a9e27a8079dd86301ecfeeec49c175 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 16:59:44 -0700 Subject: [PATCH 181/196] tests/flit_update: add test for 1 provided compiler --- tests/flit_cli/flit_update/README.md | 8 +- .../data/onlyprovidedcompilers.toml | 6 + .../flit_update/tst_onlyprovidedcompilers.py | 168 ++++++++++++++++++ 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 tests/flit_cli/flit_update/data/onlyprovidedcompilers.toml create mode 100644 tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py diff --git a/tests/flit_cli/flit_update/README.md b/tests/flit_cli/flit_update/README.md index 8a3d8517..e5a1f2a1 100644 --- a/tests/flit_cli/flit_update/README.md +++ b/tests/flit_cli/flit_update/README.md @@ -8,10 +8,10 @@ optimization levels gives the default values 3. `tst_noswitches.py`: Test that specifying a compiler, but not specifying the switches list gives the default values -[ ] 4. Test that the provided list of optimization levels and switches are - used, and nothing more. -[ ] 5. Test that by only specifying one or two compilers, only those specified - are used +4. `tst_onlyprovidedoptlswitches.py`: Test that the provided list of + optimization levels and switches are used, and nothing more. +5. `tst_onlyprovidedcompilers.py`: Test that by only specifying one compiler, + only that specified compiler is used [ ] 6. Test error cases, such as specifying more than one type of a compiler # Needed tests diff --git a/tests/flit_cli/flit_update/data/onlyprovidedcompilers.toml b/tests/flit_cli/flit_update/data/onlyprovidedcompilers.toml new file mode 100644 index 00000000..131b55a9 --- /dev/null +++ b/tests/flit_cli/flit_update/data/onlyprovidedcompilers.toml @@ -0,0 +1,6 @@ +# Test only providing g++ + +[[compiler]] +binary = '/usr/bin/my-g++' +name = 'g++' +type = 'gcc' diff --git a/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py b/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py new file mode 100644 index 00000000..b75f303a --- /dev/null +++ b/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py @@ -0,0 +1,168 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests only providing gcc and no other compiler. Tests that +- the binary is taken from the configuration file +- the other two compilers are not present (i.e. clang and intel) + +>>> from io import StringIO +>>> import os +>>> import shutil + +>>> testconf = 'data/onlyprovidedcompilers.toml' +>>> class UpdateTestError(RuntimeError): pass + +>>> def deref_makelist(name): +... return sorted([' '.join(makevars[x]) for x in makevars[name]]) +>>> def get_default_compiler(typename): +... defaults = th.util.get_default_toml() +... default_compiler = [x for x in defaults['compiler'] +... if x['type'] == typename] +... assert len(default_compiler) == 1 +... return default_compiler[0] + +>>> with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) +... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to initialize flit directory') +... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) +... with StringIO() as ostream: +... retval = th.flit.main(['update', '-C', temp_dir], +... outstream=ostream) +... update_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to update Makefile') +... makevars = th.util.extract_make_vars(directory=temp_dir) + +Get default values for each compiler from the default configuration + +>>> print('\\n'.join(init_out)) # doctest:+ELLIPSIS +Creating .../flit-config.toml +Creating .../custom.mk +Creating .../main.cpp +Creating .../tests/Empty.cpp +Creating .../Makefile + +>>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS +Updating .../Makefile + +Check that the compiler binaries are the default values +>>> makevars['GCC'] +['/usr/bin/my-g++'] + +>>> makevars['CLANG'] +['None'] + +>>> makevars['INTEL'] +['None'] + +>>> makevars['COMPILERS'] +['GCC'] + +>>> 'OPCODES_GCC' in makevars +True +>>> 'SWITCHES_GCC' in makevars +True +>>> 'OPCODES_CLANG' in makevars +False +>>> 'SWITCHES_CLANG' in makevars +False +>>> 'OPCODES_INTEL' in makevars +False +>>> 'SWITCHES_INTEL' in makevars +False +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From f16237244bb32297afa2633a9c242d523055b7cf Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 18:00:14 -0700 Subject: [PATCH 182/196] tests/flit_update: add tst_badconfig.py This tests error paths in handling the config file --- scripts/flitcli/flit.py | 13 +- scripts/flitcli/flit_update.py | 6 - tests/flit_cli/flit_update/README.md | 3 +- tests/flit_cli/flit_update/tst_badconfig.py | 201 ++++++++++++++++++++ 4 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 tests/flit_cli/flit_update/tst_badconfig.py diff --git a/scripts/flitcli/flit.py b/scripts/flitcli/flit.py index f5ae92bb..8317158a 100755 --- a/scripts/flitcli/flit.py +++ b/scripts/flitcli/flit.py @@ -160,7 +160,7 @@ def generate_help_documentation(subcom_map): return (parser.format_help(), help_subparser.format_help()) -def main(arguments, outstream=None): +def main(arguments, outstream=None, errstream=None): ''' Main logic here. @@ -168,14 +168,19 @@ def main(arguments, outstream=None): optional outstream parameter. You can use this to capture the stdout that would go to the console and put it into a StringStream or maybe a file. ''' - if outstream is None: + if outstream is None and errstream is None: return _main_impl(arguments) + oldout = sys.stdout + olderr = sys.stderr try: - oldout = sys.stdout - sys.stdout = outstream + if outstream is not None: + sys.stdout = outstream + if errstream is not None: + sys.stderr = errstream return _main_impl(arguments) finally: sys.stdout = oldout + sys.stderr = olderr def _main_impl(arguments): 'Implementation of main' diff --git a/scripts/flitcli/flit_update.py b/scripts/flitcli/flit_update.py index 3276fca3..183caf77 100644 --- a/scripts/flitcli/flit_update.py +++ b/scripts/flitcli/flit_update.py @@ -305,18 +305,12 @@ def main(arguments, prog=sys.argv[0]): if x['name'] == dev_build['compiler_name']] assert len(matching_dev_compilers) > 0, \ 'Compiler name {0} not found'.format(dev_build['compiler_name']) - assert len(matching_dev_compilers) < 2, \ - 'Multiple compilers with name {0} found' \ - .format(dev_build['compiler_name']) ground_truth = projconf['ground_truth'] matching_gt_compilers = [x for x in projconf['compiler'] if x['name'] == ground_truth['compiler_name']] assert len(matching_gt_compilers) > 0, \ 'Compiler name {0} not found'.format(ground_truth['compiler_name']) - assert len(matching_gt_compilers) < 2, \ - 'Multiple compilers with name {0} found' \ - .format(ground_truth['compiler_name']) base_compilers = {x.upper(): None for x in _supported_compiler_types} base_compilers.update({compiler['type'].upper(): compiler['binary'] diff --git a/tests/flit_cli/flit_update/README.md b/tests/flit_cli/flit_update/README.md index e5a1f2a1..e699da98 100644 --- a/tests/flit_cli/flit_update/README.md +++ b/tests/flit_cli/flit_update/README.md @@ -12,7 +12,8 @@ optimization levels and switches are used, and nothing more. 5. `tst_onlyprovidedcompilers.py`: Test that by only specifying one compiler, only that specified compiler is used -[ ] 6. Test error cases, such as specifying more than one type of a compiler +6. `tst_badconfig.py`: Tests error cases in the configuration file, such as + specifying more than one of a certain type of compiler # Needed tests diff --git a/tests/flit_cli/flit_update/tst_badconfig.py b/tests/flit_cli/flit_update/tst_badconfig.py new file mode 100644 index 00000000..4e12215c --- /dev/null +++ b/tests/flit_cli/flit_update/tst_badconfig.py @@ -0,0 +1,201 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- + +''' +Tests error cases in the configuration file, such as specifying more than one of a certain type of compiler. + +>>> from io import StringIO +>>> import os +>>> import shutil + +>>> class UpdateTestError(RuntimeError): pass + +>>> def deref_makelist(name): +... return sorted([' '.join(makevars[x]) for x in makevars[name]]) + +>>> def runconfig(configstr): +... with th.tempdir() as temp_dir: +... with StringIO() as ostream: +... retval = th.flit.main(['init', '-C', temp_dir], +... outstream=ostream, errstream=ostream) +... init_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to initialize flit directory') +... with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as fout: +... print(configstr, file=fout, flush=True) +... with StringIO() as ostream: +... retval = th.flit.main(['update', '-C', temp_dir], +... outstream=ostream, errstream=ostream) +... update_out = ostream.getvalue().splitlines() +... if retval != 0: +... raise UpdateTestError('Failed to update Makefile: ' + +... ' '.join(update_out)) +... makevars = th.util.extract_make_vars(directory=temp_dir) +... return (init_out, update_out, makevars) + +>>> configstr = \\ +... '[dev_build]\\n' \\ +... 'compiler_name = \\'name-does-not-exist\\'\\n' +>>> runconfig(configstr) +Traceback (most recent call last): +... +AssertionError: Compiler name name-does-not-exist not found + +>>> configstr = \\ +... '[ground_truth]\\n' \\ +... 'compiler_name = \\'another-name-that-does-not-exist\\'\\n' +>>> runconfig(configstr) +Traceback (most recent call last): +... +AssertionError: Compiler name another-name-that-does-not-exist not found + +>>> runconfig('[compiler]\\n') +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml improperly configured, needs [[compiler]] section + +>>> runconfig('[[compiler]]\\n') +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{}" is missing the "name" field + +>>> runconfig('[[compiler]]\\n' +... 'name = \\'hello\\'\\n') +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{'name': 'hello'}" is missing the "type" field + +>>> runconfig('[[compiler]]\\n' +... 'name = \\'hello\\'\\n' +... 'type = \\'gcc\\'\\n') # doctest:+ELLIPSIS +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{...}" is missing the "binary" field + +>>> runconfig('[[compiler]]\\n' +... 'binary = \\'my-special-compiler\\'\\n' +... 'name = \\'hello\\'\\n' +... 'type = \\'my-unsupported-type\\'\\n') +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml: unsupported compiler type "my-unsupported-type" + +>>> runconfig('[[compiler]]\\n' +... 'binary = \\'gcc\\'\\n' +... 'name = \\'gcc\\'\\n' +... 'type = \\'gcc\\'\\n' +... '\\n' +... '[[compiler]]\\n' +... 'binary = \\'gcc-2\\'\\n' +... 'name = \\'gcc-2\\'\\n' +... 'type = \\'gcc\\'\\n' +... ) +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml: cannot have multiple compilers of the same type (gcc) + +>>> runconfig('[[compiler]]\\n' +... 'binary = \\'gcc\\'\\n' +... 'name = \\'gcc\\'\\n' +... 'type = \\'gcc\\'\\n' +... '\\n' +... '[[compiler]]\\n' +... 'binary = \\'gcc-2\\'\\n' +... 'name = \\'gcc\\'\\n' +... 'type = \\'clang\\'\\n' +... ) +Traceback (most recent call last): +... +UpdateTestError: Failed to update Makefile: Error: flit-config.toml: cannot have multiple compilers of the same name (gcc) +''' + +# Test setup before the docstring is run. +import sys +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) From 0adf88e4557d6b12079ffeafd548cd24b4fe2112 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 18:37:52 -0700 Subject: [PATCH 183/196] tests/flit_update: make common functions file --- tests/flit_cli/flit_update/tst_badconfig.py | 39 ++---- .../flit_cli/flit_update/tst_common_funcs.py | 132 ++++++++++++++++++ tests/flit_cli/flit_update/tst_nocompilers.py | 46 ++---- tests/flit_cli/flit_update/tst_nooptl.py | 37 ++--- tests/flit_cli/flit_update/tst_noswitches.py | 39 ++---- .../flit_update/tst_onlyprovidedcompilers.py | 30 +--- .../tst_onlyprovidedoptlswitches.py | 42 ++---- 7 files changed, 191 insertions(+), 174 deletions(-) create mode 100644 tests/flit_cli/flit_update/tst_common_funcs.py diff --git a/tests/flit_cli/flit_update/tst_badconfig.py b/tests/flit_cli/flit_update/tst_badconfig.py index 4e12215c..495501f0 100644 --- a/tests/flit_cli/flit_update/tst_badconfig.py +++ b/tests/flit_cli/flit_update/tst_badconfig.py @@ -87,30 +87,7 @@ >>> import os >>> import shutil ->>> class UpdateTestError(RuntimeError): pass - ->>> def deref_makelist(name): -... return sorted([' '.join(makevars[x]) for x in makevars[name]]) - ->>> def runconfig(configstr): -... with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], -... outstream=ostream, errstream=ostream) -... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to initialize flit directory') -... with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as fout: -... print(configstr, file=fout, flush=True) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream, errstream=ostream) -... update_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to update Makefile: ' + -... ' '.join(update_out)) -... makevars = th.util.extract_make_vars(directory=temp_dir) -... return (init_out, update_out, makevars) +>>> from tst_common_funcs import runconfig >>> configstr = \\ ... '[dev_build]\\n' \\ @@ -131,25 +108,25 @@ >>> runconfig('[compiler]\\n') Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml improperly configured, needs [[compiler]] section +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml improperly configured, needs [[compiler]] section >>> runconfig('[[compiler]]\\n') Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{}" is missing the "name" field +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{}" is missing the "name" field >>> runconfig('[[compiler]]\\n' ... 'name = \\'hello\\'\\n') Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{'name': 'hello'}" is missing the "type" field +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{'name': 'hello'}" is missing the "type" field >>> runconfig('[[compiler]]\\n' ... 'name = \\'hello\\'\\n' ... 'type = \\'gcc\\'\\n') # doctest:+ELLIPSIS Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{...}" is missing the "binary" field +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml: compiler "{...}" is missing the "binary" field >>> runconfig('[[compiler]]\\n' ... 'binary = \\'my-special-compiler\\'\\n' @@ -157,7 +134,7 @@ ... 'type = \\'my-unsupported-type\\'\\n') Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml: unsupported compiler type "my-unsupported-type" +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml: unsupported compiler type "my-unsupported-type" >>> runconfig('[[compiler]]\\n' ... 'binary = \\'gcc\\'\\n' @@ -171,7 +148,7 @@ ... ) Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml: cannot have multiple compilers of the same type (gcc) +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml: cannot have multiple compilers of the same type (gcc) >>> runconfig('[[compiler]]\\n' ... 'binary = \\'gcc\\'\\n' @@ -185,7 +162,7 @@ ... ) Traceback (most recent call last): ... -UpdateTestError: Failed to update Makefile: Error: flit-config.toml: cannot have multiple compilers of the same name (gcc) +tst_common_funcs.UpdateTestError: Failed to update Makefile: Error: flit-config.toml: cannot have multiple compilers of the same name (gcc) ''' # Test setup before the docstring is run. diff --git a/tests/flit_cli/flit_update/tst_common_funcs.py b/tests/flit_cli/flit_update/tst_common_funcs.py new file mode 100644 index 00000000..a34b6fd3 --- /dev/null +++ b/tests/flit_cli/flit_update/tst_common_funcs.py @@ -0,0 +1,132 @@ +# -- LICENSE BEGIN -- +# +# Copyright (c) 2015-2018, Lawrence Livermore National Security, LLC. +# +# Produced at the Lawrence Livermore National Laboratory +# +# Written by +# Michael Bentley (mikebentley15@gmail.com), +# Geof Sawaya (fredricflinstone@gmail.com), +# and Ian Briggs (ian.briggs@utah.edu) +# under the direction of +# Ganesh Gopalakrishnan +# and Dong H. Ahn. +# +# LLNL-CODE-743137 +# +# All rights reserved. +# +# This file is part of FLiT. For details, see +# https://pruners.github.io/flit +# Please also read +# https://github.com/PRUNERS/FLiT/blob/master/LICENSE +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# - Redistributions of source code must retain the above copyright +# notice, this list of conditions and the disclaimer below. +# +# - Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the disclaimer +# (as noted below) in the documentation and/or other materials +# provided with the distribution. +# +# - Neither the name of the LLNS/LLNL nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL LAWRENCE LIVERMORE NATIONAL +# SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +# THE POSSIBILITY OF SUCH DAMAGE. +# +# Additional BSD Notice +# +# 1. This notice is required to be provided under our contract +# with the U.S. Department of Energy (DOE). This work was +# produced at Lawrence Livermore National Laboratory under +# Contract No. DE-AC52-07NA27344 with the DOE. +# +# 2. Neither the United States Government nor Lawrence Livermore +# National Security, LLC nor any of their employees, makes any +# warranty, express or implied, or assumes any liability or +# responsibility for the accuracy, completeness, or usefulness of +# any information, apparatus, product, or process disclosed, or +# represents that its use would not infringe privately-owned +# rights. +# +# 3. Also, reference herein to any specific commercial products, +# process, or services by trade name, trademark, manufacturer or +# otherwise does not necessarily constitute or imply its +# endorsement, recommendation, or favoring by the United States +# Government or Lawrence Livermore National Security, LLC. The +# views and opinions of authors expressed herein do not +# necessarily state or reflect those of the United States +# Government or Lawrence Livermore National Security, LLC, and +# shall not be used for advertising or product endorsement +# purposes. +# +# -- LICENSE END -- +''' +This module holds common functions used in all of the tests for +`flit_update.py` +''' + +from io import StringIO +import os +import shutil +import sys + +before_path = sys.path[:] +sys.path.append('../..') +import test_harness as th +sys.path = before_path + +class UpdateTestError(RuntimeError): pass + +def deref_makelist(name, makevars): + return sorted([' '.join(makevars[x]) for x in makevars[name]]) + +def get_default_compiler(typename): + defaults = th.util.get_default_toml() + default_compiler = [x for x in defaults['compiler'] + if x['type'] == typename] + assert len(default_compiler) == 1 + return default_compiler[0] + +def runconfig(configstr): + with th.tempdir() as temp_dir: + with StringIO() as ostream: + retval = th.flit.main(['init', '-C', temp_dir], + outstream=ostream, errstream=ostream) + init_out = ostream.getvalue().splitlines() + if retval != 0: + raise UpdateTestError('Failed to initialize flit directory') + with open(os.path.join(temp_dir, 'flit-config.toml'), 'w') as fout: + print(configstr, file=fout, flush=True) + with StringIO() as ostream: + retval = th.flit.main(['update', '-C', temp_dir], + outstream=ostream, errstream=ostream) + update_out = ostream.getvalue().splitlines() + if retval != 0: + raise UpdateTestError('Failed to update Makefile: ' + + ' '.join(update_out)) + makevars = th.util.extract_make_vars(directory=temp_dir) + return (init_out, update_out, makevars) + +if __name__ == '__main__': + from doctest import testmod + failures, tests = testmod() + sys.exit(failures) diff --git a/tests/flit_cli/flit_update/tst_nocompilers.py b/tests/flit_cli/flit_update/tst_nocompilers.py index b6f464af..838623f3 100644 --- a/tests/flit_cli/flit_update/tst_nocompilers.py +++ b/tests/flit_cli/flit_update/tst_nocompilers.py @@ -88,32 +88,12 @@ >>> import os >>> import shutil +>>> from tst_common_funcs import ( +... deref_makelist, get_default_compiler, runconfig) + >>> testconf = 'data/nocompilers.toml' ->>> class UpdateTestError(RuntimeError): pass - ->>> def deref_makelist(name): -... return sorted([' '.join(makevars[x]) for x in makevars[name]]) ->>> def get_default_compiler(typename): -... defaults = th.util.get_default_toml() -... default_compiler = [x for x in defaults['compiler'] -... if x['type'] == typename] -... assert len(default_compiler) == 1 -... return default_compiler[0] - ->>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to initialize flit directory') -... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream) -... update_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to update Makefile') -... makevars = th.util.extract_make_vars(directory=temp_dir) +>>> with open(testconf, 'r') as fin: +... init_out, update_out, makevars = runconfig(fin.read()) Get default values for each compiler from the default configuration @@ -153,24 +133,28 @@ >>> sorted(makevars['COMPILERS']) ['CLANG', 'GCC', 'INTEL'] ->>> deref_makelist('OPCODES_GCC') == sorted(default_gcc['optimization_levels']) +>>> deref_makelist('OPCODES_GCC', makevars) == \\ +... sorted(default_gcc['optimization_levels']) True ->>> deref_makelist('OPCODES_CLANG') == \\ +>>> deref_makelist('OPCODES_CLANG', makevars) == \\ ... sorted(default_clang['optimization_levels']) True ->>> deref_makelist('OPCODES_INTEL') == \\ +>>> deref_makelist('OPCODES_INTEL', makevars) == \\ ... sorted(default_intel['optimization_levels']) True ->>> deref_makelist('SWITCHES_GCC') == sorted(default_gcc['switches_list']) +>>> deref_makelist('SWITCHES_GCC', makevars) == \\ +... sorted(default_gcc['switches_list']) True ->>> deref_makelist('SWITCHES_CLANG') == sorted(default_clang['switches_list']) +>>> deref_makelist('SWITCHES_CLANG', makevars) == \\ +... sorted(default_clang['switches_list']) True ->>> deref_makelist('SWITCHES_INTEL') == sorted(default_intel['switches_list']) +>>> deref_makelist('SWITCHES_INTEL', makevars) == \\ +... sorted(default_intel['switches_list']) True ''' diff --git a/tests/flit_cli/flit_update/tst_nooptl.py b/tests/flit_cli/flit_update/tst_nooptl.py index 2d409ea0..2570d89e 100644 --- a/tests/flit_cli/flit_update/tst_nooptl.py +++ b/tests/flit_cli/flit_update/tst_nooptl.py @@ -87,32 +87,12 @@ >>> import os >>> import shutil ->>> testconf = 'data/nooptl.toml' ->>> class UpdateTestError(RuntimeError): pass - ->>> def deref_makelist(name): -... return sorted([' '.join(makevars[x]) for x in makevars[name]]) ->>> def get_default_compiler(typename): -... defaults = th.util.get_default_toml() -... default_compiler = [x for x in defaults['compiler'] -... if x['type'] == typename] -... assert len(default_compiler) == 1 -... return default_compiler[0] +>>> from tst_common_funcs import ( +... deref_makelist, get_default_compiler, runconfig) ->>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to initialize flit directory') -... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream) -... update_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to update Makefile') -... makevars = th.util.extract_make_vars(directory=temp_dir) +>>> testconf = 'data/nooptl.toml' +>>> with open(testconf, 'r') as fin: +... init_out, update_out, makevars = runconfig(fin.read()) Get default values for each compiler from the default configuration >>> default_gcc = get_default_compiler('gcc') @@ -129,14 +109,15 @@ >>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS Updating .../Makefile ->>> deref_makelist('OPCODES_GCC') == sorted(default_gcc['optimization_levels']) +>>> deref_makelist('OPCODES_GCC', makevars) == \\ +... sorted(default_gcc['optimization_levels']) True ->>> deref_makelist('OPCODES_CLANG') == \\ +>>> deref_makelist('OPCODES_CLANG', makevars) == \\ ... sorted(default_clang['optimization_levels']) True ->>> deref_makelist('OPCODES_INTEL') == \\ +>>> deref_makelist('OPCODES_INTEL', makevars) == \\ ... sorted(default_intel['optimization_levels']) True ''' diff --git a/tests/flit_cli/flit_update/tst_noswitches.py b/tests/flit_cli/flit_update/tst_noswitches.py index 5fe2a6c3..b07091c2 100644 --- a/tests/flit_cli/flit_update/tst_noswitches.py +++ b/tests/flit_cli/flit_update/tst_noswitches.py @@ -86,32 +86,12 @@ >>> from io import StringIO >>> import shutil ->>> testconf = 'data/noswitches.toml' ->>> class UpdateTestError(RuntimeError): pass - ->>> def deref_makelist(name): -... return sorted([' '.join(makevars[x]) for x in makevars[name]]) ->>> def get_default_compiler(typename): -... defaults = th.util.get_default_toml() -... default_compiler = [x for x in defaults['compiler'] -... if x['type'] == typename] -... assert len(default_compiler) == 1 -... return default_compiler[0] +>>> from tst_common_funcs import ( +... deref_makelist, get_default_compiler, runconfig) ->>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to initialize flit directory') -... _ = shutil.copy(testconf, temp_dir) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream) -... update_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to update Makefile') -... makevars = th.util.extract_make_vars(directory=temp_dir) +>>> testconf = 'data/noswitches.toml' +>>> with open(testconf, 'r') as fin: +... init_out, update_out, makevars = runconfig(fin.read()) Get default values for each compiler from the default configuration @@ -129,13 +109,16 @@ >>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS Updating .../Makefile ->>> deref_makelist('SWITCHES_GCC') == sorted(default_gcc['switches_list']) +>>> deref_makelist('SWITCHES_GCC', makevars) == \\ +... sorted(default_gcc['switches_list']) True ->>> deref_makelist('SWITCHES_CLANG') == sorted(default_clang['switches_list']) +>>> deref_makelist('SWITCHES_CLANG', makevars) == \\ +... sorted(default_clang['switches_list']) True ->>> deref_makelist('SWITCHES_INTEL') == sorted(default_intel['switches_list']) +>>> deref_makelist('SWITCHES_INTEL', makevars) == \\ +... sorted(default_intel['switches_list']) True ''' diff --git a/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py b/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py index b75f303a..f0f48af7 100644 --- a/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py +++ b/tests/flit_cli/flit_update/tst_onlyprovidedcompilers.py @@ -89,32 +89,12 @@ >>> import os >>> import shutil ->>> testconf = 'data/onlyprovidedcompilers.toml' ->>> class UpdateTestError(RuntimeError): pass - ->>> def deref_makelist(name): -... return sorted([' '.join(makevars[x]) for x in makevars[name]]) ->>> def get_default_compiler(typename): -... defaults = th.util.get_default_toml() -... default_compiler = [x for x in defaults['compiler'] -... if x['type'] == typename] -... assert len(default_compiler) == 1 -... return default_compiler[0] +>>> from tst_common_funcs import ( +... deref_makelist, get_default_compiler, runconfig) ->>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to initialize flit directory') -... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream) -... update_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to update Makefile') -... makevars = th.util.extract_make_vars(directory=temp_dir) +>>> testconf = 'data/onlyprovidedcompilers.toml' +>>> with open(testconf, 'r') as fin: +... init_out, update_out, makevars = runconfig(fin.read()) Get default values for each compiler from the default configuration diff --git a/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py b/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py index c0fe2530..8299b1f9 100644 --- a/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py +++ b/tests/flit_cli/flit_update/tst_onlyprovidedoptlswitches.py @@ -87,32 +87,12 @@ >>> import shutil >>> import os +>>> from tst_common_funcs import ( +... deref_makelist, get_default_compiler, runconfig) + >>> testconf = 'data/onlyprovidedoptlswitches.toml' ->>> class UpdateTestError(RuntimeError): pass - ->>> def deref_makelist(name): -... return sorted([' '.join(makevars[x]) for x in makevars[name]]) ->>> def get_default_compiler(typename): -... defaults = th.util.get_default_toml() -... default_compiler = [x for x in defaults['compiler'] -... if x['type'] == typename] -... assert len(default_compiler) == 1 -... return default_compiler[0] - ->>> with th.tempdir() as temp_dir: -... with StringIO() as ostream: -... retval = th.flit.main(['init', '-C', temp_dir], outstream=ostream) -... init_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to initialize flit directory') -... _ = shutil.copy(testconf, os.path.join(temp_dir, 'flit-config.toml')) -... with StringIO() as ostream: -... retval = th.flit.main(['update', '-C', temp_dir], -... outstream=ostream) -... update_out = ostream.getvalue().splitlines() -... if retval != 0: -... raise UpdateTestError('Failed to update Makefile') -... makevars = th.util.extract_make_vars(directory=temp_dir) +>>> with open(testconf, 'r') as fin: +... init_out, update_out, makevars = runconfig(fin.read()) Get default values for each compiler from the default configuration @@ -130,22 +110,22 @@ >>> print('\\n'.join(update_out)) # doctest:+ELLIPSIS Updating .../Makefile ->>> deref_makelist('OPCODES_GCC') +>>> deref_makelist('OPCODES_GCC', makevars) ['-O2', '-O3'] ->>> deref_makelist('OPCODES_CLANG') +>>> deref_makelist('OPCODES_CLANG', makevars) ['-O0', '-O1'] ->>> deref_makelist('OPCODES_INTEL') +>>> deref_makelist('OPCODES_INTEL', makevars) ['-Ofast', '-Og'] ->>> deref_makelist('SWITCHES_GCC') +>>> deref_makelist('SWITCHES_GCC', makevars) ['', '-funsafe-math-optimizations', '-mavx'] ->>> deref_makelist('SWITCHES_CLANG') +>>> deref_makelist('SWITCHES_CLANG', makevars) ['-ffinite-math-only', '-ffloat-store'] ->>> deref_makelist('SWITCHES_INTEL') +>>> deref_makelist('SWITCHES_INTEL', makevars) ['-DUSE_MPI', '-fmerge-all-constants', '-fp-model fast=1', '-fp-model fast=2'] ''' From 663b3aa6f396c853ff6c82f572455fc0d1f72217 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 21:06:55 -0700 Subject: [PATCH 184/196] tests/flit_update: Add docstring tests for tst_common_funcs.py --- .../flit_cli/flit_update/tst_common_funcs.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/flit_cli/flit_update/tst_common_funcs.py b/tests/flit_cli/flit_update/tst_common_funcs.py index a34b6fd3..93e4e0ef 100644 --- a/tests/flit_cli/flit_update/tst_common_funcs.py +++ b/tests/flit_cli/flit_update/tst_common_funcs.py @@ -97,9 +97,56 @@ class UpdateTestError(RuntimeError): pass def deref_makelist(name, makevars): + ''' + The makevars are a dictionary of key list pairs of strings in the + form of a dictionary. This function is useful when a variable within + makevars contains a list of other variables within makevars. This + dereferences all of them and returns a sorted list of them all. + + @param name (str) variable name from makevars + @param makevars (dict{str: list(str)}) all makefile variables + + See some examples to see exactly what to expect: + + >>> makevars = { + ... 'A': ['one', 'first'], 'B': ['two', 'second'], + ... 'C': ['three', 'third'], 'D': ['four', 'fourth'], + ... 'evens': ['D', 'B'], 'odds': ['A', 'C'] + ... } + + >>> deref_makelist('evens', makevars) + ['four fourth', 'two second'] + + >>> deref_makelist('odds', makevars) + ['one first', 'three third'] + ''' return sorted([' '.join(makevars[x]) for x in makevars[name]]) def get_default_compiler(typename): + ''' + Returns the default compiler from the default toml configuration. + + @param typename (str) name of the type of compiler to extract + @return (dict) default compiler values from the default flit config + + >>> gcc = get_default_compiler('gcc') + >>> gcc['binary'] + 'g++' + >>> gcc['type'] + 'gcc' + >>> gcc['name'] + 'g++' + + >>> clang = get_default_compiler('clang') + >>> clang['optimization_levels'] + ['-O0', '-O1', '-O2', '-O3'] + >>> clang['binary'] + 'clang++' + + >>> intel = get_default_compiler('intel') + >>> intel['binary'] + 'icpc' + ''' defaults = th.util.get_default_toml() default_compiler = [x for x in defaults['compiler'] if x['type'] == typename] @@ -107,6 +154,21 @@ def get_default_compiler(typename): return default_compiler[0] def runconfig(configstr): + ''' + Runs `flit init`, then writes the given configuration string into + `flit-config.toml`, and then runs `flit update`. + + @param configstr (str) contents to put into `flit-config.toml` + @return (tuple(list(str), list(str), dict{str: list(str)}) + Three things are returned: + 1. init_out (list(str)): the lines of output from `flit init` + 2. update_out (list(str)): the lines of output from `flit update` + 3. makevars (dict{str: list(str)}): all Makefile variables from the + `Makefile` generated from `flit update` + + I will not put tests for this function here since this is tested by its use + in the other test functions. + ''' with th.tempdir() as temp_dir: with StringIO() as ostream: retval = th.flit.main(['init', '-C', temp_dir], From 705b727459e903331ba8f52335b6a032175fbdb1 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Wed, 12 Dec 2018 21:08:40 -0700 Subject: [PATCH 185/196] tests/flit_update/tst_common_funcs.py: pylint fixes --- tests/flit_cli/flit_update/tst_common_funcs.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/flit_cli/flit_update/tst_common_funcs.py b/tests/flit_cli/flit_update/tst_common_funcs.py index 93e4e0ef..f1cffa70 100644 --- a/tests/flit_cli/flit_update/tst_common_funcs.py +++ b/tests/flit_cli/flit_update/tst_common_funcs.py @@ -86,7 +86,6 @@ from io import StringIO import os -import shutil import sys before_path = sys.path[:] @@ -94,7 +93,9 @@ import test_harness as th sys.path = before_path -class UpdateTestError(RuntimeError): pass +class UpdateTestError(RuntimeError): + 'Error used in runconfig()' + pass def deref_makelist(name, makevars): ''' @@ -157,7 +158,7 @@ def runconfig(configstr): ''' Runs `flit init`, then writes the given configuration string into `flit-config.toml`, and then runs `flit update`. - + @param configstr (str) contents to put into `flit-config.toml` @return (tuple(list(str), list(str), dict{str: list(str)}) Three things are returned: From eaddc9ee421a4afb8b4f9b9a2caefe1b3c51b2b6 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 18 Dec 2018 12:32:23 -0700 Subject: [PATCH 186/196] update MPI documentation Specifically with section "Test Return Values" --- documentation/mpi-support.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/documentation/mpi-support.md b/documentation/mpi-support.md index af4c7ad6..80df64d7 100644 --- a/documentation/mpi-support.md +++ b/documentation/mpi-support.md @@ -74,12 +74,34 @@ global pointer even if MPI is not enabled and you can have logic based on the rank and size of the MPI world. +## Test Return Values + +Under FLiT, you can write tests using MPI with multiple processes (as long as +the result is deterministic). To prevent confusion with multiple test return +values, one from each process, FLiT will ignore the test result value from all +processes except for the one with rank 0. Therefore, all calculated results +must be communicated to rank 0 in order to have it be captured by the FLiT +framework. + +If you find this does not fit with your use case, please submit an +[issue](https://github.com/PRUNERS/FLiT/issues/new?template=feature_request.md) +on GitHub. For example, it may be that users may want to configure whether +each result is captured individually and checked at test time, process by +process. However, That approach will not work in all cases, such as the +producer-consumer model where processes may end up getting different data and +tasks. For now, enforcing users to communicate with rank 0 is the most +straightforward way to ensure determinism. + + ## Conditional Compilation If you want your tests to conditionally use MPI, there is a macro-defined variable you can condition off of to disable or enable certain code. That variable is `FLIT_USE_MPI`. For example +Note: even when MPI is disabled, the global `flit::mpi` variable is still +available. + ```c++ T grid[1024][1024]; int nrows = 1024 / mpi->size; From 2728341e4654bed79a0e6f32695bf6a19560eda8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 8 Jan 2019 09:14:31 -0700 Subject: [PATCH 187/196] Fix review finding --- data/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/Makefile.in b/data/Makefile.in index 1d9e7060..3afc9237 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -348,7 +348,7 @@ TARGET_OUTS := # @param 1: compiler variable name (e.g. CLANG) # @param 2: optimization level variable name (e.g. O2) -# @param 3: switches variable name (e.g. --use_fast_math) +# @param 3: switches variable name (e.g. USE_FAST_MATH) define RECURSION_RULE TARGETS += $$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip $2) From b950ed57c3d1414816c4ece5fd45aa74457d968e Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 4 Apr 2019 17:41:49 -0600 Subject: [PATCH 188/196] flitelf: fix _gen_file_line_table for empty dwarfinfo --- scripts/flitcli/flitelf.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py index afa4d370..76d70081 100644 --- a/scripts/flitcli/flitelf.py +++ b/scripts/flitcli/flitelf.py @@ -95,7 +95,8 @@ from elftools.elf.elffile import ELFFile from elftools.elf.sections import SymbolTableSection -SymbolTuple = namedtuple('SymbolTuple', 'src, symbol, demangled, fname, lineno') +SymbolTuple = namedtuple('SymbolTuple', + 'src, symbol, demangled, fname, lineno') SymbolTuple.__doc__ = ''' Tuple containing information about the symbols in a file. Has the following attributes: @@ -223,6 +224,15 @@ def _locate_symbols(elffile, symbols): def _gen_file_line_table(dwarfinfo): ''' Generates and returns a list of (filename, lineno, startaddr, endaddr). + + Tests that an empty dwarfinfo object will result in an empty return list + >>> class FakeDwarf: + ... def __init__(self): + ... pass + ... def iter_CUs(self): + ... return [] + >>> _gen_file_line_table(FakeDwarf()) + [] ''' # generate the table table = [] @@ -238,13 +248,18 @@ def _gen_file_line_table(dwarfinfo): if prevstate is not None: filename = lineprog['file_entry'][prevstate.file - 1].name dirno = lineprog['file_entry'][prevstate.file - 1].dir_index - filepath = os.path.join(lineprog['include_directory'][dirno - 1], filename) + filepath = os.path.join( + lineprog['include_directory'][dirno - 1], filename) line = prevstate.line fromaddr = prevstate.address toaddr = max(fromaddr, entry.state.address) table.append((filepath, line, fromaddr, toaddr)) prevstate = entry.state + # If there are no functions, then return an empty list + if len(table) == 0: + return [] + # consolidate the table consolidated = [] prev = table[0] From a871b0ffeecac611f70863fb669fbe52b27fd087 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 4 Apr 2019 18:17:18 -0600 Subject: [PATCH 189/196] flitelf.py: Put an early exit in _locate_symbols() If the symbols list is empty, then return early, never even checking for dwarfinfo. That way, if there are no functions to match up, we do not even care about the dwarfinfo object. --- scripts/flitcli/flitelf.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/flitcli/flitelf.py b/scripts/flitcli/flitelf.py index afa4d370..787743bc 100644 --- a/scripts/flitcli/flitelf.py +++ b/scripts/flitcli/flitelf.py @@ -202,7 +202,15 @@ def _locate_symbols(elffile, symbols): If the file does not have DWARF info or a symbol is not found, an exception is raised + + Test that even without a proper elffile, if there are no symbols to match, + then no error occurs and you can be on your merry way. + >>> _locate_symbols(object(), []) + [] ''' + if len(symbols) == 0: + return [] + if not elffile.has_dwarf_info(): raise RuntimeError('Elf file has no DWARF info') From 177ea7eeac3069ca72515df52d727a9fe2432bf8 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 4 Apr 2019 19:43:12 -0600 Subject: [PATCH 190/196] Makefile.in: add CLANG_REQUIRED to dev and gt builds if clang --- data/Makefile.in | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/data/Makefile.in b/data/Makefile.in index 3afc9237..792a9c9c 100644 --- a/data/Makefile.in +++ b/data/Makefile.in @@ -121,6 +121,7 @@ MPIRUN_ARGS := {mpirun_args} # initalize some variables to be appended later CC_REQUIRED := DEV_CFLAGS := +GT_CFLAGS := LD_REQUIRED := RUNWRAP = $(RUN_WRAPPER) @@ -237,6 +238,13 @@ GCC_TOOLCHAIN := $(dir $(shell which $(GCC) 2>/dev/null))/.. CLANG_REQUIRED += --gcc-toolchain=$(GCC_TOOLCHAIN) endif +ifeq ($(DEV_CXX_TYPE),$(CLANG_TYPE)) +DEV_CFLAGS += $(CLANG_REQUIRED) +endif +ifeq ($(GT_CXX_TYPE),$(CLANG_TYPE)) +GT_CFLAGS += $(CLANG_REQUIRED) +endif + # Compiler setting targets # taken from: https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html # among other places @@ -285,9 +293,9 @@ rec: $(R_TARGET) # clang's flag is -nopie # else if the current compiler is not GCC 4 or 5, then enable -no-pie # GCC 4 and 5 do not need -no-pie since that is the default -ifeq ($($(R_CUR_COMPILER)_TYPE),clang) +ifeq ($($(R_CUR_COMPILER)_TYPE),$(CLANG_TYPE)) LD_REQUIRED += -nopie -else ifeq ($($(R_CUR_COMPILER)_TYPE), gcc) +else ifeq ($($(R_CUR_COMPILER)_TYPE),$(GCC_TYPE)) ifeq ($(call IS_VER_4_OR_5,$($(R_CUR_COMPILER))),0) LD_REQUIRED += -no-pie endif @@ -316,18 +324,18 @@ else # ifndef R_IS_RECURSED # clang's flag is -nopie # else if the current compiler is not GCC 4 or 5, then enable -no-pie # GCC 4 and 5 do not need -no-pie since that is the default -ifeq ($(DEV_CXX_TYPE),clang) +ifeq ($(DEV_CXX_TYPE),$(CLANG_TYPE)) DEV_LDFLAGS += -nopie -else ifeq ($(DEV_CXX_TYPE), gcc) +else ifeq ($(DEV_CXX_TYPE),$(GCC_TYPE)) ifeq ($(call IS_VER_4_OR_5,$(DEV_CXX)),0) DEV_LDFLAGS += -no-pie endif endif # same for the gt compiler -ifeq ($(GT_CXX_TYPE),clang) +ifeq ($(GT_CXX_TYPE),$(CLANG_TYPE)) GT_LDFLAGS += -nopie -else ifeq ($(GT_CXX_TYPE), gcc) +else ifeq ($(GT_CXX_TYPE),$(GCC_TYPE)) ifeq ($(call IS_VER_4_OR_5,$(GT_CXX)),0) GT_LDFLAGS += -no-pie endif @@ -482,7 +490,7 @@ $(GT_TARGET): $(GT_OBJ) Makefile custom.mk $(GT_CXX) $(CC_REQUIRED) -o $@ $(GT_OBJ) $(LD_REQUIRED) $(GT_LDFLAGS) $(OBJ_DIR)/%_gt.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(GT_CXX) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ + $(GT_CXX) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(GT_CFLAGS) $(DEPFLAGS) -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(GT_CXX)"' \ -DFLIT_OPTL='"$(GT_OPTL)"' \ @@ -490,7 +498,7 @@ $(OBJ_DIR)/%_gt.o: %.cpp Makefile custom.mk | $(OBJ_DIR) -DFLIT_FILENAME='"$(notdir $(GT_TARGET))"' $(OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(GT_CXX) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(GT_CXX) -g $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(GT_CFLAGS) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(GT_CXX)"' \ -DFLIT_OPTL='"$(GT_OPTL)"' \ From b2580eaa264d8f196612dc16a1094735d6ccef39 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 4 Apr 2019 19:51:34 -0600 Subject: [PATCH 191/196] Makefile_bisect_binary.in: add TROUBLE_TYPE variable Not yet used. But done as a first step. --- data/Makefile_bisect_binary.in | 3 ++- scripts/flitcli/flit_bisect.py | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/data/Makefile_bisect_binary.in b/data/Makefile_bisect_binary.in index 9ac5d402..14e9216e 100644 --- a/data/Makefile_bisect_binary.in +++ b/data/Makefile_bisect_binary.in @@ -97,9 +97,10 @@ PRECISION := {precision} TEST_CASE := {test_case} -TROUBLE_CXX := {trouble_cc} +TROUBLE_CXX := {trouble_cxx} TROUBLE_OPTL := {trouble_optl} TROUBLE_SWITCHES := {trouble_switches} +TROUBLE_CXX_TYPE := {trouble_type} BISECT_LINK := $(GT_CXX) TROUBLE_ID := {trouble_id} diff --git a/scripts/flitcli/flit_bisect.py b/scripts/flitcli/flit_bisect.py index f7028c21..1d378209 100644 --- a/scripts/flitcli/flit_bisect.py +++ b/scripts/flitcli/flit_bisect.py @@ -1451,9 +1451,10 @@ def compile_trouble(directory, compiler, optl, switches, verbose=False, 'flit_version': conf.version, 'precision': '', 'test_case': '', - 'trouble_cc': compiler, + 'trouble_cxx': compiler, 'trouble_optl': optl, 'trouble_switches': switches, + 'trouble_type': None, 'trouble_id': trouble_hash, 'link_flags': [], 'cpp_flags': [], @@ -1536,9 +1537,10 @@ def run_bisect(arguments, prog=sys.argv[0]): 'flit_version': conf.version, 'precision': args.precision, 'test_case': args.testcase, - 'trouble_cc': args.compiler, + 'trouble_cxx': args.compiler, 'trouble_optl': args.optl, 'trouble_switches': args.switches, + 'trouble_type': None, 'trouble_id': trouble_hash, 'link_flags': [], 'cpp_flags': [], From 517b9e60d7bdf24d195cd0e29d3e42382e403534 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Thu, 4 Apr 2019 20:13:17 -0600 Subject: [PATCH 192/196] Makefile_bisect_binary.in: utilize TROUBLE_CFLAGS It will now check to see if TROUBLE_CXX_TYPE is CLANG_TYPE, and if so it will add the --gcc-toolchain flag into TROUBLE_CFLAGS variable. However, we do not yet have a value in TROUBLE_CXX_TYPE, it is hard-coded to be None for now. --- data/Makefile_bisect_binary.in | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/data/Makefile_bisect_binary.in b/data/Makefile_bisect_binary.in index 14e9216e..5c9e6d65 100644 --- a/data/Makefile_bisect_binary.in +++ b/data/Makefile_bisect_binary.in @@ -125,12 +125,17 @@ SPLIT_SRC := {EXTRA_CC_FLAGS} {EXTRA_LD_FLAGS} -TROUBLE_LDFLAGS = - -# if the trouble compiler is not GCC 4 or 5, then add -no-pie -ifeq ($(call IS_GCC_4_OR_5,$(TROUBLE_CXX)),0) +TROUBLE_LDFLAGS := +TROUBLE_CFLAGS := + +ifeq ($(TROUBLE_CXX_TYPE),$(CLANG_TYPE)) + TROUBLE_LDFLAGS += -nopie + TROUBLE_CFLAGS += $(CLANG_REQUIRED) +else ifeq ($(TROUBLE_CXX_TYPE),$(GCC_TYPE)) +ifeq ($(call IS_VER_4_OR_5,$(TROUBLE_CXX)),0) TROUBLE_LDFLAGS += -no-pie endif +endif BUILD_GT_LOCAL := {build_gt_local} @@ -271,7 +276,7 @@ $(BISECT_OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(BISECT_OBJ_DIR) if [ -f "$(OBJ_DIR)/$*_gt_fPIC.o" ]; then \ ln -s "../../$(OBJ_DIR)/$*_gt_fPIC.o" "$@"; \ else \ - $(GT_CXX) $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(GT_CXX) $(GT_OPTL) $(GT_SWITCHES) $(CC_REQUIRED) $(GT_CFLAGS) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(GT_CXX)"' \ -DFLIT_OPTL='"$(GT_OPTL)"' \ @@ -282,7 +287,7 @@ $(BISECT_OBJ_DIR)/%_gt_fPIC.o: %.cpp Makefile custom.mk | $(BISECT_OBJ_DIR) # specify how to build the troublesome ones $(OBJ_DIR)/%_bisect_$(TROUBLE_ID).o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -c $< -o $@ \ + $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(TROUBLE_CFLAGS) $(DEPFLAGS) -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(TROUBLE_CXX)"' \ -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ @@ -294,7 +299,7 @@ $(BISECT_OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(BI if [ -f "$(OBJ_DIR)/$*_bisect_$(TROUBLE_ID)_fPIC.o" ]; then \ ln -s "../../$(OBJ_DIR)/$*_bisect_$(TROUBLE_ID)_fPIC.o" "$@"; \ else \ - $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(TROUBLE_CFLAGS) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(TROUBLE_CXX)"' \ -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ @@ -304,7 +309,7 @@ $(BISECT_OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(BI # and the fPIC variant $(OBJ_DIR)/%_bisect_$(TROUBLE_ID)_fPIC.o: %.cpp Makefile custom.mk | $(OBJ_DIR) - $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(DEPFLAGS) -fPIC -c $< -o $@ \ + $(TROUBLE_CXX) $(TROUBLE_OPTL) $(TROUBLE_SWITCHES) $(CC_REQUIRED) $(TROUBLE_CFLAGS) $(DEPFLAGS) -fPIC -c $< -o $@ \ -DFLIT_HOST='"$(HOSTNAME)"' \ -DFLIT_COMPILER='"$(TROUBLE_CXX)"' \ -DFLIT_OPTL='"$(TROUBLE_OPTL)"' \ From d1b9496d2e639ba017d51f065b1a91f2346e8509 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 9 Apr 2019 15:46:36 -0600 Subject: [PATCH 193/196] Increment version number to v2.0-beta.2 --- scripts/flitcli/config/version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/flitcli/config/version.txt b/scripts/flitcli/config/version.txt index 1c5979fc..8a80b658 100644 --- a/scripts/flitcli/config/version.txt +++ b/scripts/flitcli/config/version.txt @@ -1 +1 @@ -v2.0-beta.1 +v2.0-beta.2 From 80089957fd48cae069d93070e91f1d1543ef9d37 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 9 Apr 2019 17:20:07 -0600 Subject: [PATCH 194/196] Add release-notes.md in documentation --- README.md | 1 + documentation/README.md | 1 + documentation/installation.md | 4 + documentation/release-notes.md | 131 +++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) create mode 100644 documentation/release-notes.md diff --git a/README.md b/README.md index 76d23011..15ea7eba 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ It consists of the following components: Contents: +* [Release Notes](documentation/release-notes.md) * [Installation](documentation/installation.md) * [Litmus Tests](documentation/litmus-tests.md) * [FLiT Command-Line](documentation/flit-command-line.md) diff --git a/documentation/README.md b/documentation/README.md index 0daf08a5..ed668c6b 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,6 +2,7 @@ [Return to top-level README file](../README.md) +* [Release Notes](release-notes.md) * [Installation](installation.md) * [Litmus Tests](litmus-tests.md) * [FLiT Command-Line](flit-command-line.md) diff --git a/documentation/installation.md b/documentation/installation.md index 687d92a6..5f61b909 100644 --- a/documentation/installation.md +++ b/documentation/installation.md @@ -1,5 +1,7 @@ # FLiT Installation +[Prev](release-notes.md) +| [Table of Contents](README.md) | [Next](litmus-tests.md) @@ -186,6 +188,8 @@ then you would uninstall with make uninstall PREFIX=~/my-installs/ ``` +[Prev](release-notes.md) +| [Table of Contents](README.md) | [Next](litmus-tests.md) diff --git a/documentation/release-notes.md b/documentation/release-notes.md new file mode 100644 index 00000000..f073fab5 --- /dev/null +++ b/documentation/release-notes.md @@ -0,0 +1,131 @@ +# Release Notes + +[Table of Contents](README.md) +| +[Next](installation.md) + +Release note versions: + +- [v2.0-beta.2](#v2.0-beta.2) +- [v2.0-beta.1](#v2.0-beta.1) +- [v2.0-alpha.3](#v2.0-alpha.3) +- [v2.0-alpha.2](#v2.0-alpha.2) +- [v2.0-alpha.1](#v2.0-alpha.1) +- [v1.0.0](#v1.0.0) + +## v2.0-beta.2 + +Released on 10 April 2019 + +**Highlights of Major Changes** + +- TravisCI continuous integration fixed and working +- `flit bisect` + - outputs results incrementally. + - optimizations, such as memoizing and search space reduction + - order findings by the magnitude of variability + - add flags `--compile-only` and `--precompile-fpic` + - additional bisect assertion for finding disjoint sets + - add dependency of `pyelftools` +- Users specify the FLiT search space in `flit-config.toml` instead of being hard-coded +- `flit import`: add `--dbfile` flag to create an import database without a `flit-config.toml` file +- Remove `hosts` section from `flit-config.toml` +- Many bug fixes + +**All Issues Addressed:** + +- [#174](https://github.com/PRUNERS/FLiT/issues/174) (PR [#179](https://github.com/PRUNERS/FLiT/pull/179)): Have bisect output results incrementally +- [#175](https://github.com/PRUNERS/FLiT/issues/175) (PR [#181](https://github.com/PRUNERS/FLiT/pull/181)): Have function passed to `bisect_search` only take one argument +- [#182](https://github.com/PRUNERS/FLiT/issues/182) (PR [#185](https://github.com/PRUNERS/FLiT/pull/185), [#186](https://github.com/PRUNERS/FLiT/pull/186), [#187](https://github.com/PRUNERS/FLiT/pull/187)): Fix TravisCI continuous integration +- [#180](https://github.com/PRUNERS/FLiT/issues/180) (PR [#190](https://github.com/PRUNERS/FLiT/pull/190)): Memoize the bisect test function +- [#143](https://github.com/PRUNERS/FLiT/issues/143) (PR [#195](https://github.com/PRUNERS/FLiT/pull/195)): Fix NaN return values from litmus tests +- [#172](https://github.com/PRUNERS/FLiT/issues/172) (PR [#197](https://github.com/PRUNERS/FLiT/pull/197)): Order bisect findings by magnitude of variability +- [#200](https://github.com/PRUNERS/FLiT/issues/200) (PR [#201](https://github.com/PRUNERS/FLiT/pull/201)): Fix CSV file parsing +- [#120](https://github.com/PRUNERS/FLiT/issues/120) (PR [#206](https://github.com/PRUNERS/FLiT/pull/206)): Allow user-provided compilers in `flit-config.toml` +- (PR [#209](https://github.com/PRUNERS/FLiT/pull/209)): Add `--compile-only` and `--precompile-fpic` to `flit bisect` +- [#211](https://github.com/PRUNERS/FLiT/issues/211) (PR [#215](https://github.com/PRUNERS/FLiT/pull/215), [#223](https://github.com/PRUNERS/FLiT/pull/223)): Add `--dbfile` to `flit import` to import without a `flit-config.toml` file +- [#220](https://github.com/PRUNERS/FLiT/issues/220) (PR [#221](https://github.com/PRUNERS/FLiT/pull/221)): Have the test harness delete temporary directories even when exceptions are thrown +- [#217](https://github.com/PRUNERS/FLiT/issues/217) (PR [#219](https://github.com/PRUNERS/FLiT/pull/219)): Create a template for issues and pull requests (a GitHub-specific update) +- [#212](https://github.com/PRUNERS/FLiT/issues/212) (PR [#213](https://github.com/PRUNERS/FLiT/pull/213)): For bisect, if the Makefile errors out, print out the Makefile output for debugging +- [#225](https://github.com/PRUNERS/FLiT/issues/225) (PR [#226](https://github.com/PRUNERS/FLiT/pull/226)): For bisect, add assertion for finding disjoint sets (cannot continue if they overlap) +- [#230](https://github.com/PRUNERS/FLiT/issues/230) (PR [#232](https://github.com/PRUNERS/FLiT/pull/232)): Fix compilation if header files go missing +- [#229](https://github.com/PRUNERS/FLiT/issues/229) (PR [#231](https://github.com/PRUNERS/FLiT/pull/231)): Fix bisect deadlock where multiple updates to `ground-truth.csv` were attempted +- [#194](https://github.com/PRUNERS/FLiT/issues/194) (PR [#236](https://github.com/PRUNERS/FLiT/pull/236)): Fix the slow bisect search due to an explosion of templated function definitions +- [#238](https://github.com/PRUNERS/FLiT/issues/238) (PR [#241](https://github.com/PRUNERS/FLiT/pull/241)): Fix bisect search space problems. Specifically, only search over strong and publicly exported function symbols. This pull request added the dependency of `pyelftools`. +- [#233](https://github.com/PRUNERS/FLiT/issues/233) (PR [#243](https://github.com/PRUNERS/FLiT/pull/243)): Update the required version of `binutils` in the documentation +- [#239](https://github.com/PRUNERS/FLiT/issues/239) (PR [#242](https://github.com/PRUNERS/FLiT/pull/242)): Fix support for older versions of the Clang compiler (version 4) +- [#244](https://github.com/PRUNERS/FLiT/issues/244) (PR [#246](https://github.com/PRUNERS/FLiT/pull/246)); Remove the `hosts` section from `flit-config.toml`. It was not used. +- [#249](https://github.com/PRUNERS/FLiT/issues/249) (PR [#250](https://github.com/PRUNERS/FLiT/pull/250)): Update documentation about how FLiT handles MPI tests. Specifically how the test return values are handled. +- [#119](https://github.com/PRUNERS/FLiT/issues/119) (PR [#351](https://github.com/PRUNERS/FLiT/pull/351)): Allow the user to specify the list of optimization levels and flags in `flit-config.toml` for the FLiT search space. No longer hard-coded. +- [#256](https://github.com/PRUNERS/FLiT/issues/256) (PR [#258](https://github.com/PRUNERS/FLiT/pull/258)): Fix bisect crash when an object file has an empty dwarf info +- [#257](https://github.com/PRUNERS/FLiT/issues/257) (PR [#259](https://github.com/PRUNERS/FLiT/pull/259)): Fix bisect crash when an object file has no dwarf info section + + +## v2.0-beta.1 + +Since FLiT has been stable in the alpha phase for some time and some other things have stabilized more (such as documentation and interface), we are happy to announce the move to beta status. + +In this release, we have included the following pull requests: + +[#115](https://github.com/PRUNERS/FLiT/pull/115), [#116](https://github.com/PRUNERS/FLiT/pull/116), [#128](https://github.com/PRUNERS/FLiT/pull/128), [#130](https://github.com/PRUNERS/FLiT/pull/130), [#131](https://github.com/PRUNERS/FLiT/pull/131), [#132](https://github.com/PRUNERS/FLiT/pull/132), [#135](https://github.com/PRUNERS/FLiT/pull/135), [#139](https://github.com/PRUNERS/FLiT/pull/139), [#142](https://github.com/PRUNERS/FLiT/pull/142), [#145](https://github.com/PRUNERS/FLiT/pull/145), [#147](https://github.com/PRUNERS/FLiT/pull/147), [#150](https://github.com/PRUNERS/FLiT/pull/150), [#154](https://github.com/PRUNERS/FLiT/pull/154), [#155](https://github.com/PRUNERS/FLiT/pull/155), [#156](https://github.com/PRUNERS/FLiT/pull/156), [#157](https://github.com/PRUNERS/FLiT/pull/157), [#158](https://github.com/PRUNERS/FLiT/pull/158), [#159](https://github.com/PRUNERS/FLiT/pull/159), [#160](https://github.com/PRUNERS/FLiT/pull/160), [#161](https://github.com/PRUNERS/FLiT/pull/161), [#167](https://github.com/PRUNERS/FLiT/pull/167), [#170](https://github.com/PRUNERS/FLiT/pull/170), [#176](https://github.com/PRUNERS/FLiT/pull/176) + +This includes the following features: + +- Bisect + - Fully implemented and supported - assigns variability blame to individual source files and functions + - Works with Intel linker problems + - Autodelete intermediate generated files to reduce disk usage from going out of control + - Autorun all differences found in a given database file + - Unfortunately, this functionality is not adequately documented (see issue [#136](https://github.com/PRUNERS/FLiT/pull/136)) +- Add MPI support within `flit-config.toml` +- Add timing parameters to `flit-config.toml` +- Add `--info` flag to test executable to show how it was compiled +- Rename results and database columns to be more understandable +- Add `plot_timing_histogram.py` for auto-generating histogram plots and update `plot_timing.py` +- Add benchmarks: polybench and random - benchmark examples of FLiT usage +- Add `uninstall` target to the top-level `Makefile` +- Remove CUDA completely, it was broken and cumbering the space +- Remove old unused files. The repository is more lean with all files relevant +- License notices on files +- Fix support for GCC 4.8 (had a compiler error in FLiT) + + +## v2.0-alpha.3 + +There was reported a bug in the installation making `flit import` not work. This has been fixed and a new alpha release is ready. + + +## v2.0-alpha.2 + +Many fixes in this update: + +- Remove `TestInput` and `CUTestInput` types, replace with arrays and `std::vector` +- Disable unfinished flit command-line commands +- Remove sections of the `flit-config.toml` settings file that are unused +- Fix incremental build +- Add `--version` argument to `flit` +- Recursive generated `Makefile` allows for more scalability with project size and number of tests +- Add some tests for FLiT's infrastructure - not comprehensive, but some automated tests +- Fix timing functionality +- Add a time plot + + +## v2.0-alpha.1 + +Not everything for this new release is finished. The tool has been rearchitected to be easier to use within existing code bases. Many things have changed. Here are a few of them: + +- A command-line tool called `flit` with subcommands +- Storage is into an SQLite database rather than Postgres (for simplicity and ease of installation) +- A configuration file, `flit-config.toml`, where you can specify your ground-truth compilation and your developer compilation. Some of the values in this configuration file are not yet implemented to be used. +- An included `custom.mk` makefile to help you specify how to build your source files with the tests +- Turn FLiT into a shared library to be linked + + +## v.1.0.0 + +This release provides litmus tests, a reproducibility test framework, and analysis tools for the results of the tests. + + +[Table of Contents](README.md) +| +[Next](installation.md) From d1e6d94cdd6c0cf78dde30cd7100e252ea6af3b0 Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 9 Apr 2019 17:30:05 -0600 Subject: [PATCH 195/196] release-notes.md: add release dates to versions --- documentation/release-notes.md | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/documentation/release-notes.md b/documentation/release-notes.md index f073fab5..0a0f39af 100644 --- a/documentation/release-notes.md +++ b/documentation/release-notes.md @@ -6,16 +6,16 @@ Release note versions: -- [v2.0-beta.2](#v2.0-beta.2) -- [v2.0-beta.1](#v2.0-beta.1) -- [v2.0-alpha.3](#v2.0-alpha.3) -- [v2.0-alpha.2](#v2.0-alpha.2) -- [v2.0-alpha.1](#v2.0-alpha.1) -- [v1.0.0](#v1.0.0) +- [v2.0-beta.2](#v2.0-beta.2) _(10 April 2019)_ +- [v2.0-beta.1](#v2.0-beta.1) _(18 July 2018)_ +- [v2.0-alpha.3](#v2.0-alpha.3) _(29 January 2018)_ +- [v2.0-alpha.2](#v2.0-alpha.2) _(27 January 2018)_ +- [v2.0-alpha.1](#v2.0-alpha.1) _(25 September 2017)_ +- [v1.0.0](#v1.0.0) _(25 March 2017)_ ## v2.0-beta.2 -Released on 10 April 2019 +_Released on 10 April 2019_ **Highlights of Major Changes** @@ -63,6 +63,8 @@ Released on 10 April 2019 ## v2.0-beta.1 +_Released on 18 July 2018_ + Since FLiT has been stable in the alpha phase for some time and some other things have stabilized more (such as documentation and interface), we are happy to announce the move to beta status. In this release, we have included the following pull requests: @@ -92,11 +94,15 @@ This includes the following features: ## v2.0-alpha.3 +_Released on 29 January 2018_ + There was reported a bug in the installation making `flit import` not work. This has been fixed and a new alpha release is ready. ## v2.0-alpha.2 +_Released on 27 January 2018_ + Many fixes in this update: - Remove `TestInput` and `CUTestInput` types, replace with arrays and `std::vector` @@ -112,6 +118,8 @@ Many fixes in this update: ## v2.0-alpha.1 +_Released on 25 September 2017_ + Not everything for this new release is finished. The tool has been rearchitected to be easier to use within existing code bases. Many things have changed. Here are a few of them: - A command-line tool called `flit` with subcommands @@ -123,6 +131,8 @@ Not everything for this new release is finished. The tool has been rearchitected ## v.1.0.0 +_Released on 25 March 2017_ + This release provides litmus tests, a reproducibility test framework, and analysis tools for the results of the tests. From 276cedbfbeebcc884af4b3329799f8203b64c30d Mon Sep 17 00:00:00 2001 From: Michael Bentley Date: Tue, 9 Apr 2019 17:37:50 -0600 Subject: [PATCH 196/196] release-notes.md: fix broken pull request link --- documentation/release-notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/release-notes.md b/documentation/release-notes.md index 0a0f39af..df32b20b 100644 --- a/documentation/release-notes.md +++ b/documentation/release-notes.md @@ -56,7 +56,7 @@ _Released on 10 April 2019_ - [#239](https://github.com/PRUNERS/FLiT/issues/239) (PR [#242](https://github.com/PRUNERS/FLiT/pull/242)): Fix support for older versions of the Clang compiler (version 4) - [#244](https://github.com/PRUNERS/FLiT/issues/244) (PR [#246](https://github.com/PRUNERS/FLiT/pull/246)); Remove the `hosts` section from `flit-config.toml`. It was not used. - [#249](https://github.com/PRUNERS/FLiT/issues/249) (PR [#250](https://github.com/PRUNERS/FLiT/pull/250)): Update documentation about how FLiT handles MPI tests. Specifically how the test return values are handled. -- [#119](https://github.com/PRUNERS/FLiT/issues/119) (PR [#351](https://github.com/PRUNERS/FLiT/pull/351)): Allow the user to specify the list of optimization levels and flags in `flit-config.toml` for the FLiT search space. No longer hard-coded. +- [#119](https://github.com/PRUNERS/FLiT/issues/119) (PR [#251](https://github.com/PRUNERS/FLiT/pull/251)): Allow the user to specify the list of optimization levels and flags in `flit-config.toml` for the FLiT search space. No longer hard-coded. - [#256](https://github.com/PRUNERS/FLiT/issues/256) (PR [#258](https://github.com/PRUNERS/FLiT/pull/258)): Fix bisect crash when an object file has an empty dwarf info - [#257](https://github.com/PRUNERS/FLiT/issues/257) (PR [#259](https://github.com/PRUNERS/FLiT/pull/259)): Fix bisect crash when an object file has no dwarf info section