diff --git a/testdata/doubledata.py b/testdata/doubledata.py new file mode 100755 index 0000000000000000000000000000000000000000..6fac610bb2848215ed15acaf19f4de8b2251dd99 --- /dev/null +++ b/testdata/doubledata.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +""" +Usage: + doubledata.py [options] input-log doubled-log + +Split pairs of send and recv log data entries to increase the number of +messages that we send to represent the data of a step. Preserves the data +volume, but not the tagging. + +This file is part of SWIFT. + +Copyright (C) 2019 Peter W. Draper (p.w.draper@durham.ac.uk) +All Rights Reserved. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +""" + +import argparse +import sys +from operator import itemgetter + +# Handle the command line. +parser = argparse.ArgumentParser(description="Pair MPI logs") + +parser.add_argument( + "input", + help="Output log from simulator") +parser.add_argument( + "output", + help="Doubled log") +parser.add_argument( + "-v", + "--verbose", + dest="verbose", + help="Verbose output", + default=False, + action="store_true", +) +args = parser.parse_args() +infile = args.input +outfile = args.output + +# Indices for words in a line. +sticcol = 0 +eticcol = 1 +dticcol = 2 +stepcol = 3 +rankcol = 4 +otherrankcol = 5 +typecol = 6 +itypecol = 7 +subtypecol = 8 +isubtypecol = 9 +activationcol = 10 +tagcol = 11 +sizecol = 12 +sumcol = 13 + +# The plan is to pair the sends and receives across all ranks so that +# we can split each pair into two and give everything new tags that also +# match. + +# Keyed lines. +keysends = {} +keyrecvs = {} + +# Indexed lines. +sends = [] +recvs = [] +nsends = 0 +nrecvs = 0 + +# Generate keys that are unique between send/recv pairs and gather the +# associated lines initiation lines. +with open(infile, "r") as fp: + for line in fp: + if line[0] == '#': + continue + words = line.split() + if words[activationcol] == 0: + continue + + if words[itypecol] == "22": + key = words[otherrankcol] + "/" + \ + words[rankcol] + "/" + \ + words[isubtypecol] + "/" + \ + words[tagcol] + "/" + \ + words[sizecol] + if not key in keysends: + keysends[key] = [nsends] + else: + keysends[key].append(nsends) + sends.append(words) + nsends = nsends + 1 + + elif words[itypecol] == "23": + key = words[rankcol] + "/" + \ + words[otherrankcol] + "/" + \ + words[isubtypecol] + "/" + \ + words[tagcol] + "/" + \ + words[sizecol] + if not key in keyrecvs: + keyrecvs[key] = [nrecvs] + else: + keyrecvs[key].append(nrecvs) + recvs.append(words) + nrecvs = nrecvs + 1 + +print "# Read " + str(nsends) + " sends and " + str(nrecvs) + " recvs" + +# Now get the indices of the matches. +msends = [None] * nsends +for key in keysends: + if key in keyrecvs: + isend = keysends[key][0] + irecv = keyrecvs[key][0] + msends[isend] = irecv + +# Reorder recvs to same order as sends. +recvs = [recvs[i] for i in msends] + +# Now we can split and retag. +splits = [] +ctag = 0 +for i in range(nsends): + swords = sends[i] + rwords = recvs[i] + size = str(float(swords[sizecol]) / 2.0) + swords[sizecol] = size + rwords[sizecol] = size + + ctag = ctag + 1 + stag = str(ctag) + swords[tagcol] = stag + rwords[tagcol] = stag + splits.append(swords) + splits.append(rwords) + + ctag = ctag + 1 + stag = str(ctag) + swords[tagcol] = stag + rwords[tagcol] = stag + splits.append(swords) + splits.append(rwords) + +# Sort by tic. +splits = sorted(splits, key=lambda x: int(x[sticcol])) + +# And output. +with open(outfile, "w") as fp: + fp.write("# stic etic dtic step rank otherrank type itype subtype isubtype activation tag size sum\n") + for line in splits: + fp.write(" ".join(line) + "\n") + +sys.exit(0) diff --git a/testdata/pairdata.py b/testdata/pairdata.py new file mode 100755 index 0000000000000000000000000000000000000000..c53ce22ca7691227188e6f128d3dd43e5f989ed3 --- /dev/null +++ b/testdata/pairdata.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +""" +Usage: + pairdata.py [options] output-log paired-log + +Combine pairs of send and recv log data entries to reduce the number of +messages that we send to represent the data of a step. Uses a simple strategy +identifying sends and recvs of the same ranks and type/subtypes that are close +in time and combining them. We need to keep the tags and sizes matched across +the ranks so we pick the tag of the first in time and sum the sizes. + +This file is part of SWIFT. + +Copyright (C) 2019 Peter W. Draper (p.w.draper@durham.ac.uk) +All Rights Reserved. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published +by the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +""" + +import argparse +import sys +from operator import itemgetter + +# Handle the command line. +parser = argparse.ArgumentParser(description="Pair MPI logs") + +parser.add_argument( + "input", + help="Output log from simulator") +parser.add_argument( + "output", + help="Paired log") +parser.add_argument( + "-v", + "--verbose", + dest="verbose", + help="Verbose output", + default=False, + action="store_true", +) +args = parser.parse_args() +infile = args.input +outfile = args.output + +# Indices for words in a line. +sticcol = 0 +eticcol = 1 +dticcol = 2 +stepcol = 3 +rankcol = 4 +otherrankcol = 5 +typecol = 6 +itypecol = 7 +subtypecol = 8 +isubtypecol = 9 +activationcol = 10 +tagcol = 11 +sizecol = 12 +sumcol = 13 + +# Indexed lines. +lines = [] +nlines = 0 + +# Gather lines from the input log. We only want activation lines. +with open(infile, "r") as fp: + for line in fp: + if line[0] == '#': + continue + words = line.split() + if words[activationcol] == "1": + lines.append(words) + nlines = nlines + 1 + +# Sort by tag as we need a stable join (sends and recvs are not ordered). +lines = sorted(lines, key=lambda x: float(x[tagcol])) +if args.verbose: + print "# Read ", nlines, " activation logs from ", infile + +# Now locate pairs. +nmatches = 0 +nnlines = 0 +with open(outfile, "w") as fp: + for n in range(0, nlines): + nwords = lines[n] + + # If not already used. + if nwords[rankcol] == "-1": + continue + + # Check remaining lines for a match. + for m in range(n + 1, nlines): + mwords = lines[m] + + if (nwords[rankcol] == mwords[rankcol] and + nwords[otherrankcol] == mwords[otherrankcol] and + nwords[itypecol] == mwords[itypecol] and + nwords[isubtypecol] == mwords[isubtypecol]): + + # Matching send or recv of same type to and from same + # ranks. Use sum of sizes and min of tags and tics. + nwords[sizecol] = str(int(nwords[sizecol]) + int(mwords[sizecol])) + nwords[tagcol] = str(min(int(nwords[tagcol]), int(mwords[tagcol]))) + nwords[sticcol] = str(min(int(nwords[sticcol]), int(mwords[sticcol]))) + + # Don't use this other entry again. Will be skipped or + # fail to match. + mwords[rankcol] = "-1" + nmatches = nmatches + 1 + break + + # And output. + fp.write(" ".join(nwords) + "\n") + nnlines = nnlines + 1 + +if args.verbose: + print "# Matched ", nmatches, " wrote ", nnlines, " lines to ", outfile + +sys.exit(0)