Revision 2f8f6071

View differences:

scripts/measure_breakage_time.py
9 9
import json
10 10
import copy
11 11

  
12
def readTopology(pathPrefix):
13
    jsonRt = defaultdict(dict)
14
    nodeSet = set()
15
    failedNodes = {}
16
    for topoFile in glob.glob(pathPrefix+"*.json"):
17
        try:
18
            f = open(topoFile, "r")
19
            j = json.load(f)
20
        except Exception as e:
21
            print "NOK", str(e)
22
            sys.exit(1)
23
        #nodeIP = ".".join(j["node"].split(":")[0].split(".")[:3])
24
        nodeIP = j["node"].split(":")[0]
25
        if j["fail"] == True:
26
            failedNodes[nodeIP] = j["failtime"]
27
        rt = j["log"]
28
        for logId, logDump in rt.items():
29
            jsonRt[logId][nodeIP] = logDump["RT"]
30
            jsonRt[logId]["time"] = logDump["time"]
31
        nodeSet.add(str(nodeIP))
32
    return jsonRt, nodeSet, failedNodes
33

  
34

  
35
def checkRoutingTables(jsonRt, ns, failedNodes):
36
    errors = 0
37
    loops = 0
38
    jsonRtPurged = copy.deepcopy(jsonRt)
39

  
40
    for failedNode, failureTime in failedNodes.items():
41
        if jsonRt["time"] > failureTime and failedNode in ns:
42
            ns.remove(failedNode)
43

  
44
    nl = list(ns)
45
    routesOk = 0
46
    for i in range(len(nl)):
47
        sIP = nl[i]
48
        for j in range(len(nl)):
49
            if i == j:
50
                continue
51
            dIP = nl[j]
12
class resultParser():
13

  
14
    def readTopology(self, pathPrefix):
15
        jsonRt = defaultdict(dict)
16
        nodeSet = set()
17
        failedNodes = {}
18
        signallingSent = 0
19
        for topoFile in glob.glob(pathPrefix+"*.json"):
52 20
            try:
53
                route = navigateRoutingTables(jsonRtPurged, sIP,
54
                    dIP, [], 0)
55
            except KeyError as e:
56
                errors += 1
57
                print str(e)
58
                print sIP, jsonRt[sIP]
59
                print dIP, jsonRt[dIP]
60
                print "NOK!: there is no route from ", sIP, "to", dIP
61
                continue
62
            except LoopError:
63
                print "NOK: there is a loop from", sIP, "to", dIP
64
                loops += 1
65
                continue
66
            print "OK!: route", route
67
            routesOk += 1
68
    return routesOk, errors, loops
69

  
70

  
21
                f = open(topoFile, "r")
22
                j = json.load(f)
23
            except Exception as e:
24
                print "NOK", str(e)
25
                sys.exit(1)
26
            #nodeIP = ".".join(j["node"].split(":")[0].split(".")[:3])
27
            nodeIP = j["node"].split(":")[0]
28
            if j["fail"] == True:
29
                failedNodes[nodeIP] = j["failtime"]
30
            rt = j["log"]
31
            signallingSent += j["signalling"]
32
            for logId, logDump in rt.items():
33
                jsonRt[logId][nodeIP] = logDump["RT"]
34
                jsonRt[logId]["time"] = logDump["time"]
35
            nodeSet.add(str(nodeIP))
36
        return jsonRt, nodeSet, failedNodes, signallingSent
37
    
38
    
39
    def checkRoutingTables(self, jsonRt, ns, failedNodes):
40
        errors = 0
41
        loops = 0
42
        jsonRtPurged = copy.deepcopy(jsonRt)
43
    
44
        for failedNode, failureTime in failedNodes.items():
45
            if jsonRt["time"] > failureTime and failedNode in ns:
46
                ns.remove(failedNode)
47
    
48
        nl = list(ns)
49
        routesOk = 0
50
        for i in range(len(nl)):
51
            sIP = nl[i]
52
            for j in range(len(nl)):
53
                if i == j:
54
                    continue
55
                dIP = nl[j]
56
                try:
57
                    route = navigateRoutingTables(jsonRtPurged, sIP,
58
                        dIP, [], 0)
