From 7a986617de3ef35f23402db1b507c57ca1879cfb Mon Sep 17 00:00:00 2001 From: Aaron Taylor Date: Sat, 15 May 2021 02:50:02 -0700 Subject: [PATCH] Added basic CPU and heap profiling to Chapter 1 "Breeding Numbers" program. --- chapter-1-experiments/ch1-breeding-numbers.go | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/chapter-1-experiments/ch1-breeding-numbers.go b/chapter-1-experiments/ch1-breeding-numbers.go index fd1901f..fbba0ec 100644 --- a/chapter-1-experiments/ch1-breeding-numbers.go +++ b/chapter-1-experiments/ch1-breeding-numbers.go @@ -7,6 +7,9 @@ import ( "flag" "fmt" "log" + "os" + "runtime/pprof" + "strconv" ) // ============================================================================= @@ -209,6 +212,11 @@ func (s *surrealSet) remove(num surrealNumber, u surrealUniverse) { // ============================================================================= func main() { + // Flags to enable various performance profiling options. + cpuProfile := flag.String("cpuprofile", "", "Filename for saving CPU profile output.") + memProfilePrefix := flag.String("memprofileprefix", "", "Filename PREFIX for saving memory profile output.") + suppressOutput := flag.Bool("silent", false, "Suppress printing of numberline at end of simulation. Useful when profiling.") + // Obtain termination conditions from user. totalGenerations := flag.Int("generations", 2, "Number of generations of surreal numbers to breed.") flag.Parse() @@ -217,6 +225,17 @@ func main() { } remainingGenerations := *totalGenerations - 1 + // Setup any CPU performance profiling requested by the user. This will run + // throughout program execution. + if *cpuProfile != "" { + cpuProFile, err := os.Create(*cpuProfile) + if err != nil { + log.Fatal("ERROR: Unable to open CPU profiling output file:", err) + } + pprof.StartCPUProfile(cpuProFile) + defer pprof.StopCPUProfile() + } + // Build a universe to contain all the surreal numbers we breed. // Seed it by hand with the number zero as generation-0. var universe surrealUniverse @@ -228,10 +247,12 @@ func main() { // add them all to the universe. fmt.Printf("Breeding Generation:") for generation := 1; generation <= remainingGenerations; generation++ { + // Give the user some idea of overall progress during long jobs. if generation != 1 { fmt.Printf(",") } fmt.Printf(" %d", generation) + // First generate all possible reduced form symbols per Axiom 1. potentialNumbers := permuteExistingNumbers(generation, universe) // Now prune out any symbols which are NOT valid numbers per Axiom 2. @@ -239,13 +260,27 @@ func main() { // Attempt to add the new numbers to the universe. Any duplicates will // be weeded out in the attempt. addNumbersToUniverse(validNumbers, &universe) + + // Setup any memory profiling requested by the user. This will snapshot + // the heap at the end of every generation. + if *memProfilePrefix != "" { + memProFile, err := os.Create(*memProfilePrefix + "-gen" + strconv.Itoa(generation) + ".mprof") + if err != nil { + log.Fatal("ERROR: Unable to write heap profile to disk:", err) + } + pprof.WriteHeapProfile(memProFile) + memProFile.Close() + } } fmt.Printf(".\n") + // Print the number line with generation on the horizontal axis and // magnitude on the vertical axis. - for i := 0; i < universe.cardinality(); i++ { - printlnNumber(universe.numbers[i]) + if !(*suppressOutput) { + for i := 0; i < universe.cardinality(); i++ { + printlnNumber(universe.numbers[i]) + } } fmt.Println("After", *totalGenerations, "generations, the universe contains", len(universe.numbers), "numbers.") fmt.Println("If output looks poor, ensure tabstop is eight spaces and that output doesn't wrap.") -- 2.20.1