From d9fc4e166eb0917e52cfeeff3c67f250b10c118f Mon Sep 17 00:00:00 2001 From: Leonardo Bautista-Gomez Date: Mon, 27 Mar 2023 15:29:39 +0200 Subject: [PATCH] Switch from time steps to miliseconds --- DAS/results.py | 15 ++++++++------- DAS/simulator.py | 9 +++++---- DAS/visualizer.py | 6 ++++-- config_example.py | 15 +++++++++------ study.py | 4 ++-- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/DAS/results.py b/DAS/results.py index 0efe26d..7f1ccb4 100644 --- a/DAS/results.py +++ b/DAS/results.py @@ -7,31 +7,32 @@ from dicttoxml import dicttoxml class Result: """This class stores and process/store the results of a simulation.""" - def __init__(self, shape): + def __init__(self, shape, execID): """It initializes the instance with a specific shape.""" self.shape = shape + self.execID = execID self.blockAvailable = -1 self.tta = -1 self.missingVector = [] - def populate(self, shape, missingVector): + def populate(self, shape, config, missingVector): """It populates part of the result data inside a vector.""" self.shape = shape self.missingVector = missingVector missingSamples = missingVector[-1] if missingSamples == 0: self.blockAvailable = 1 - self.tta = len(missingVector) + self.tta = len(missingVector) * (1000/config.stepDuration) else: self.blockAvailable = 0 self.tta = -1 - def dump(self, execID): + def dump(self): """It dumps the results of the simulation in an XML file.""" if not os.path.exists("results"): os.makedirs("results") - if not os.path.exists("results/"+execID): - os.makedirs("results/"+execID) + if not os.path.exists("results/"+self.execID): + os.makedirs("results/"+self.execID) resd1 = self.shape.__dict__ resd2 = self.__dict__.copy() resd2.pop("shape") @@ -39,6 +40,6 @@ class Result: resXml = dicttoxml(resd1) xmlstr = minidom.parseString(resXml) xmlPretty = xmlstr.toprettyxml() - filePath = "results/"+execID+"/"+str(self.shape)+".xml" + filePath = "results/"+self.execID+"/"+str(self.shape)+".xml" with open(filePath, "w") as f: f.write(xmlPretty) diff --git a/DAS/simulator.py b/DAS/simulator.py index a6788b8..ab61729 100644 --- a/DAS/simulator.py +++ b/DAS/simulator.py @@ -13,12 +13,13 @@ from DAS.validator import * class Simulator: """This class implements the main DAS simulator.""" - def __init__(self, shape, config): + def __init__(self, shape, config, execID): """It initializes the simulation with a set of parameters (shape).""" self.shape = shape self.config = config self.format = {"entity": "Simulator"} - self.result = Result(self.shape) + self.execID = execID + self.result = Result(self.shape, self.execID) self.validators = [] self.logger = [] self.logLevel = config.logLevel @@ -207,12 +208,12 @@ class Simulator: missingVector.append(missingSamples) break elif missingSamples == 0: - #self.logger.info("The entire block is available at step %d, with failure rate %d !" % (steps, self.shape.failureRate), extra=self.format) + self.logger.debug("The entire block is available at step %d, with failure rate %d !" % (steps, self.shape.failureRate), extra=self.format) missingVector.append(missingSamples) break else: steps += 1 - self.result.populate(self.shape, missingVector) + self.result.populate(self.shape, self.config, missingVector) return self.result diff --git a/DAS/visualizer.py b/DAS/visualizer.py index 8afd006..db4b2d5 100644 --- a/DAS/visualizer.py +++ b/DAS/visualizer.py @@ -36,7 +36,7 @@ class Visualizer: bwUplinkProd = int(root.find('bwUplinkProd').text) bwUplink1 = int(root.find('bwUplink1').text) bwUplink2 = int(root.find('bwUplink2').text) - tta = int(root.find('tta').text) + tta = float(root.find('tta').text) # Loop over all possible combinations of of the parameters minus two for combination in combinations(self.parameters, len(self.parameters)-2): @@ -120,7 +120,7 @@ class Visualizer: hist, xedges, yedges = np.histogram2d(data[key][labels[0]], data[key][labels[1]], bins=(len(xlabels), len(ylabels)), weights=data[key]['ttas']) hist = hist.T fig, ax = plt.subplots(figsize=(10, 6)) - sns.heatmap(hist, xticklabels=xlabels, yticklabels=ylabels, cmap='Purples', cbar_kws={'label': 'Time to block availability'}, linecolor='black', linewidths=0.3, annot=True, fmt=".2f", ax=ax) + sns.heatmap(hist, xticklabels=xlabels, yticklabels=ylabels, cmap='Purples', cbar_kws={'label': 'Time to block availability (ms)'}, linecolor='black', linewidths=0.3, annot=True, fmt=".2f", ax=ax) plt.xlabel(self.formatLabel(labels[0])) plt.ylabel(self.formatLabel(labels[1])) filename = "" @@ -131,6 +131,8 @@ class Visualizer: filename += f"{key[paramValueCnt]}" formattedTitle = self.formatTitle(key[paramValueCnt]) title += formattedTitle + if (paramValueCnt+1) % 5 == 0: + title += "\n" paramValueCnt += 1 title_obj = plt.title(title) font_size = 16 * fig.get_size_inches()[0] / 10 diff --git a/config_example.py b/config_example.py index af55fc2..9afde53 100644 --- a/config_example.py +++ b/config_example.py @@ -24,14 +24,14 @@ logLevel = logging.INFO # number of parallel workers. -1: all cores; 1: sequential # for more details, see joblib.Parallel -numJobs = 3 +numJobs = -1 # distribute rows/columns evenly between validators (True) # or generate it using local randomness (False) evenLineDistribution = True # Number of simulation runs with the same parameters for statistical relevance -runs = range(10) +runs = range(2) # Number of validators numberNodes = range(256, 513, 128) @@ -46,14 +46,14 @@ blockSizes = range(32,65,16) netDegrees = range(6, 9, 2) # number of rows and columns a validator is interested in -chis = range(1, 5, 2) +chis = range(2, 5, 2) # ratio of class1 nodes (see below for parameters per class) -class1ratios = np.arange(0, 1, .2) +class1ratios = [0.8, 0.9] # Number of validators per beacon node validatorsPerNode1 = [1] -validatorsPerNode2 = [2, 4, 8, 16, 32] +validatorsPerNode2 = [500] # Set uplink bandwidth. In segments (~560 bytes) per timestep (50ms?) # 1 Mbps ~= 1e6 / 20 / 8 / 560 ~= 11 @@ -61,8 +61,11 @@ bwUplinksProd = [2200] bwUplinks1 = [110] bwUplinks2 = [2200] +# Step duration in miliseconds (Classic RTT is about 100ms) +stepDuration = 50 + # Set to True if you want your run to be deterministic, False if not -deterministic = False +deterministic = True # If your run is deterministic you can decide the random seed. This is ignore otherwise. randomSeed = "DAS" diff --git a/study.py b/study.py index fde8099..74dba63 100644 --- a/study.py +++ b/study.py @@ -28,7 +28,7 @@ def runOnce(config, shape, execID): shape.setSeed(config.randomSeed+"-"+str(shape)) random.seed(shape.randomSeed) - sim = Simulator(shape, config) + sim = Simulator(shape, config, execID) sim.initLogger() sim.initValidators() sim.initNetwork() @@ -36,7 +36,7 @@ def runOnce(config, shape, execID): sim.logger.info("Shape: %s ... Block Available: %d in %d steps" % (str(sim.shape.__dict__), result.blockAvailable, len(result.missingVector)), extra=sim.format) if config.dumpXML: - result.dump(execID) + result.dump() return result