source: benchmark/convoy/genConvoyStats.py@ d0bdb18

ADT ast-experimental
Last change on this file since d0bdb18 was fd6e3a4, checked in by caparsons <caparson@…>, 3 years ago

small CLI changes to convoy script

  • Property mode set to 100644
File size: 6.8 KB
RevLine 
[93e0603]1import os
2import sys
3import math
4import argparse
5import statistics as st
6
7# Parsing Logic
8parser = argparse.ArgumentParser(prog = 'GenConvoyStats',
9 description = 'Analyzes handoff matrix output and uses Markov chain modelling to provide upper and lower bounds on the largest long term convoy',
10 epilog = '')
11
12parser.add_argument("Filename")
[fd6e3a4]13parser.add_argument("-r", "--RunsPerNumThds", default=5, help="Number of trials per # of threads. Default is 5")
[93e0603]14parser.add_argument("-m", "--MaxThreads", default=32, help="Maximum number of threads. Default is 32")
15parser.add_argument("-o", "--OutputFile", default='', help="File to write output to")
16parser.add_argument("-v", "--Verbose", help="Verbose output. Will print per run stats alongside aggregates", action='count', default=0)
17
18args = parser.parse_args()
19
20# handoff data
21handoff = []
22sumPerRow = []
23handoffTotal = 0
24maxCycleSum = 0
25maxCycle = []
26
27# per thread data (across runs)
28minBound = []
29maxBound = []
30expected = []
31
32# input file descriptor
33readFile = open(args.Filename, "r")
34
35writeFile = False
36if args.OutputFile != '':
37 writeFile = open(args.Filename, "w")
38
39def reset():
40 global handoff, sumPerRow, handoffTotal, readFile, maxCycleSum, maxCycle
41 handoff.clear()
42 sumPerRow.clear()
43 handoffTotal = 0
44 maxCycleSum = 0
45 maxCycle.clear()
46
47def thdReset():
48 global minBound, maxBound, expected
49 minBound.clear()
50 maxBound.clear()
51 expected.clear()
52
53def output(string):
54 global writeFile
55 if writeFile:
56 writeFile.write(string + '\n')
57
58 print(string)
59
60# reads in handoff matrix for a single run and accumulates row/matrix total at the same time
61def readInMatrix(currThds):
62 global handoff, sumPerRow, handoffTotal, readFile
63 for i in range(currThds):
64 line = readFile.readline()
65
66 # Deal with EOF
67 if not line:
68 print("Incorrect arguments or file format: error in readInMatrix")
69 sys.exit(1)
70
71 # deal with any empty lines
72 while line == '\n':
73 line = readFile.readline()
74
75 row = []
76 rowSum = 0
77
78 # convert row into list of ints and accumulate
79 for val in line.replace(',','').split():
80 row.append(int(val))
81 rowSum += int(val)
82
83 #store row in global state
84 handoff.append(row)
85 sumPerRow.append(rowSum)
86 handoffTotal += rowSum
87
88# moves current non empty line in readFile to line after line described by first two chars
89def goToLineByStartingChars(string):
90 global readFile
91 # find start of relevant data
92 line = ""
93 while True:
94 line = readFile.readline()
95 if not line:
96 print("Incorrect arguments or file format: error in goToLineByStartingChars")
97 sys.exit(1)
98
99 # strip after checking for EOF so we can distinguish EOF vs empty line
100 line = line.strip()
101
102 # discard lines until we see the column line in output
103 if line and line[0:len(string)] == string:
104 break
105
106# recursively find largest cycle included a specific node using DFS
107def findLargestCycle(startNode, currNode, visited, globalVisited, currSum, currCycle):
108 global handoff, maxCycle, maxCycleSum
109
110 # print("CurrNode: " + str(currNode))
111 # print(currCycle)
112 # if we visit a node from a previous call then return since we have already
113 # looked at all cycles containing that node
114 if globalVisited[currNode]:
115 # print("globalVisited")
116 return
117
118 # found a cycle
119 if visited[currNode]:
120 # print("LocalVisited, curr: " + str(currSum) + ", max: " + str(maxCycleSum) + ", Start: " + str(startNode) )
121 # if the cycle contains the start node check if it is our new max cycle
122 if currNode == startNode and currSum > maxCycleSum:
123 # print("NewMax")
124 maxCycleSum = currSum
125 maxCycle = currCycle.copy()
126 return
127
128 visited[currNode] = True
129
130 for idx, val in enumerate(handoff[currNode]):
131 # continue if no edge
132 if val == 0:
133 continue
134
135 currCycle.append(currNode)
136 findLargestCycle(startNode, idx, visited, globalVisited, currSum + val, currCycle)
137 currCycle.pop()
138
139 visited[currNode] = False
140
141
142
143def analyzeRun():
144 global handoff, sumPerRow, handoffTotal, maxCycle, maxCycleSum, minBound, maxBound, expected
145 currThds = len(handoff)
146
147 # find largest cycle
148 globalVisited = [False] * currThds
149 for i in range(currThds):
150 visited = [False] * currThds
151 findLargestCycle(i, i, visited, globalVisited, 0, [])
152 globalVisited[i] = True
153
154 # calculate stats
155 cycleHandoffs = []
156 cycleHandoffs.append(handoff[maxCycle[-1]][maxCycle[0]])
157 sumOfMaxCycleRows = sumPerRow[maxCycle[0]]
158
159 # expected handoff is MULT P( handoff ) for each handoff in max cycle
160 expectedConvoy = handoff[maxCycle[-1]][maxCycle[0]] / sumPerRow[maxCycle[-1]]
161 for idx, val in enumerate(maxCycle[1:]):
162 cycleHandoffs.append(handoff[maxCycle[idx]][val])
163 sumOfMaxCycleRows += sumPerRow[val]
164 expectedConvoy = expectedConvoy * handoff[maxCycle[idx]][val] / sumPerRow[maxCycle[idx]]
165
166 # adjust expected bound
167 # if max cycle contains all nodes, sumOfMaxCycleRows / handoffTotal == 1
168 # else this adjusts the expected bound to compensate for the cycle not visiting all nodes
169 # also mult by 100 to turn into percentage from decimal
170 expectedConvoy = expectedConvoy * sumOfMaxCycleRows * 100 / handoffTotal
171
172 # upper bound is the percentage of all handoffs that occur in the maximum possible cycle
173 # The cycle is possible min(cycleHandoffs) number of times
174 maxFeasibleHandoff = min(cycleHandoffs)
175 upperBoundConvoy = maxFeasibleHandoff * len(maxCycle) * 100 / handoffTotal
176 lowerBoundConvoy = 1
177 for val in maxCycle:
178 lowerBoundConvoy = lowerBoundConvoy * maxFeasibleHandoff / sumPerRow[val]
179
180 # adjust lower bound. See comment for expectedConvoy adjustment to explain why
181 lowerBoundConvoy = lowerBoundConvoy * sumOfMaxCycleRows * 100 / handoffTotal
182
183 maxBound.append(upperBoundConvoy)
184 minBound.append(lowerBoundConvoy)
185 expected.append(expectedConvoy)
186
187 if args.Verbose:
188 output('Convoying bounds: {:.2f}%-{:.2f}%, Expected convoying: {:.2f}%'.format(lowerBoundConvoy,upperBoundConvoy, expectedConvoy))
189
190
191for i in range(args.MaxThreads):
192 output("N: " + str(i+1))
193
194 goToLineByStartingChars(str(i+1)+' ')
[fd6e3a4]195 for j in range(args.RunsPerNumThds):
[93e0603]196 readInMatrix(i+1)
197 analyzeRun()
198 reset()
199
200 output('Mean convoying bounds: {:.2f}%-{:.2f}%, Mean expected convoying: {:.2f}%'.format(st.mean(minBound), st.mean(maxBound),st.mean(expected)))
201 output('Median convoying bounds: {:.2f}%-{:.2f}%, Median expected convoying: {:.2f}%'.format(st.median(minBound), st.median(maxBound),st.median(expected)))
202 output('')
203 thdReset()
204
205readFile.close()
206
207if writeFile:
208 writeFile.close()
Note: See TracBrowser for help on using the repository browser.