go.dedis.ch/onet/v3@v3.2.11-0.20210930124529-e36530bca7ef/simul/platform/runsimul.go (about)

     1  package platform
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/BurntSushi/toml"
     8  	"go.dedis.ch/onet/v3"
     9  	"go.dedis.ch/onet/v3/log"
    10  	"go.dedis.ch/onet/v3/network"
    11  	"go.dedis.ch/onet/v3/simul/manage"
    12  	"go.dedis.ch/onet/v3/simul/monitor"
    13  	"golang.org/x/xerrors"
    14  )
    15  
    16  type simulInit struct{}
    17  type simulInitDone struct{}
    18  
    19  // Simulate starts the server and will setup the protocol.
    20  func Simulate(suite, serverAddress, simul, monitorAddress string) error {
    21  	scs, err := onet.LoadSimulationConfig(suite, ".", serverAddress)
    22  	if err != nil {
    23  		// We probably are not needed
    24  		log.Lvl2(err, serverAddress)
    25  		return nil
    26  	}
    27  	if monitorAddress != "" {
    28  		if err := monitor.ConnectSink(monitorAddress); err != nil {
    29  			log.Error("Couldn't connect monitor to sink:", err)
    30  			return xerrors.New("couldn't connect monitor to sink: " + err.Error())
    31  		}
    32  	}
    33  	sims := make([]onet.Simulation, len(scs))
    34  	simulInitID := network.RegisterMessage(simulInit{})
    35  	simulInitDoneID := network.RegisterMessage(simulInitDone{})
    36  	var rootSC *onet.SimulationConfig
    37  	var rootSim onet.Simulation
    38  	// having a waitgroup so the binary stops when all servers are closed
    39  	var wgServer, wgSimulInit sync.WaitGroup
    40  	var ready = make(chan bool)
    41  	measureNodeBW := true
    42  	measuresLock := sync.Mutex{}
    43  	measures := make([]*monitor.CounterIOMeasure, len(scs))
    44  	if len(scs) > 0 {
    45  		cfg := &conf{}
    46  		_, err := toml.Decode(scs[0].Config, cfg)
    47  		if err != nil {
    48  			return xerrors.New("error while decoding config: " + err.Error())
    49  		}
    50  		measureNodeBW = cfg.IndividualStats == ""
    51  	}
    52  	for i, sc := range scs {
    53  		// Starting all servers for that server
    54  		server := sc.Server
    55  
    56  		if measureNodeBW {
    57  			hostIndex, _ := sc.Roster.Search(sc.Server.ServerIdentity.ID)
    58  			measures[i] = monitor.NewCounterIOMeasureWithHost("bandwidth", sc.Server, hostIndex)
    59  		}
    60  
    61  		log.Lvl3(serverAddress, "Starting server", server.ServerIdentity.Address)
    62  		// Launch a server and notifies when it's done
    63  		wgServer.Add(1)
    64  		measure := measures[i]
    65  		go func(c *onet.Server) {
    66  			ready <- true
    67  			defer wgServer.Done()
    68  			c.Start()
    69  			if measure != nil {
    70  				measuresLock.Lock()
    71  				measure.Record()
    72  				measuresLock.Unlock()
    73  			}
    74  			log.Lvl3(serverAddress, "Simulation closed server", c.ServerIdentity)
    75  		}(server)
    76  		// wait to be sure the goroutine started
    77  		<-ready
    78  
    79  		sim, err := onet.NewSimulation(simul, sc.Config)
    80  		if err != nil {
    81  			return xerrors.New("couldn't create new simulation: " + err.Error())
    82  		}
    83  		sims[i] = sim
    84  		// Need to store sc in a tmp-variable so it's correctly passed
    85  		// to the Register-functions.
    86  		scTmp := sc
    87  		server.RegisterProcessorFunc(simulInitID, func(env *network.Envelope) error {
    88  			// The node setup must be done in a goroutine to prevent the connection
    89  			// from the root to this node to stale forever.
    90  			go func() {
    91  				defer func() {
    92  					if measure != nil {
    93  						measuresLock.Lock()
    94  						// Remove the initialization of the simulation from this statistic
    95  						measure.Reset()
    96  						measuresLock.Unlock()
    97  					}
    98  				}()
    99  
   100  				err = sim.Node(scTmp)
   101  				log.ErrFatal(err)
   102  				_, err := scTmp.Server.Send(env.ServerIdentity, &simulInitDone{})
   103  				log.ErrFatal(err)
   104  			}()
   105  			return nil
   106  		})
   107  		server.RegisterProcessorFunc(simulInitDoneID, func(env *network.Envelope) error {
   108  			wgSimulInit.Done()
   109  			if measure != nil {
   110  				measuresLock.Lock()
   111  				// Reset the root bandwidth after the children sent the ACK.
   112  				measure.Reset()
   113  				measuresLock.Unlock()
   114  			}
   115  			return nil
   116  		})
   117  		if server.ServerIdentity.ID.Equal(sc.Tree.Root.ServerIdentity.ID) {
   118  			log.Lvl2(serverAddress, "is root-node, will start protocol")
   119  			rootSim = sim
   120  			rootSC = sc
   121  		}
   122  	}
   123  
   124  	var simError error
   125  	if rootSim != nil {
   126  		// If this cothority has the root-server, it will start the simulation
   127  		log.Lvl2("Starting protocol", simul, "on server", rootSC.Server.ServerIdentity.Address)
   128  		log.Lvl5("Tree is", rootSC.Tree.Dump())
   129  
   130  		// First count the number of available children
   131  		childrenWait := monitor.NewTimeMeasure("ChildrenWait")
   132  		wait := true
   133  		// The timeout starts with 1 second, which is the time of response between
   134  		// each level of the tree.
   135  		timeout := 1 * time.Second
   136  		for wait {
   137  			p, err := rootSC.Overlay.CreateProtocol("Count", rootSC.Tree, onet.NilServiceID)
   138  			if err != nil {
   139  				return xerrors.New("couldn't create protocol: " + err.Error())
   140  			}
   141  			proto := p.(*manage.ProtocolCount)
   142  			proto.SetTimeout(timeout)
   143  			proto.Start()
   144  			log.Lvl1("Started counting children with timeout of", timeout)
   145  			select {
   146  			case count := <-proto.Count:
   147  				if count == rootSC.Tree.Size() {
   148  					log.Lvl1("Found all", count, "children")
   149  					wait = false
   150  				} else {
   151  					log.Lvl1("Found only", count, "children, counting again")
   152  				}
   153  			}
   154  			// Double the timeout and try again if not successful.
   155  			timeout *= 2
   156  		}
   157  		childrenWait.Record()
   158  		log.Lvl2("Broadcasting start")
   159  		syncWait := monitor.NewTimeMeasure("SimulSyncWait")
   160  		wgSimulInit.Add(len(rootSC.Tree.Roster.List))
   161  		for _, conode := range rootSC.Tree.Roster.List {
   162  			go func(si *network.ServerIdentity) {
   163  				_, err := rootSC.Server.Send(si, &simulInit{})
   164  				log.ErrFatal(err, "Couldn't send to conode:")
   165  			}(conode)
   166  		}
   167  		wgSimulInit.Wait()
   168  		syncWait.Record()
   169  		log.Lvl1("Starting new node", simul)
   170  
   171  		measureNet := monitor.NewCounterIOMeasure("bandwidth_root", rootSC.Server)
   172  		simError = rootSim.Run(rootSC)
   173  		measureNet.Record()
   174  
   175  		// Test if all ServerIdentities are used in the tree, else we'll run into
   176  		// troubles with CloseAll
   177  		if !rootSC.Tree.UsesList() {
   178  			log.Error("The tree doesn't use all ServerIdentities from the list!\n" +
   179  				"This means that the CloseAll will fail and the experiment never ends!")
   180  		}
   181  
   182  		// Recreate a tree out of the original roster, to be sure all nodes are included and
   183  		// that the tree is easy to close.
   184  		closeTree := rootSC.Roster.GenerateBinaryTree()
   185  		pi, err := rootSC.Overlay.CreateProtocol("CloseAll", closeTree, onet.NilServiceID)
   186  		if err != nil {
   187  			return xerrors.New("couldn't create closeAll protocol: " + err.Error())
   188  		}
   189  		pi.Start()
   190  	}
   191  
   192  	log.Lvl3(serverAddress, scs[0].Server.ServerIdentity, "is waiting for all servers to close")
   193  	wgServer.Wait()
   194  	log.Lvl2(serverAddress, "has all servers closed")
   195  	if monitorAddress != "" {
   196  		monitor.EndAndCleanup()
   197  	}
   198  
   199  	// Give a chance to the simulation to stop the servers and clean up but returns the simulation error anyway.
   200  	if simError != nil {
   201  		return xerrors.New("error from simulation run: " + simError.Error())
   202  	}
   203  	return nil
   204  }
   205  
   206  type conf struct {
   207  	IndividualStats string
   208  }