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  }