Ejemplo n.º 1
0
def run_trial(trial, tests_per_trial, exe_dir, out_dir, max_rsd,
              keep_best_test_only, convert_traces, skeleton_only):
    import online_math

    test_output_re = re.compile(test_output_pattern, flags=re.DOTALL)

    # abbrevs
    exe = trial.exe
    N = trial.N
    cores = trial.cores
    NB = trial.NB
    IB = trial.IB
    sched = trial.sched

    if NB < 100:
        max_rsd += 1
    if NB < 80:
        max_rsd += 2
    if NB < 60:
        max_rsd += 4

    # counters and loop variables
    test_num = 0
    stddev_fails = 0
    trial_finished = False
    extra_tests = []

    while not trial_finished:
        test_attempts = 0
        while test_num < tests_per_trial + stddev_fails:
            if test_attempts > max_test_failures:
                test_num += 1
                test_attempts = 0
                print('Failed this test too many times. Moving on...')
                continue
            print(
                "%s for %dx%d matrix on %d cores, NB = %d, IB = %d; sched = %s Xargs = %s trial #%d"
                % (exe, N, N, cores, NB, IB, sched, str(
                    trial.extra_args), test_num))
            cmd, args = trial.generate_cmd()
            proc = subprocess.Popen([exe_dir + os.sep + cmd] + args,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
            # RUN
            (stdout, stderr) = proc.communicate()
            # if len(stderr) != 0:
            #     marker = randint(0, 99999)
            #     print("AN ERROR OCCURRED (random id: %d)" % marker)
            #     sys.stderr.write(str(marker) + ':\n' + stderr + '\n')
            match = test_output_re.match(stdout)
            trace_filenames = glob.glob('testing_' + exe + '*.prof-*')
            if match:
                # save successfully-parsed output
                time = float(match.group(1))
                perf = float(match.group(2))
                extra_output = match.group(3)
                print("   -----> gflops: %f time: %f NB:%d" % (perf, time, NB))
                test = ParsecTest(trial.ident, exe, N, cores, NB, IB, sched,
                                  perf, time, test_num)
                test.extra_output = extra_output
                if not os.environ.get('SUPPRESS_EXTRA_OUTPUT', None):
                    sys.stdout.write(extra_output)
                # rename trace, if it exists
                if len(trace_filenames) > 0:
                    moved_trace_filenames = list()
                    for filename in trace_filenames:
                        trace_filename = filename.replace(
                            'testing_' + exe,
                            out_dir + os.sep + test.unique_name())
                        # print('moving {} to {}'.format(filename, trace_filename))
                        print('moving', filename, 'to', trace_filename)
                        shutil.move(filename, trace_filename)
                        moved_trace_filenames.append(trace_filename)
                    trace_filenames = moved_trace_filenames
                trial.append((test, trace_filenames))
                test_num += 1  # no more attempts are needed - we got what we came for
            else:
                safe_unlink(trace_filenames)
                sys.stderr.write("results not properly parsed: %s\n" % stdout)
                print('\nWe\'ll just try this one again.\n')
        if tests_per_trial > 1:
            print('finished all {} tests of this trial'.format(len(trial)))
        # done with trial. now calculate trial statistics
        test_perfs = []
        test_times = []
        for test, trace_filenames in trial:
            test_times.append(test.time)
            test_perfs.append(test.perf)
        variance, avgPerf = online_math.online_variance_mean(test_perfs)
        perf_stddev = variance**0.5
        rsd = trial.percent_sdv(perf_stddev, avgPerf)
        # now check whether our results are clean/good
        if rsd <= max_rsd or keep_best_test_only:  # clean - save and print!
            trial.perf_sdv = perf_stddev
            trial.perf_avg = avgPerf
            variance, trial.time_avg = online_math.online_variance_mean(
                test_times)
            trial.time_sdv = variance**0.5
            print(trial)  # realtime progress report

            for test, trace_filenames in extra_tests:
                safe_unlink(trace_filenames)  # these won't be needed anymore

            if keep_best_test_only:
                best_perf = 0
                best_index = 0
                for index, (test, trace_filenames) in enumerate(trial):
                    if test.perf > best_perf:
                        best_perf = test.perf
                        best_index = index
                print(
                    'Only keeping the trace of the test with the best performance'
                    + ' ({} gflops/s), at index {}.'.format(
                        best_perf, best_index))

                new_list = list()
                for index, (test, trace_filenames) in enumerate(trial):
                    if index != best_index:
                        safe_unlink(trace_filenames
                                    )  # remove traces of 'not best' runs
                        new_list.append((test, list()))
                    else:
                        new_list.append((test, trace_filenames))
                del trial[:]
                trial.extend(new_list)

            if convert_traces:
                # iterate through the list, convert the traces, and save the new names
                new_list = list()
                while len(trial) > 0:
                    test, trace_filenames = trial.pop()
                    print('converting', trace_filenames)
                    if len(trace_filenames) > 0:
                        try:
                            import pbt2ptt
                            add_info = add_info_to_trace(trial)
                            trace_filenames = [
                                pbt2ptt.convert(trace_filenames,
                                                unlink=True,
                                                add_info=add_info,
                                                skeleton_only=skeleton_only)
                            ]
                            print('converted filename is', trace_filenames[0])
                            if skeleton_only:
                                try:
                                    os.system(
                                        'ptrepack --chunkshape=auto --propindexes '
                                        + '--complevel=5 --complib=blosc ' +
                                        '{} {}'.format(
                                            trace_filenames[0],
                                            trace_filenames[0] + '.tmp'))
                                    shutil.move(trace_filenames[0] + '.tmp',
                                                trace_filenames[0])
                                except Exception as e:
                                    print(e)
                                    print('ptrepack utility not available.')
                            new_list.append((test, trace_filenames))
                        except ImportError as ie:
                            print(ie)
                            print(
                                'Cannot convert. pbt2ptt module is unavailable.'
                            )
                            new_list.append((test, trace_filenames))
                            pass  # can't convert without the module... ahh well
                    else:
                        new_list.append((test, trace_filenames))
                trial.extend(new_list)  # put everything back in the trial

            while not trial_finished:  # safe against Keyboard Interrupt
                try:
                    pfilename = out_dir + os.sep + trial.unique_name(
                    ) + '.trial'
                    pfile = open(pfilename, 'w')
                    trial.pickle(pfile)
                    # move 'pending' to 'rerun' in case a later re-run of the entire group is necessary
                    if 'pending.' in trial.filename:
                        rerun = trial.filename.replace('pending.', 'rerun.')
                        if os.path.exists(trial.filename):
                            shutil.move(trial.filename, rerun)
                    trial_finished = True
                    # safe_unlink([out_dir + os.sep +
                    #              test.unique_name() + '.test'
                    #              for test in trial],
                    #             report_error=False)
                except KeyboardInterrupt:
                    print('Currently writing files. Cannot interrupt.')

        elif stddev_fails < max_stddev_fails:  # no good, try again from beginning
            stddev_fails += 1
            test_num = 0
            extra_tests.extend(trial[:])
            del trial[:]  # retry with a clean trial, in case there was interference
            print('WARNING: this trial has a large relative ' +
                  'standard deviation ({}%), and will be redone.'.format(rsd))
        else:  # no good.... but we've tried too many times :(
            # (so let's just use all of our many results, and label the trial with a warning)
            trial.extend(extra_tests)
            test_perfs = []
            test_times = []
            for test, trace_filenames in trial:
                test_times.append(test.time)
                test_perfs.append(test.perf)
            variance, avgPerf = online_math.online_variance_mean(test_perfs)
            perf_stddev = variance**0.5
            trial.perf_sdv = perf_stddev
            trial.perf_avg = avgPerf
            variance, trial.time_avg = online_math.online_variance_mean(
                test_times)
            trial.time_sdv = variance**0.5
            wfile = open(out_dir + os.sep + trial.unique_name() + '.warn', 'w')
            trial.pickle(wfile)
            # leave the pending pickle so it can be easily identified
            # as never having completed later on
            trial_finished = True
    # be done.
    return trial
Ejemplo n.º 2
0
import ptt_utils
import pbt2ptt
import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Convert a set of PaRSEC Binary Profile files into an HDF5 file")
    parser.add_argument('--output', dest='output', help='Output file name')
    parser.add_argument('--report-progress', dest='report_progress', action='store_const',
                        const=True, default=False,
                        help='Report progress of conversion to stderr')
    parser.add_argument('--single-process', dest='multiprocess', action='store_const',
                        const=False, default=True,
                        help='Deactivate multiprocess parallelism')
    parser.add_argument('inputs', metavar='INPUT', type=str, nargs='+',
                        help='PaRSEC Binary Profile Input files')
    args = parser.parse_args()

    if args.output is None:
        groups = ptt_utils.group_trace_filenames(args.inputs)
        for f in groups:
            print("Processing {}".format(f))
            name = pbt2ptt.convert(f, multiprocess=args.multiprocess, report_progress=args.report_progress)
            print("Generated: {}".format(name))
    else:
        f = args.inputs
        print("Processing {}".format(f))
        name = pbt2ptt.convert(f, multiprocess=args.multiprocess, report_progress=args.report_progress,
                               out=args.output)
        print("Generated {}".format(name))
    sys.exit(0)
Ejemplo n.º 3
0
def scatter_papi(filenames, units, unit_modify):
    with Timer() as main:
        # The import of matplotlib is timed because it takes a surprisingly long time.
        with Timer() as t:
            import matplotlib
            matplotlib.use('Agg') # For use with headless systems
            import matplotlib.pyplot as plt
            import matplotlib.cm as cm
        print('Importing matplotlib took {} seconds.\n'.format(t.interval))

        trace = None
        # This is for loading and possibly converting trace files.
        with Timer() as t:
            if len(filenames) == 1 and (ptt.is_ptt(filenames[0])):
                print('Loading the HDFed trace...')
            else:
                print('Converting binary trace to the ParSEC Trace Tables format...')
                filenames[0] = pbt2ptt.convert(filenames, report_progress=True)
                print('Loading the HDFed trace...')
            trace = ptt.from_hdf(filenames[0])

        print('The load took {} seconds.'.format(t.interval))
        print('')

        # The column_data list will store subsets of the pandas dataframes for the
        # columns containing PAPI counter information.  The column_names list stores
        # the names corresponding to those columns.
        column_data = []
        column_names = []
        print('Populating user-defined lists...')
        with Timer() as t:
            # We start from the beginning, which is where the PAPI event columns will be.
            for i in range(0,len(trace.events.columns.values)):
                column_name = trace.events.columns.values[i]
                # If we hit the 'begin' column, there aren't any more PAPI event columns.
                if column_name == 'begin':
                    break
                if '_start' in column_name:
                    continue
                column_names.append(column_name)
                # We only care about the data in this column for which there is data.
                # Note: column_data actually stores all of the rows for which the column
                #       of interest is not NULL.
                column_data.append(trace.events[:][trace.events[column_name].notnull()])
        print('Populating the lists took {} seconds.\n'.format(t.interval))

        # Find the maximum y value
        max_count = 0
        max_counts = []
        for i in range(0, len(column_data)):
            temp = column_data[i][:][column_names[i]].values.tolist()
            max_counts.append(0)
            for val in temp:
                if(val > max_count):
                    max_count = val
                if(val > max_counts[i]):
                    max_counts[i] = val

        # Determine the maximum number of colors that we would need for one of the graphs.
        colors_needed = 0
        for event_name in trace.event_names:
            if event_name.startswith('PINS_PAPI'):
                colors_needed += 1
        print('Colors Needed: ' + str(colors_needed))

        # Start the plot of the figure with a relatively large size.
        fig = plt.figure(num=None, figsize=(12, 9), dpi=80, facecolor='w', edgecolor='k')
        # Start the color iterator so we can plot each column in its own color.
        colors = iter(cm.prism(np.linspace(0, 1, colors_needed)))
        print('Plotting all PAPI counters together...')
        with Timer() as t:
            for i in range(0, len(column_data)):
                # This is done in 4 lines instead of two due to an issue with multiplying unit_modify
                temp = column_data[i]['begin'] * unit_modify
                tempX = temp.values.tolist()
                temp = column_data[i]['end'] * unit_modify
                # We should now have all of the 'x' values (time)
                tempX.extend(temp.values.tolist())

                tempY = column_data[i][:][column_names[i] + '_start'].values.tolist()
                #end_index = len(tempY)
                # We should now have all of the 'y' values (count)
                tempY.extend(column_data[i][:][column_names[i]].values.tolist())

                adjust_factor = 1000
                adjust_power = 3
                while max_count > adjust_factor:
                    adjust_factor *= 1000
                    adjust_power += 3
                adjust_factor /= 1000
                adjust_power -= 3

                if(adjust_factor > 1):
                    for v in range(0, len(tempY)):
                        tempY[v] /= adjust_factor

                #localize(tempY)

                # Note: The values in tempX and tempY are stored with the first half of the array being
                #       the '_start' values and the second half being the 'end' values, so they match up
                #       properly, however a line plot would look very odd because these values should
                #       actually be interleaved.
                plt.scatter(tempX, tempY, color = next(colors), label = column_names[i])

                #if(tempY[-1] > max_count):
                #    max_count = tempY[-1]

                plt.title('All PAPI Counters')
                plt.ylim(ymin = 0, ymax = (max_count / adjust_factor) * 1.1)
                plt.xlim(xmin = 0)

                if(adjust_power > 0):
                    plt.ylabel('Count (Times 10^' + str(adjust_power) + ')')
                else:
                    plt.ylabel('Count')

                if units != 'c':
                    plt.xlabel('Time (' + units + ')')
                else:
                    plt.xlabel('Cycles')

                plt.legend(loc='upper left')
                plt.show()

        print('Saving plot as all_papi_counters.png...')
        fig.savefig('all_papi_counters.png')
        print('Plotting and saving took {} seconds.'.format(t.interval))

        # Each iteration will plot a different individual counter as its own plot.
        for i in range(0, len(column_data)):
            with Timer() as t:
                print('Plotting data for: ' + column_names[i] + '...')
                fig = plt.figure(num=None, figsize=(12, 9), dpi=80, facecolor='w', edgecolor='k')
                # Restart the colors iterator
                colors = iter(cm.prism(np.linspace(0, 1, colors_needed)))

                # Plot each non-empty subset of this counter by 'type'.  This typically means
                # the counters that occurred on each core are grouped together.
                for n in range(0, len(trace.event_names)-1):
                    if trace.event_names[n].startswith('PINS_PAPI'):
                        temp = column_data[i][:][column_data[i]['type'] == n]['begin'] * unit_modify

                        if len(temp) > 0:
                            tempX = temp.values.tolist()
                            temp = column_data[i][:][column_data[i]['type'] == n]['end'] * unit_modify
                            tempX.extend(temp.values.tolist())

                            tempY = column_data[i][:][column_data[i]['type'] == n][column_names[i] + '_start'].values.tolist()
                            tempY.extend(column_data[i][:][column_data[i]['type'] == n][column_names[i]].values.tolist())

                            adjust_factor = 1000
                            adjust_power = 3
                            while max_counts[i] > adjust_factor:
                                adjust_factor *= 1000
                                adjust_power += 3
                            adjust_factor /= 1000
                            adjust_power -= 3

                            if(adjust_factor > 1):
                                for v in range(0, len(tempY)):
                                    tempY[v] /= adjust_factor

                            #localize(tempY)

                            temp_color = next(colors)
                            plt.scatter(tempX, tempY, color = temp_color,\
                                        label = trace.event_names[n].replace('PINS_PAPI_', ''))

                            # The following will do line plots
                            #plt.scatter(tempX, tempY, color = temp_color)
                            #plt.plot(tempX, tempY, color = temp_color,\
                            #         linestyle = '-', label = trace.event_names[n].replace('PINS_PAPI_', ''))

                plt.title(column_names[i])
                plt.ylim(ymin = 0, ymax = (max_counts[i] / adjust_factor) * 1.1)
                plt.xlim(xmin = 0)

                if(adjust_power > 0):
                    plt.ylabel('Count (Times 10^' + str(adjust_power) + ')')
                else:
                    plt.ylabel('Count')
                if units != 'c':
                    plt.xlabel('Time (' + units + ')')
                else:
                    plt.xlabel('Cycles')

                plt.legend(loc='upper left')

                plt.show()
                fig.savefig(column_names[i] + '.png')
                print('Saving plot as ' + column_names[i] + '.png...')
            print('Plotting and saving took {} seconds.'.format(t.interval))

    print('Total Time: {} seconds\n'.format(main.interval))
Ejemplo n.º 4
0
#!/usr/bin/env python
from __future__ import print_function
import sys
import ptt_utils
import pbt2ptt

if __name__ == '__main__':
    if len(sys.argv[1:]) == 0:
        print("Usage: %s profile-file1 profile-file2 ..." % (sys.argv[0]),
              file=sys.stderr)
        sys.exit(1)

    groups = ptt_utils.group_trace_filenames(sys.argv[1:])
    for f in groups:
        print("Processing %s" % f)
        name = pbt2ptt.convert(f)
        print("Generated: %s" % (name))
    sys.exit(0)
Ejemplo n.º 5
0
def do_demo(filenames, translate=False):
    with Timer() as main:
        trace = None

        with Timer() as t:
            if len(filenames) == 1 and (ptt.is_ptt(filenames[0])):
                print('First, we load the HDFed trace...')
            else:
                print(
                    'First, we read the binary trace and convert it to the ParSEC Trace Tables format.'
                )
                filenames[0] = pbt2ptt.convert(filenames, report_progress=True)
                print('Then, we read the HDFed trace...')
            trace = ptt.from_hdf(filenames[0])

        print('The load took {} seconds.'.format(t.interval))
        print('')
        print('First, let\'s print some basic information about the run.\n')

        print('Most PaRSEC traces are traces of testing executables, and')
        print(
            'these runs tend to have some basic linear algebra attributes, such as matrix size.'
        )
        print(
            'If the trace contains these sorts of attributes, they will print below:\n'
        )
        try:
            print(
                'N: {} M: {} NB: {} MB: {} gflops: {} time elapsed: {} scheduler: {}\n'
                .format(trace.N, trace.M, trace.NB, trace.MB, trace.gflops,
                        trace.time_elapsed, trace.sched))
        except AttributeError as e:
            print(e)
            print(
                'It appears that one or more of the basic attributes was not present,'
            )
            print('so we\'ll just move on.\n')

        print(
            'The bulk of the trace information is stored in a data structure called a DataFrame.'
        )
        print('A DataFrame is a large matrix/table with labeled columns.\n')
        print('One of our trace\'s DataFrames contains all of the "events".')
        print('Each event in our trace is one row in the events DataFrame,')
        print(
            'and some events have different pieces of information than others.\n'
        )

        print(
            'The columns of the DataFrame (or data labels) and their datatypes are:'
        )
        print(trace.events.dtypes)

        print('')
        print(
            'Now, we can print some statistics about the *shared* columns of the events.'
        )
        print('###################################################\n')
        # Note trace.events.loc[:,'begin':] returns the information from columns 'begin' to the last column
        with Timer() as t:
            print(trace.events.loc[:, 'begin':])
        print('There are ' + str(len(trace.events)) + ' events in this trace',
              end=' ')
        print('and they took {} seconds to describe.'.format(t.interval))
        print('###################################################\n\n')
        print('')

        print('')
        user_columns = []
        for column_name in trace.events.columns.values:
            if column_name not in trace.events.loc[:, 'begin':]:
                user_columns.append(column_name)
        print('Here are some statistics on the unique, non-shared columns:')
        print('###################################################\n')
        with Timer() as t:
            print(trace.events[user_columns].describe())
        print('There are ' + str(len(trace.events)) + ' events in this trace',
              end=' ')
        print('and they took {} seconds to describe.'.format(t.interval))
        print('###################################################\n\n')
        print('')

        # Set this to a number to specify the compression level (e.x. 1)
        clevel = None
        if clevel:
            print('Compression Test:')
            print('###################################################\n')

            print('Testing re-store of events as a compressed HDF5')
            with Timer() as t:
                trace.events.to_hdf('test_compressed_events.hdf5',
                                    'events',
                                    complevel=clevel,
                                    complib='blosc')
            print(
                'took {} to write only the events to HDF5, compression level {}\n'
                .format(t.interval, clevel))
            print('')

            print('Testing re-store as a Table HDF5')
            with Timer() as t:
                trace.to_hdf('test_table.hdf5', table=True, append=False)
            print('took {} to write the HDF5 table\n'.format(t.interval))
            print('')

            print('Testing re-store as Storer HDF5')
            with Timer() as t:
                trace.to_hdf('test_storer.hdf5', table=False, append=False)
            print('took {} to write the HDF5 storer\n'.format(t.interval))
            print('')

            print('Testing re-store as HDF5_Store')
            with Timer() as t:
                new_store = pandas.HDFStore('test_events.hdf5_store',
                                            'w',
                                            complevel=clevel,
                                            complib='blosc')
                new_store.put('events', trace.events, table=False)
            print(
                'took {} to PUT only the events to HDF5, compression level {}\n'
                .format(t.interval, clevel))
            print('')

            print('Testing read from compressed HDF5')
            with Timer() as t:
                trace.events = pandas.read_hdf('test_compressed_events.hdf5',
                                               'events')
                print(trace.events[trace.events.loc[:, 'begin':]].describe())
            print(
                'There are ' + str(len(trace.events)) +
                ' events in this trace',
                'and they took {} seconds to read & describe.'.format(
                    t.interval))
            print('')

            print('Testing read from Table HDF5')
            with Timer() as t:
                trace = ptt.from_hdf('test_table.hdf5')
            print(
                'There are ' + str(len(trace.events)) +
                ' events in this trace',
                'and they took {} seconds to read'.format(t.interval))
            print('')

            print('Testing write to CSV (with compression)...')
            with Timer() as t:
                trace.events.to_csv('test.csv',
                                    complevel=clevel,
                                    complib='blosc')
            print('took {} to write to csv, clevel {}'.format(
                t.interval, clevel))
            print('###################################################\n\n')

        print(
            'Now, we will select only the PINS_PAPI* events via a simple operation (only the first will be printed).'
        )
        print('###################################################\n')
        for event_name in trace.event_types.keys():
            if event_name.startswith('PINS_PAPI'):
                print('\nFound: ' + event_name)
                print('---------------------------------------------------\n')
                onlyexec = trace.events[:][trace.events['type'] ==
                                           trace.event_types[event_name]]
                print(onlyexec.describe())
                break  # Removing this break will print all of the PINS_PAPI* events' descriptions
        print('###################################################\n\n')
        onlyexec = trace.events[:][trace.events['type'] ==
                                   trace.event_types[event_name]]

        print('')
        print('Now, we will select only the {} events from thread 0.'.format(
            event_name))
        print(
            'We will also pick only certain pieces of the statistics to show, using the same'
        )
        print(
            'syntax that is used to pick rows out of any regular DataFrame.\n')
        onlyexec = onlyexec[:][onlyexec.stream_id == 0]

        if len(onlyexec) == 0:
            print(
                'Unfortunately the {} event doesn\'t have any events for thread 0,'
                .format(event_name))
            print('so the following outputs will be rather dull...\n')

        print('Again, our view of the dataframe has changed:')
        print('###################################################\n')
        print(onlyexec.describe()[:]['count':'std'])
        print('###################################################\n\n')
        print('')
        print(
            'It is also possible to perform both operations in one query, like so:'
        )
        onlyexec = trace.events[:][
            (trace.events['type'] == trace.event_types[event_name])
            & (trace.events.stream_id == 0)]
        print(
            'Note that the description is the same as for the previous subset.'
        )
        print('###################################################\n')
        print(onlyexec.describe()[:]['count':'std'])
        print('###################################################\n\n')
        print('')

        print(
            'Now, a simple sort of {} events from thread 0 by duration, in ascending order.'
            .format(event_name))
        with Timer() as t:
            onlyexec['duration'] = pandas.Series(onlyexec['end'] -
                                                 onlyexec['begin'])
            srted = onlyexec.sort_index(by=['duration'], ascending=[True])
        print('That sort only took ' + str(t.interval) + ' seconds.')
        print('Here is the sorted list:')
        print('###################################################\n')
        print(srted)
        print('###################################################\n\n')

    print('Overall demo took {:.2f} seconds'.format(main.interval))
Ejemplo n.º 6
0
def autoload_traces(filenames,
                    convert=True,
                    unlink=False,
                    enhance_filenames=False,
                    skeleton_only=False,
                    report_progress=True,
                    force_reconvert=False,
                    multiprocess=True):
    """ Preferred interface for most attempts to load PTTs from the filesystem.

    Whether from PTT, PBT, or a combination of the two, you should be able to
    throw a huge, messy list of filenames at this function and receive a bunch of
    coherent PTT traces back. Give it a whirl, and be sure to report any bugs!
    """

    pbt_groups = group_trace_filenames(filenames)
    ptts = list()

    # convert or separate into PTTs and PBTs
    if convert:  # then turn everything into a PTT
        for fn_group in pbt_groups[:]:
            if len(fn_group) == 1 and ptt.is_ptt(fn_group[0]):
                ptts.append(fn_group[0])
                pbt_groups.remove(fn_group)
            else:
                import pbt2ptt
                # do convert on all -- already-converted filenames will simply be returned
                converted_filename = pbt2ptt.convert(
                    fn_group,
                    unlink=unlink,
                    report_progress=report_progress,
                    force_reconvert=force_reconvert,
                    multiprocess=multiprocess)
                ptts.append(converted_filename)
                pbt_groups.remove(fn_group)
    else:  # separate into already-PTTs and PBTs
        for fn_group in pbt_groups[:]:
            ptt_name = ptt.ptt_name(fn_group[0])
            h5_conflicts = find_h5_conflicts(fn_group)
            if ptt.is_ptt(fn_group[0]):
                ptts.append(fn_group)
                pbt_groups.remove(fn_group)
            elif os.path.exists(
                    ptt_name
            ):  # passed a PBT name, but previous conversion exists
                ptts.append([ptt_name])
                pbt_groups.remove(fn_group)
            elif len(h5_conflicts) > 0:
                ptts.append([h5_conflicts[0]])
                pbt_groups.remove(fn_group)

    # LOAD PTTs
    if len(ptts) > 0:
        # prepare to multithread the loads
        if multiprocess:
            pool = multiprocessing.Pool(multiprocessing.cpu_count())
        else:
            pool = multiprocessing.Pool(1)

        if report_progress:
            print('loading PTTs...')
        partial_from_hdf = functools.partial(ptt.from_hdf,
                                             skeleton_only=skeleton_only)

        # do load
        traces = pool.map(partial_from_hdf, ptts)

        if report_progress:
            print('loaded all PTTs.')
    else:
        traces = list()

    # LOAD PBTs
    for group in pbt_groups:
        import pbt2ptt  # don't do this if not necessary

        if report_progress:
            print('loading PBT group {}'.format(group))
        trace = pbt2ptt.read(group,
                             skeleton_only=skeleton_only,
                             multiprocess=multiprocess,
                             report_progress=report_progress)
        traces.append(trace)

    return traces
Ejemplo n.º 7
0
        convert = False
        args.remove('--no-convert')
    if '--unlink' in args:
        unlink = True
        args.remove('--unlink')

    if len(args) > 0:
        name_infos = args
    else:
        name_infos = default_name_infos

    processed_filename_groups = group_trace_filenames(filenames)

    # this is commented out because I decided not to enhance the filenames of the
    # binary trace files by default anymore. It tended to confuse matters,
    # and it inadvertently encourages continued use of those binary traces.
    # processed_filename_groups = preprocess_traces(filenames, dry_run=dry_run,
    # enhance_filenames=False,
    #                                               force_enhance=force_enhance,
    #                                               name_infos=name_infos)

    if convert:
        for fn_group in processed_filename_groups:
            import pbt2ptt

            fn_group = pbt2ptt.convert(fn_group,
                                       unlink=unlink,
                                       report_progress=True,
                                       force_reconvert=False,
                                       multiprocess=True)
Ejemplo n.º 8
0
def scatter_papi(filenames, units, unit_modify, args):
    with Timer() as main:
        # The import of matplotlib is timed because it takes a surprisingly long time.
        with Timer() as t:
            import matplotlib
            matplotlib.use('Agg')  # For use with headless systems
            import matplotlib.pyplot as plt
            import matplotlib.cm as cm
        #print('Importing matplotlib took {} seconds.\n'.format(t.interval))

        trace = None
        # This is for loading and possibly converting trace files.
        with Timer() as t:
            if len(filenames) == 1 and (ptt.is_ptt(filenames[0])):
                print('Loading the HDFed trace...')
            else:
                print(
                    'Converting binary trace to the ParSEC Trace Tables format...'
                )
                filenames[0] = pbt2ptt.convert(filenames, report_progress=True)
                print('Loading the HDFed trace...')
            trace = ptt.from_hdf(filenames[0])

        print('The load took {} seconds.\n'.format(t.interval))

        i = 0
        if args.list:
            print('Available Counters:')
            for col_name in trace.events.columns.values:
                if col_name == 'begin':
                    break
                if '_start' in col_name:
                    continue
                print(str(i) + '\t' + col_name)
                i += 1
            print('\nAvailable Events:')
            for i in range(0, len(trace.event_names) - 1):
                if not trace.event_names[i].startswith('PINS_PAPI'):
                    print(str(i) + '\t' + trace.event_names[i])
            exit()

        colors_needed = 0
        num_counters = 0
        event_names = []
        event_types = []
        column_names = []

        i = 0
        available = []
        # We only need to print these if the user hasn't already specified a list of counters
        if args.counters == None:
            print(
                '/nPlease select the counter(s) you want to plot as a comma-separated list.  Enter \'-1\' for all.'
            )
            print(
                'You may also specify a range of events within the list.  For instance, 4-6 translates to 4,5,6.'
            )
            print('Example: 0,1,4-6,8\n')
        for col_name in trace.events.columns.values:
            if col_name == 'begin':
                break
            if '_start' in col_name:
                continue
            if args.counters == None:
                print(str(i) + '\t' + col_name)
            available.append(col_name)
            i += 1
        if args.counters == None:
            selection = raw_input('Counter(s) to measure: ')
            selection = selection.replace(' ', '')
        else:
            selection = args.counters

        print('\nYour selected counter(s):')
        if selection != '-1':
            selection = selection.split(',')
            i = 0
            # Iterate through the selections and print the corresponding counters
            while True:
                # If this is a list of counters, break it up and add each to the list
                if '-' in selection[i]:
                    min_max = selection[i].split('-')
                    selection[i] = available[int(min_max[0])]
                    print(min_max[0] + '\t' + selection[i])
                    inc = 0
                    for n in range(int(min_max[0]) + 1, int(min_max[1]) + 1):
                        inc += 1
                        print(str(n) + '\t' + available[n])
                        selection.insert(i + inc, available[n])
                    i += inc + 1
                else:
                    print(selection[i] + '\t' + available[int(selection[i])])
                    selection[i] = available[int(selection[i])]
                    i += 1
                if i == len(selection):
                    break
        # Add all of the counters to the selection
        else:
            selection = []
            for i in range(0, len(available)):
                print(str(i) + '\t' + available[i])
                selection.append(available[i])
        column_names.extend(selection)
        num_counters = len(selection)

        # We only need to do this if the user hasn't specified a list of events already
        if args.events == None:
            print(
                '\n\nPlease select the event(s) you want to plot as a comma-separated list.  Enter \'-1\' for all.'
            )
            print(
                'You may also specify a range of events within the list.  For instance, 4-6 translates to 4,5,6.'
            )
            print('Example: 0,1,4-6,8\n')
            for i in range(0, len(trace.event_names) - 1):
                if not trace.event_names[i].startswith('PINS_PAPI'):
                    print(str(i) + '\t' + trace.event_names[i])
            selection = raw_input('Event(s) to Measure: ')
            selection = selection.replace(' ', '')
        else:
            selection = args.events

        print('\nYour selected event(s):')
        if selection != '-1':
            selection = selection.split(',')
            i = 0
            # Iterate through the selections and print the corresponding events
            while True:
                # If this is a list of events, break it up and add each to the list
                if '-' in selection[i]:
                    min_max = selection[i].split('-')
                    selection[i] = trace.event_names[int(min_max[0])]
                    event_types.append(trace.event_types[selection[i]])
                    print(min_max[0] + '\t' +
                          trace.event_names[int(min_max[0])])
                    inc = 0
                    for n in range(int(min_max[0]) + 1, int(min_max[1]) + 1):
                        inc += 1
                        print(str(n) + '\t' + trace.event_names[n])
                        selection.insert(i + inc, trace.event_names[n])
                        event_types.append(trace.event_types[selection[i +
                                                                       inc]])
                    i += inc + 1
                else:
                    print(selection[i] + '\t' +
                          trace.event_names[int(selection[i])])
                    selection[i] = trace.event_names[int(selection[i])]
                    event_types.append(trace.event_types[selection[i]])
                    i += 1
                if i == len(selection):
                    break
        else:
            selection = []
            for i in range(0, len(trace.event_names) - 1):
                if not trace.event_names[i].startswith('PINS_PAPI'):
                    print(str(i) + '\t' + trace.event_names[i])
                    selection.append(trace.event_names[i])
                    event_types.append(trace.event_types[selection[-1]])
        print('')
        event_names = selection

        colors_needed = num_counters * len(event_names)
        print('Colors Needed: ' + str(colors_needed))

        # The counter_data list will store subsets of the pandas dataframes for the
        # columns containing PAPI counter information.  The column_names list stores
        # the names corresponding to those columns.
        counter_data = []
        counter_dict = []
        event_data = []
        print('Populating user-defined lists...')
        with Timer() as t:
            # We start from the beginning, which is where the PAPI event columns will be.
            for i in range(0, len(trace.events.columns.values)):
                column_name = trace.events.columns.values[i]
                # If we hit the 'begin' column, there aren't any more PAPI event columns.
                if column_name == 'begin':
                    break
                if '_start' in column_name:
                    continue
                if column_name not in column_names:
                    continue
                # We only care about the data in this column for which there is data.
                # Note: counter_data actually stores all of the rows for which the column
                #       of interest is not NULL.
                counter_data.append(
                    trace.events[:][trace.events[column_name].notnull()])
                prev = 0
                counter_dict.append(dict())

                end_count = counter_data[-1][column_name].values.tolist()
                start_count = counter_data[-1][column_name +
                                               '_start'].values.tolist()
                for j in range(0, len(end_count)):
                    counter_dict[-1][
                        end_count[j]] = end_count[j] - start_count[j]
            for i in range(0, len(event_types)):
                event_data.append(
                    trace.events[:][trace.events.type == event_types[i]])
        print('Populating the lists took {} seconds.\n'.format(t.interval))

        max_count = 0
        for i in range(0, len(counter_data)):
            print('i = ' + str(i))
            # For each counter, iterate through all of the selected event types
            for j in range(0, len(event_types)):
                # The begins, ends, and streams lists are used for selecting correct records from pandas
                begins = event_data[j].begin.tolist()
                ends = event_data[j].end.tolist()
                streams = event_data[j].stream_id.tolist()
                counts = []

                for k in range(0, len(event_data[j])):
                    temp_data = counter_data[i][:][
                        (counter_data[i].begin < ends[k])
                        & (counter_data[i].end > begins[k])
                        &
                        (counter_data[i].stream_id
                         == streams[k])].loc[:,
                                             [column_names[i], 'begin', 'end'
                                              ]].values.tolist()
                    for l in range(0, len(temp_data)):
                        temp_begin = 0
                        temp_end = 0
                        if temp_data[l][1] < begins[k]:
                            # The measurement started before the event
                            temp_begin = begins[k]
                        else:
                            # The measurement started after the event
                            temp_begin = temp_data[l][1]
                        if temp_data[l][2] > ends[k]:
                            # The measurement ended after the event
                            temp_end = ends[k]
                        else:
                            # The measurement ended before the event
                            temp_end = temp_data[l][2]
                        # This is the proportion of overlap between the counter and event data
                        overlap = (temp_end - temp_begin) / (temp_data[l][2] -
                                                             temp_data[l][1])
                        # Only the proportion of the counter data that corresponds to this event is recorded.
                        # Note: This is an approximation, because events will inevitably accumulate counts
                        #       at different rates.
                        counts.append(
                            int(overlap * counter_dict[i][temp_data[l][0]]))
                for val in counts:
                    if val > max_count:
                        max_count = val

        # Start the plot of the figure with a relatively large size.
        fig = plt.figure(num=None,
                         figsize=(16, 9),
                         dpi=80,
                         facecolor='w',
                         edgecolor='k')
        # Start the color iterator so we can plot each column in its own color.
        colors = iter(cm.rainbow(np.linspace(0, 1, colors_needed)))
        print('Plotting all selected counters and events together...')
        with Timer() as t:
            # Iterate through all of the selected counters
            for i in range(0, len(counter_data)):
                # For each counter, iterate through all of the selected event types
                for j in range(0, len(event_types)):
                    # The begins, ends, and streams lists are used for selecting correct records from pandas
                    begins = event_data[j].begin.tolist()
                    ends = event_data[j].end.tolist()
                    streams = event_data[j].stream_id.tolist()
                    counts = []
                    times = []

                    print('Processing and plotting \'' + event_names[j] + '_' +
                          column_names[i] + '\'...')
                    # Iterate through all of the events within this event type
                    for k in range(0, len(event_data[j])):
                        # This command grabs all of the rows for which the counter data and the event data overlap in time on the same execution stream
                        temp_data = counter_data[i][:][
                            (counter_data[i].begin < ends[k])
                            & (counter_data[i].end > begins[k])
                            & (counter_data[i].stream_id == streams[k]
                               )].loc[:, [column_names[i], 'begin', 'end'
                                          ]].values.tolist()
                        # Iterate through all of the counter data rows for this event.
                        # Note: There will typically be only 1 overlapping counter row, but it is possible there could be more
                        for l in range(0, len(temp_data)):
                            temp_begin = 0
                            temp_end = 0
                            if temp_data[l][1] < begins[k]:
                                # The measurement started before the event
                                temp_begin = begins[k]
                            else:
                                # The measurement started after the event
                                temp_begin = temp_data[l][1]
                            if temp_data[l][2] > ends[k]:
                                # The measurement ended after the event
                                temp_end = ends[k]
                            else:
                                # The measurement ended before the event
                                temp_end = temp_data[l][2]
                            # This is the proportion of overlap between the counter and event data
                            overlap = (temp_end - temp_begin) / (
                                temp_data[l][2] - temp_data[l][1])
                            # Only the proportion of the counter data that corresponds to this event is recorded.
                            # Note: This is an approximation, because events will inevitably accumulate counts
                            #       at different rates.
                            counts.append(
                                int(overlap *
                                    counter_dict[i][temp_data[l][0]]))
                            times.append(temp_end * unit_modify)

                    adjust_factor = 1000
                    adjust_power = 3
                    while max_count > adjust_factor:
                        adjust_factor *= 1000
                        adjust_power += 3
                    adjust_factor /= 1000
                    adjust_power -= 3

                    if (adjust_factor > 1):
                        for v in range(0, len(counts)):
                            counts[v] /= adjust_factor

                    # Plot the data for this event type
                    plt.scatter(times,
                                counts,
                                color=next(colors),
                                label=event_names[j] + '_' + column_names[i])

                plt.title('Counts by Event Name')
                plt.ylim(ymin=0)
                plt.xlim(xmin=0)

                if (adjust_power > 0):
                    plt.ylabel('Count (Times 10^' + str(adjust_power) + ')')
                else:
                    plt.ylabel('Count')

                if units != 'c':
                    plt.xlabel('Time (' + units + ')')
                else:
                    plt.xlabel('Cycles')

                ax = plt.subplot(111)
                box = ax.get_position()
                ax.set_position([box.x0, box.y0, box.width * 0.8, box.height])
                ax.legend(loc='center left', bbox_to_anchor=(1, 0.5))

                plt.show()

        figure_name = 'counts_by_eventname.png'

        if args.output != None:
            figure_name = args.output

        print('Saving plot as ' + figure_name + '...')
        fig.savefig(figure_name)

        print('Plotting and saving took {} seconds.'.format(t.interval))

    print('Total Time: {} seconds\n'.format(main.interval))