|
| 1 | +#! /usr/bin/env /usr/bin/python3 |
| 2 | + |
| 3 | +import subprocess |
| 4 | +from time import sleep |
| 5 | +import shutil |
| 6 | +import os |
| 7 | +import numpy |
| 8 | +import json |
| 9 | + |
| 10 | +class channel_benchmark(): |
| 11 | + def __init__(self, tests, runsPerTest=10, timeBetweenRuns=1, |
| 12 | + senderCore=0, readerCore=2, |
| 13 | + channelArgs=["interval", "primeTime", "accessTime"]): |
| 14 | + |
| 15 | + self.sender = ['taskset', '-c', str(senderCore), |
| 16 | + sender_bin, "-b"] |
| 17 | + print(self.sender) |
| 18 | + self.resultFile = os.path.join(result_dir, "llc-pp.json") |
| 19 | + try: |
| 20 | + os.mkdir(result_dir) |
| 21 | + except (OSError): |
| 22 | + pass |
| 23 | + |
| 24 | + self.reader = ['taskset', '-c', str(readerCore), |
| 25 | + reader_bin, "-b"] |
| 26 | + |
| 27 | + self.cool_down = timeBetweenRuns |
| 28 | + self.channelArgs = channelArgs |
| 29 | + self.runs = runsPerTest |
| 30 | + self.tests = tests |
| 31 | + |
| 32 | + def readChannelFile(self, f): |
| 33 | + if os.path.isfile(f): |
| 34 | + with open(f) as fd: |
| 35 | + return [int(datum.split(" ")[1]) for datum in fd.readlines()] |
| 36 | + else: |
| 37 | + return [] |
| 38 | + |
| 39 | + def check(self, sender, reader): |
| 40 | + readerData = self.readChannelFile(reader) |
| 41 | + senderData = self.readChannelFile(sender) |
| 42 | + transition = numpy.zeros((2, 2), dtype=numpy.float64) |
| 43 | + if (len(senderData) != len(readerData)) : |
| 44 | + print("Data length mismatch!") |
| 45 | + elif (len(senderData) == 0) : |
| 46 | + print("No Data!") |
| 47 | + else: |
| 48 | + for sent,read in zip(senderData, readerData): |
| 49 | + transition[sent, read] += 1 |
| 50 | + print("Printing bit transition matrix as:") |
| 51 | + print("[[0 -> 0, 0 -> 1],\n [1 -> 0, 0 -> 1]]\n") |
| 52 | + print(transition) |
| 53 | + return transition |
| 54 | + |
| 55 | + def capacity(self, transition): |
| 56 | + m,n = transition.shape |
| 57 | + r = numpy.ones((m,)) / m |
| 58 | + q = numpy.zeros((m,n)) |
| 59 | + error_allowed = 1e-5/m |
| 60 | + for i in range(n): |
| 61 | + if transition[:,i].sum() == 0: |
| 62 | + print("error: transition matrix contains a zero columnn") |
| 63 | + return 0 |
| 64 | + |
| 65 | + for i in range(m): |
| 66 | + if transition[i].sum() == 0: |
| 67 | + print("error: transition matrix contains a zero row") |
| 68 | + return 0 |
| 69 | + transition[i] /= transition[i].sum() |
| 70 | + |
| 71 | + for iter in range(10000): |
| 72 | + for i in range(n): |
| 73 | + q[:,i] = r * transition[:,i] |
| 74 | + q[:,i] /= q[:,i].sum() |
| 75 | + rprime = r.copy() |
| 76 | + for i in range(m): |
| 77 | + rprime[i] = (q[i]**transition[i]).prod() |
| 78 | + rprime = rprime/rprime.sum() |
| 79 | + if (numpy.linalg.norm(rprime - r)) < error_allowed: |
| 80 | + break |
| 81 | + else: |
| 82 | + r = rprime |
| 83 | + |
| 84 | + cap = 0 |
| 85 | + for i in range(m): |
| 86 | + for j in range(n): |
| 87 | + if (r[i] > 0 and q[i,j] > 0): |
| 88 | + cap += r[i]*transition[i,j]*numpy.log2(q[i,j]/r[i]) |
| 89 | + return cap |
| 90 | + |
| 91 | + |
| 92 | + def doTest(self, paramMap): |
| 93 | + print("\n==== Test parameters:{} ====".format(paramMap)) |
| 94 | + try: |
| 95 | + shutil.rmtree(data_dir) |
| 96 | + except (OSError): |
| 97 | + pass |
| 98 | + try: |
| 99 | + os.mkdir(data_dir) |
| 100 | + except (OSError): |
| 101 | + pass |
| 102 | + contents = {} |
| 103 | + if not os.path.isfile(self.resultFile) \ |
| 104 | + or os.path.getmtime(sender_bin) < os.path.getmtime(self.resultFile): |
| 105 | + try: |
| 106 | + with open(self.resultFile) as results: |
| 107 | + contents = json.load(results) |
| 108 | + except OSError: |
| 109 | + pass |
| 110 | + except Exception: |
| 111 | + print("Warning: corrupted results file") |
| 112 | + |
| 113 | + key = json.dumps([paramMap[arg] for arg in self.channelArgs]) |
| 114 | + if (key in contents) and (len(contents[key]) >= 3): |
| 115 | + # estimate |
| 116 | + bitsPerSec = 2300 * 1000 * 1000 / paramMap["interval"] |
| 117 | + print(" Capacity: {}".format(max(contents[key]))) |
| 118 | + print(" Bandwidth: {}".format(max(contents[key]) * bitsPerSec)) |
| 119 | + return max(contents[key]) * bitsPerSec |
| 120 | + |
| 121 | + for i in range(self.runs): |
| 122 | + print(" run #{}...".format(i), end='') |
| 123 | + readerOut = os.path.join(data_dir, "receiverSave") |
| 124 | + senderOut = os.path.join(data_dir, "senderSave") |
| 125 | + reader = subprocess.Popen(self.reader |
| 126 | + + ['-i', str(paramMap['interval'])] |
| 127 | + + ['-p', str(paramMap['primeTime'])] |
| 128 | + + ['-a', str(paramMap['accessTime'])] |
| 129 | + ,stdin=subprocess.PIPE |
| 130 | + ,stdout=subprocess.PIPE |
| 131 | + # ,cwd=run_dir |
| 132 | + ,env=env) |
| 133 | + sender = subprocess.Popen(self.sender |
| 134 | + + ['-i', str(paramMap['interval'])] |
| 135 | + + ['-p', str(paramMap['primeTime'])] |
| 136 | + + ['-a', str(paramMap['accessTime'])] |
| 137 | + ,stdin=subprocess.PIPE |
| 138 | + ,stdout=subprocess.PIPE |
| 139 | + # ,cwd=run_dir |
| 140 | + ,env=env) |
| 141 | + sleep(self.cool_down) |
| 142 | + sender.wait() |
| 143 | + sleep(self.cool_down) |
| 144 | + # reader.wait() # needs work |
| 145 | + # in case reader did not get all rounds of testing from sender |
| 146 | + if reader.poll is None: |
| 147 | + reader.kill() |
| 148 | + print("Reader faild to get all benchmarking messages\n"); |
| 149 | + return 0 |
| 150 | + print("Done") |
| 151 | + |
| 152 | + reader_stdout = reader.communicate()[0].decode().split(' ') |
| 153 | + bits = int(reader_stdout[-4]) |
| 154 | + nsec = int(reader_stdout[-1]) |
| 155 | + |
| 156 | + if paramMap["interval"] != 0: |
| 157 | + # bitsPerSec_no_sync = 2300 * 1000 * 1000 / paramMap["interval"] |
| 158 | + bitsPerSec = bits * 1e9 / nsec |
| 159 | + else: |
| 160 | + eitsPerSec = 0 |
| 161 | + |
| 162 | + if (key not in contents) : |
| 163 | + contents[key] = [] |
| 164 | + cap = float(self.capacity(self.check(senderOut, readerOut))) |
| 165 | + print(" Capacity: {}".format(cap)) |
| 166 | + print(" Bandwidth: {}".format(cap * bitsPerSec)) |
| 167 | + contents[key] += [cap] |
| 168 | + with open(self.resultFile, "w+") as results: |
| 169 | + json.dump(contents,results) |
| 170 | + results.flush() |
| 171 | + return max(contents[key]) * bitsPerSec |
| 172 | + |
| 173 | + def benchmark(self): |
| 174 | + for test in self.tests: |
| 175 | + self.doTest(test) |
| 176 | + |
| 177 | +if __name__ == '__main__': |
| 178 | + data = map( |
| 179 | + lambda s: {"interval":s[0], "primeTime":s[1], "accessTime":s[2]}, |
| 180 | + [# interval, primeTime, accessTime |
| 181 | + (2000000, 800000, 800000), |
| 182 | + (1000000, 400000, 400000) |
| 183 | + ][0:2]) |
| 184 | + |
| 185 | + base_dir = os.path.dirname(os.path.abspath(__file__)) |
| 186 | + print(base_dir) |
| 187 | + data_dir = os.path.join(base_dir , "data") |
| 188 | + result_dir = os.path.join(base_dir, "llc-results") |
| 189 | + |
| 190 | + sender_bin = os.path.join(base_dir, "pp-llc-send") |
| 191 | + reader_bin = os.path.join(base_dir, "pp-llc-recv") |
| 192 | + |
| 193 | + if not os.path.isfile(sender_bin) or not os.path.isfile(reader_bin): |
| 194 | + print("Please have this script in the same folder as the executables") |
| 195 | + exit() |
| 196 | + |
| 197 | + env = os.environ.copy() |
| 198 | + try : |
| 199 | + env["LD_LIBRARY_PATH"] += ":" + base_dir |
| 200 | + except KeyError: |
| 201 | + env["LD_LIBRARY_PATH"] = base_dir |
| 202 | + |
| 203 | + channel = channel_benchmark(data |
| 204 | + ,runsPerTest=1 |
| 205 | + ,readerCore=0 |
| 206 | + ,senderCore=2) |
| 207 | + channel.benchmark(); |
| 208 | + |
0 commit comments