59
                except KeyError as e:
60
                    errors += 1
61
                    print "NOK!: there is no route from ", sIP, "to", dIP
62
                    continue
63
                except LoopError:
64
                    print "NOK: there is a loop from", sIP, "to", dIP
65
                    loops += 1
66
                    continue
67
                print "OK!: route", route
68
                routesOk += 1
69
        return routesOk, errors, loops
70

  
71

  
72
    def parseAllRuns(self, jsonRt, nodeSet, failedNodes):
73

  
74
        retDict = {}
75
        for logId, rt in sorted(jsonRt.items(), 
76
                key = lambda x: int(x[0]))[:-1]:
77
            # skip the last one, misalignments with random timers can 
78
            # produce partial data
79
            retDict[jsonRt[logId]["time"]] = \
80
                    self.checkRoutingTables(jsonRt[logId], nodeSet,
81
                            failedNodes)
82
        return retDict
71 83

  
72 84

  
73 85
if __name__ == "__main__":
......
83 95

  
84 96
    pathPrefix = sys.argv[1]
85 97

  
86
    jsonRt, nodeSet, failedNodes = readTopology(pathPrefix)
87
    print nodeSet, failedNodes
98
    p = resultParser()
99
    jsonRt, nodeSet, failedNodes, signallingSent = p.readTopology(pathPrefix)
88 100

  
89 101
    if not nodeSet:
90 102
        print "NOK: can not read routing tables"
91 103
        sys.exit(1)
92 104

  
93
    for logId, rt in sorted(jsonRt.items(), key = lambda x: int(x[0]))[:-1]:
94
        # skip the last one, misalignments with random timers can 
95
        # produce partial data
96
        routesOk, routeErrors, loopErrors = \
97
                checkRoutingTables(jsonRt[logId], nodeSet,
98
                        failedNodes)
99
        print "XX", jsonRt[logId]["time"], routesOk, routeErrors, loopErrors
105
    results = p.parseAllRuns(jsonRt, nodeSet, failedNodes)
106

  
107
    for time in sorted(results):
108
        print "FailedRoutes", time, results[time]
109
    print "Signalling: ", signallingSent
100 110

  
101 111

  
scripts/run_batch_simulations.py
1
#! /usr/bin/env python
2

  
3
import sys
4
import os
5
import time
6
import argparse
7
import glob
8
import matplotlib.pyplot as plt
9
from subprocess import check_output, CalledProcessError, call
10

  
11
import json
12

  
13
from measure_breakage_time import resultParser
14

  
15
class EmulationRunner():
16

  
17
    def __init__(self):
18
        self.path_prefix = ""
19
        self.args = None
20

  
21
    def parse_args(self):
22
        parser = argparse.ArgumentParser(description = "batch simulation launcher"+ \
23
            " and analyser")
24
        parser.add_argument("-r", dest="runs", help="number of runs",
25
            default=1, type=int)
26
        parser.add_argument("-f", dest="confile", help="configuration file",
27
            default="conf/dummyrouting.ini", type=str)
28
        parser.add_argument("-t", dest="stanza", required=True,
29
                help="name of the configuration to run", type=str)
30
        parser.add_argument("-p", dest="parseonly", action="store_true",
31
                help="do not run the simulation, only parse results")
32
        self.args = parser.parse_args()
33

  
34

  
35
    def run_and_parse(self):
36
        if not self.args.parseonly and os.getuid() != 0:
37
            print "You should run this script as root"
38
            sys.exit(1)
39
        p = resultParser()
40
        self.path_prefix = "/tmp/dummyrouting-log"
41
        ret_value = {}
42
        for i in range(self.args.runs):
43
            if not self.args.parseonly and i == 0:
44
                self.clean_environment()
45
            elif i != 0:
46
                self.clean_environment(auto=True)
47
            command = ["./wcn_simulator.py", "-f", str(self.args.confile), \
48
                    "-t", str(self.args.stanza)]
49
            self.command = command
50
            if not self.args.parseonly:
51
                self.execute_run(command)
52
            jsonRt, nodeSet, failedNodes, signallingSent = \
53
                    p.readTopology(self.path_prefix)
