github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/profile/profile.go (about) 1 package profile 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "runtime" 9 "runtime/pprof" 10 "sync" 11 "time" 12 13 "github.com/NebulousLabs/Sia/persist" 14 ) 15 16 // There's a global lock on cpu and memory profiling, because I'm not sure what 17 // happens if multiple threads call each at the same time. This lock might be 18 // unnecessary. 19 var ( 20 cpuActive bool 21 cpuLock sync.Mutex 22 memActive bool 23 memLock sync.Mutex 24 ) 25 26 // startCPUProfile starts cpu profiling. An error will be returned if a cpu 27 // profiler is already running. 28 func StartCPUProfile(profileDir, identifier string) error { 29 // Lock the cpu profile lock so that only one profiler is running at a 30 // time. 31 cpuLock.Lock() 32 if cpuActive { 33 cpuLock.Unlock() 34 return errors.New("cannot start cpu profilier, a profiler is already running") 35 } 36 cpuActive = true 37 cpuLock.Unlock() 38 39 // Start profiling into the profile dir, using the identifer. The timestamp 40 // of the start time of the profiling will be included in the filename. 41 cpuProfileFile, err := os.Create(filepath.Join(profileDir, "cpu-profile-"+identifier+"-"+time.Now().Format(time.RFC3339Nano)+".prof")) 42 if err != nil { 43 return err 44 } 45 pprof.StartCPUProfile(cpuProfileFile) 46 return nil 47 } 48 49 // stopCPUProfile stops cpu profiling. 50 func StopCPUProfile() { 51 cpuLock.Lock() 52 if cpuActive { 53 pprof.StopCPUProfile() 54 cpuActive = false 55 } 56 cpuLock.Unlock() 57 } 58 59 // saveMemProfile saves the current memory structure of the program. An error 60 // will be returned if memory profiling is already in progress. Unlike for cpu 61 // profiling, there is no 'stopMemProfile' call - everything happens at once. 62 func SaveMemProfile(profileDir, identifier string) error { 63 memLock.Lock() 64 if memActive { 65 memLock.Unlock() 66 return errors.New("cannot start memory profiler, a memory profiler is already running") 67 } 68 memActive = true 69 memLock.Unlock() 70 71 // Save the memory profile. 72 memFile, err := os.Create(filepath.Join(profileDir, "mem-profile-"+identifier+"-"+time.Now().Format(time.RFC3339Nano)+".prof")) 73 if err != nil { 74 return err 75 } 76 pprof.WriteHeapProfile(memFile) 77 78 memLock.Lock() 79 memActive = false 80 memLock.Unlock() 81 return nil 82 } 83 84 // StartContinuousProfiling will continuously print statistics about the cpu 85 // usage, memory usage, and runtime stats of the program. 86 func StartContinuousProfile(profileDir string) { 87 // Create the folder for all of the profiling results. 88 err := os.MkdirAll(profileDir, 0700) 89 if err != nil { 90 fmt.Println(err) 91 return 92 } 93 94 // Continuously log statistics about the running Sia application. 95 go func() { 96 // Create the logger. 97 log, err := persist.NewFileLogger(filepath.Join(profileDir, "continuousProfiling.log")) 98 if err != nil { 99 fmt.Println("Profile logging failed:", err) 100 return 101 } 102 103 // Collect statistics in an infinite loop. 104 sleepTime := time.Second * 20 105 for { 106 // Sleep for an exponential amount of time each iteration, this 107 // keeps the size of the log small while still providing lots of 108 // information. 109 time.Sleep(sleepTime) 110 sleepTime = time.Duration(1.5 * float64(sleepTime)) 111 112 var m runtime.MemStats 113 runtime.ReadMemStats(&m) 114 log.Printf("\n\tGoroutines: %v\n\tAlloc: %v\n\tTotalAlloc: %v\n\tHeapAlloc: %v\n\tHeapSys: %v\n", runtime.NumGoroutine(), m.Alloc, m.TotalAlloc, m.HeapAlloc, m.HeapSys) 115 } 116 }() 117 }