func main() { var finalTick, simTicks int // Run the simulation for 24 hours (a tick represents a millisecond) simTicks = 86400 * 1000 fmt.Printf("arrival_interval,utilization,avg_queue\n") for ai := 900; ai < 3000; ai += 50 { sys := &BlogSystem{ArrivalInterval: float64(ai)} finalTick = qsim.RunSimulation(sys, simTicks) fmt.Printf("%d,%0.3f,%0.3f\n", ai, 1.0-float64(sys.IdleTime)/float64(finalTick), float64(sys.QueueSum)/float64(sys.QueueCount)) } }
// Simulates a blood bank. // // – Any blood unit older than 35 days is thrown in the trash. // – There is only one queue, representing the bank itself. // - There are two processors. One represents the trash, and the other // represents actual use in transfusion. // – Each tick is a minute. // // Arguments, in order: // // - Daily Maximum Draw Rate (in units/day, as an int) // - Maximum Bank Occupancy (in units, as an int) // - Daily Mean Transfusion Rate (in units/day, as a float) // - (optional) The word "test", indicating that only 1 sim should be run. // // We output a CSV row with the following values, in order: // // - Total number of ticks ("minutes") for which simulations collected data // - Number of simulations // - Number of units used in transfusions // - Number of units thrown out // - Number of transfusions aborted due to lack of blood // - 90th percentile age of units used in transfusions // - A value for each member of `thresholds` (see below) indicating the number of units // used in transfusions over that age in days func SimBloodBank() { var simTicks, nSims, simsPerCpu, statsStart int var maxDrawRate, maxOccupancy int var maxDrawRate64, maxOccupancy64 int64 var meanTransfusionRate float64 type simResult struct { Done bool NumTossed, NumUsed, NumAborted int UnitAges []int AgeCounts []int } var nTossed, nUsed, nAborted int var unitAges, ageCounts, thresholds []int var ch chan simResult var cpu, nCpu, routinesDone int var err error if len(os.Args) > 4 && os.Args[4] == "test" { nCpu = 1 nSims = 1 simTicks = 2 * 365 * 1440 } else { nCpu = 16 nSims = 64 simTicks = 40 * 365 * 1440 } simsPerCpu = nSims / nCpu // Don't start collecting stats until a year goes by statsStart = 365 * 1440 thresholds = []int{5 * 1440, 10 * 1440, 15 * 1440, 20 * 1440, 25 * 1440, 30 * 1440} unitAges = make([]int, 0) ageCounts = make([]int, len(thresholds)) maxDrawRate64, err = strconv.ParseInt(os.Args[1], 10, 0) if err != nil { panic("Failed to parse mean draw rate") } maxDrawRate = int(maxDrawRate64) maxOccupancy64, err = strconv.ParseInt(os.Args[2], 10, 0) if err != nil { panic("Failed to parse maximum occupancy") } maxOccupancy = int(maxOccupancy64) meanTransfusionRate, err = strconv.ParseFloat(os.Args[3], 0) if err != nil { panic("Failed to parse mean transfusion rate") } ch = make(chan simResult) for cpu = 0; cpu < nCpu; cpu++ { go func(cpu int) { var i int for i = cpu*simsPerCpu + 1; i <= (cpu+1)*simsPerCpu; i++ { var rslt simResult rslt = simResult{ AgeCounts: make([]int, len(thresholds)), } var j int for j = 0; j < simsPerCpu; j++ { sys := &BloodBankSystem{ Thresholds: thresholds, StatsStart: statsStart, MaxDrawRate: maxDrawRate, MaxOccupancy: maxOccupancy, MeanTransfusionRate: meanTransfusionRate, } qsim.RunSimulation(sys, simTicks) rslt.NumTossed += sys.NumTossed rslt.NumUsed += sys.NumUsed rslt.NumAborted += sys.NumAborted rslt.UnitAges = append(rslt.UnitAges, sys.UnitAges...) var k int for k, _ = range rslt.AgeCounts { rslt.AgeCounts[k] = sys.AgeCounts[k] } } ch <- rslt } ch <- simResult{Done: true} }(cpu) } for routinesDone < nCpu { var rslt simResult rslt = <-ch if rslt.Done { routinesDone++ continue } nTossed += rslt.NumTossed nUsed += rslt.NumUsed nAborted += rslt.NumAborted unitAges = append(unitAges, rslt.UnitAges...) for i, _ := range thresholds { ageCounts[i] += rslt.AgeCounts[i] } } sort.Ints(unitAges) ind := int(9 * len(unitAges) / 10) p90UnitAge := unitAges[ind] fmt.Printf("%d,%d,%d,%d,%d,%d", (simTicks-statsStart)*nSims, nSims, nUsed, nTossed, nAborted, p90UnitAge, ) for i, _ := range thresholds { fmt.Printf(",%d", ageCounts[i]) } fmt.Printf("\n") }
// Simulates a line of porta-potties at a big concert. // // – People arrive very frequently, but if the queues are too long they leave. // – There are 15 porta-potties, each with its own queue. Once a person enters // a queue, they stay in it until that porta-potty is vacant. // – The time taken to use a porta-potty is normally distributed with a // different mean for men and women. // – Most people just pick a random queue to join (as long as it's no longer // than the shortest queue), but some people use the strategy of getting // into the queue with the highestman:woman ratio (again, as long as it's no // longer than the shortest queue), on the theory that this will get them to // the front of the queue faster. // – Each tick is a millisecond (we use very small ticks to minimize the // rounding error inherent in picking integer times from a continuous // distribution. func SimPortaPotty() { var simTicks, simsPerProb int var probStep float64 type simResult struct { Done bool PStrategy float64 SumStrategizerWaits, SumNonStrategizerWaits int NumStrategizers, NumNonStrategizers int } var ch chan simResult var cpu, nCpu, nProbs, probsPerCpu, routinesDone int fmt.Println("pStrategy,avgStratWait,avgNonStratWait,avgWait") nCpu = 5 nProbs = 100 probStep = .01 probsPerCpu = nProbs / nCpu // Run each simulation for 14 days simTicks = 14 * 86400 * 1000 simsPerProb = 40 ch = make(chan simResult) for cpu = 0; cpu < nCpu; cpu++ { go func(cpu int) { var i int for i = cpu*probsPerCpu + 1; i <= (cpu+1)*probsPerCpu; i++ { var pStrategy float64 var rslt simResult pStrategy = probStep * float64(i) rslt = simResult{ Done: false, PStrategy: pStrategy, } var j int for j = 0; j < simsPerProb; j++ { sys := &PortaPottySystem{ PStrategy: pStrategy, StatsStart: 200000000, } qsim.RunSimulation(sys, simTicks) rslt.SumStrategizerWaits += sys.SumStrategizerWaits rslt.SumNonStrategizerWaits += sys.SumNonStrategizerWaits rslt.NumStrategizers += sys.NumStrategizers rslt.NumNonStrategizers += sys.NumNonStrategizers } ch <- rslt } ch <- simResult{Done: true} }(cpu) } for routinesDone < nCpu { var rslt simResult rslt = <-ch if rslt.Done { routinesDone++ continue } avgStrategizerWait := float64(rslt.SumStrategizerWaits) / float64(rslt.NumStrategizers) avgNonStrategizerWait := float64(rslt.SumNonStrategizerWaits) / float64(rslt.NumNonStrategizers) avgWait := float64(rslt.SumStrategizerWaits+rslt.SumNonStrategizerWaits) / float64(rslt.NumStrategizers+rslt.NumNonStrategizers) fmt.Printf("%0.2f,%0.2f,%0.2f,%02.f\n", rslt.PStrategy, avgStrategizerWait/1000.0, avgNonStrategizerWait/1000.0, avgWait/1000.0) } }