Browse Source

Churn clients, and add some more progress bars

Ian Goldberg 4 years ago
parent
commit
e5345d0150
2 changed files with 87 additions and 29 deletions
  1. 10 2
      network.py
  2. 77 27
      simulator.py

+ 10 - 2
network.py

@@ -215,8 +215,15 @@ class Network:
     def nextepoch(self):
         """Increment the current epoch, and return it."""
         logging.info("Ending epoch %s", self.epoch)
-        for c in self.epochendingcallbacks:
+        totendingcallbacks = len(self.epochendingcallbacks)
+        lastroundpercent = -1
+        for i, c in enumerate(self.epochendingcallbacks):
             c.epoch_ending(self.epoch)
+            roundpercent = int(100*(i+1)/totendingcallbacks)
+            if roundpercent != lastroundpercent:
+                logging.info("Ending epoch %s %d%% complete",
+                        self.epoch, roundpercent)
+                lastroundpercent = roundpercent
         self.epoch += 1
         logging.info("Starting epoch %s", self.epoch)
         totcallbacks = len(self.epochcallbacks)
@@ -225,7 +232,8 @@ class Network:
             c.newepoch(self.epoch)
             roundpercent = int(100*(i+1)/totcallbacks)
             if roundpercent != lastroundpercent:
-                logging.info("%d%% complete", roundpercent)
+                logging.info("Starting epoch %s %d%% complete",
+                        self.epoch, roundpercent)
                 lastroundpercent = roundpercent
         logging.info("Epoch %s started", self.epoch)
         return self.epoch

+ 77 - 27
simulator.py

@@ -28,6 +28,33 @@ class Simulator:
         # Mean number of circuits created per client per epoch
         self.gamma = 8.9
 
+        # Churn is controlled by three parameters:
+        # newmean: the mean number of new arrivals per epoch
+        # newstddev: the stddev number of new arrivals per epoch
+        # oldprob: the probability any given existing one leaves per epoch
+
+        # If target is the desired steady state number, then it should
+        # be the case that target * oldprob = newmean.  That way, if the
+        # current number is below target, on average you add more than
+        # you remove, and if the current number is above target, on
+        # average you add fewer than you remove.
+
+        # For relays, looking at all the consensuses for Nov and Dec
+        # 2019, newmean is about 1.0% of the network size, and newstddev
+        # is about 0.3% of the network size.
+        self.relay_newmean = 0.010 * self.relaytarget
+        self.relay_newstddev = 0.003 * self.relaytarget
+        self.relay_oldprob = 0.010
+
+        # For clients, looking at how many clients request a consensus
+        # with an if-modified-since date more than 3 hours old (and so
+        # we treat them as "new") over several days in late Dec 2019,
+        # newmean is about 16% of all clients, and newstddev is about 4%
+        # of all clients.
+        self.client_newmean = 0.16 * self.clienttarget
+        self.client_newstddev = 0.04 * self.clienttarget
+        self.client_oldprob = 0.16
+
         # Start some dirauths
         self.dirauthaddrs = []
         self.dirauths = []
@@ -176,36 +203,31 @@ class Simulator:
 
         # Churn relays
 
-        # Churn is controlled by three parameters:
-        # newmean: the mean number of new arrivals per epoch
-        # newstddev: the stddev number of new arrivals per epoch
-        # oldprob: the probability any given existing one leaves per epoch
-
-        # If target is the desired steady state number, then it should
-        # be the case that target * oldprob = newmean.  That way, if the
-        # current number is below target, on average you add more than
-        # you remove, and if the current number is above target, on
-        # average you add fewer than you remove.
-
-        # For relays, looking at all the consensuses for Nov and Dec
-        # 2019, newmean is about 1.0% of the network size, and newstddev
-        # is about 0.3% of the network size.
-        relay_newmean = 0.010 * self.relaytarget
-        relay_newstddev = 0.003 * self.relaytarget
-        relay_oldprob = 0.010
-
         # Stop some of the (non-fallback) relays
-        relays_terminating = []
-        for r in self.relays:
-            if not r.is_fallbackrelay and random.random() < relay_oldprob:
-                relays_terminating.append(r)
-
-        for r in relays_terminating:
-            r.terminate()
-            self.relays.remove(r)
+        relays_remaining = []
+        numrelays = len(self.relays)
+        numrelaysterminated = 0
+        lastpercent = 0
+        logging.info("Terminating some relays")
+        for i, r in enumerate(self.relays):
+            percent = int(100*(i+1)/numrelays)
+            if not r.is_fallbackrelay and \
+                    random.random() < self.relay_oldprob:
+                r.terminate()
+                numrelaysterminated += 1
+            else:
+                # Keep this relay
+                relays_remaining.append(r)
+            if percent != lastpercent:
+                lastpercent = percent
+                logging.info("%d%% relays considered, %d terminated",
+                        percent, numrelaysterminated)
+        self.relays = relays_remaining
 
         # Start some new relays
-        relays_new = int(random.normalvariate(relay_newmean, relay_newstddev))
+        relays_new = int(random.normalvariate(self.relay_newmean,
+                self.relay_newstddev))
+        logging.info("Starting %d new relays", relays_new)
         if relays_new > 0:
             for i in range(relays_new):
                 x = random.randint(1,2500)
@@ -214,6 +236,34 @@ class Simulator:
 
         # TODO: churn clients
 
+        # Stop some of the clients
+        clients_remaining = []
+        numclients = len(self.clients)
+        numclientsterminated = 0
+        lastpercent = 0
+        logging.info("Terminating some clients")
+        for i, c in enumerate(self.clients):
+            percent = int(100*(i+1)/numclients)
+            if random.random() < self.client_oldprob:
+                c.terminate()
+                numclientsterminated += 1
+            else:
+                # Keep this client
+                clients_remaining.append(c)
+            if percent != lastpercent:
+                lastpercent = percent
+                logging.info("%d%% clients considered, %d terminated",
+                        percent, numclientsterminated)
+        self.clients = clients_remaining
+
+        # Start some new clients
+        clients_new = int(random.normalvariate(self.client_newmean,
+                self.client_newstddev))
+        logging.info("Starting %d new clients", clients_new)
+        if clients_new > 0:
+            for i in range(clients_new):
+                self.clients.append(client.Client(self.dirauthaddrs))
+
         # Tick the epoch
         network.thenetwork.nextepoch()