54
            results = p.parseAllRuns(jsonRt, nodeSet, failedNodes)
55
            failures = 0
56
            for tt in sorted(results):
57
                failures += sum(results[tt][1:])
58
            ret_value[i] = {}
59
            ret_value[i]["results"] = results
60
            ret_value[i]["signalling"] = signallingSent
61
            ret_value[i]["failures"] = failures
62
            ret_value[i]["failed_nodes"] = failedNodes
63
        return ret_value
64

  
65
    def save_results(self, results):
66
        results["time"] = time.time()
67
        results["command"] = " ".join(self.command)
68
        out_string = json.dumps(results, indent=1)
69
        out_file_name = "/tmp/"+self.args.stanza+"_"+str(int(time.time()))+".results"
70
        try:
71
            out_file = open(out_file_name, 'w')
72
        except:
73
            print "Error: could not open file " + out_file
74
            raise
75
        print >> out_file, out_string
76
        out_file.close()
77

  
78
    def summarise_results(self, results):
79
        signalling_messages = 0
80
        failed_routes = 0
81
        for k,v in results.items():
82
            if k in ["time", "command"]:
83
                continue
84
            signalling_messages += v["signalling"]
85
            failed_routes += v["failures"]
86
        ret_value = {}
87
        ret_value["signalling"] = signalling_messages
88
        ret_value["failures"] = failed_routes
89
        return ret_value
90

  
91
    def plot_results(self, results, title=""):
92
        x = []
93
        y = []
94
        xlabel = "Experiment Time"
95
        ylabel = "Broken Paths"
96
        run_number = 0
97
        for runId,v in results.items():
98
            if runId in ["time", "command"]:
99
                continue
100
            run_x = []
101
            run_y = []
102
            print v
103
            for tt,vv in (sorted(v["results"].items(),
104
                key = lambda x: x[0])):
105
                run_x.append(tt)
106
                run_y.append(vv[1] + vv[2])
107
            run_number += 1
108
            x.append(run_x)
109
            y.append(run_y)
110
        for runId in range(run_number):
111
            plt.plot(x[runId],y[runId], label="Failed node:")
112
        plt.xlabel(xlabel)
113
        plt.ylabel(ylabel)
114
        title += " runs:" + str(run_number)
115
        plt.title(title)
116
        plt.savefig("/tmp/pp.png")
117
        plt.show()
118

  
119

  
120
    def clean_environment(self, auto=False):
121
        commands = []
122
        log_files = glob.glob(self.path_prefix+"*")
123
        dump_files = glob.glob("../"+self.args.stanza+"*")
124
        c = []
125
        if log_files:
126
            commands.append(["rm", "-rf"]+log_files)
127
        if dump_files:
128
            commands.append(["rm", "-rf"]+dump_files)
129
        if not auto:
130
            inputString = "I'm about to run:\n"
131
            for c in commands:
132
                inputString += " ".join(c) + "\n"
133
            inputString += "[y/n]:"
134
            user_input = raw_input(inputString)
135
        if auto or user_input == 'y':
136
            for c in commands:
137
                call(c)
138
        elif user_input != 'n' and not auto:
139
            user_input = raw_input("please choose y/n:")
140
            if user_input == 'y':
141
                for c in commands:
142
                    call(c)
143
            elif user_input != 'n':
144
                print "seems you're too dumb to choose between y/n, erasing nothing"
145

  
146

  
147
    def execute_run(self, command):
148

  
149
        if not command:
150
            print "Please give me a command to run"
151
            sys.exit(1)
152
        try:
153
            output = check_output(command, cwd="../")
154
        except CalledProcessError:
155
            print "command: ", command , " exited with non-zero value"
156
            raise
157
        except:
158
            print "Could not run command ", command
159
            raise
160

  
161
if __name__ == "__main__":
162
    e = EmulationRunner()
163
    e.parse_args()
164
    results = e.run_and_parse()
165
    e.save_results(results)
166
    r = e.summarise_results(results)
167
    e.plot_results(results, title = "Tot failures " + str(r["failures"]) + \
168
            ", tot signalling " + str(r["signalling"]))
169
    print r

Also available in: Unified diff