Created
November 13, 2016 16:19
-
-
Save meson10/61e9dd35616e905cda01fc474940d9b5 to your computer and use it in GitHub Desktop.
Profiling explained
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"os" | |
"runtime" | |
"runtime/pprof" | |
"strconv" | |
"sync" | |
"syscall" | |
"time" | |
) | |
func profileCPU() { | |
f, err := os.Create("cpu.prof") | |
if err != nil { | |
log.Fatal("could not create CPU profile: ", err) | |
} | |
if err := pprof.StartCPUProfile(f); err != nil { | |
fmt.Println("could not start CPU profile: ", err) | |
} | |
defer pprof.StopCPUProfile() | |
} | |
func profileMemory() { | |
f, err := os.Create("mem.prof") | |
if err != nil { | |
log.Fatal("could not create memory profile: ", err) | |
} | |
runtime.GC() // get up-to-date statistics | |
if err := pprof.WriteHeapProfile(f); err != nil { | |
fmt.Println("could not write memory profile: ", err) | |
} | |
f.Close() | |
} | |
func timevalToDuration(tv syscall.Timeval) time.Duration { | |
return time.Duration(tv.Nano()) * time.Nanosecond | |
} | |
func bytesToMebibytesFloat(bts uint64) float64 { | |
return float64(bts) / (1024 * 1024) | |
} | |
type stats struct { | |
numGoroutine int | |
allocBytes uint64 | |
gcdelta uint32 | |
minPause time.Duration | |
maxPause time.Duration | |
} | |
type sample struct { | |
memStats runtime.MemStats | |
numGoroutine int | |
numCPU int | |
} | |
func getSample() *sample { | |
s := sample{ | |
numGoroutine: runtime.NumGoroutine(), | |
numCPU: runtime.NumCPU(), | |
} | |
ru := syscall.Rusage{} | |
if err := syscall.Getrusage(syscall.RUSAGE_SELF, &ru); err != nil { | |
fmt.Println("sample error", err.Error()) | |
return nil | |
} | |
runtime.ReadMemStats(&s.memStats) | |
return &s | |
} | |
func getStats(cur, prev *sample) stats { | |
s := stats{ | |
numGoroutine: cur.numGoroutine, | |
allocBytes: cur.memStats.Alloc, | |
} | |
gcdelta := cur.memStats.NumGC - prev.memStats.NumGC | |
if gcdelta <= 0 { | |
return s | |
} | |
deltaPauseTotalNs := cur.memStats.PauseTotalNs - prev.memStats.PauseTotalNs | |
maxPauseNs := deltaPauseTotalNs / uint64(gcdelta) | |
minPauseNs := deltaPauseTotalNs / uint64(gcdelta) | |
for i := prev.memStats.NumGC + 1; i <= cur.memStats.NumGC; i++ { | |
pause := cur.memStats.PauseNs[(i+255)%256] | |
if pause > maxPauseNs { | |
maxPauseNs = pause | |
} | |
if pause < minPauseNs { | |
minPauseNs = pause | |
} | |
} | |
s.gcdelta = gcdelta | |
s.minPause = time.Duration(minPauseNs) * time.Nanosecond | |
s.maxPause = time.Duration(maxPauseNs) * time.Nanosecond | |
return s | |
} | |
func perf(fn func()) { | |
s1 := getSample() | |
fn() | |
s2 := getSample() | |
fmt.Printf("%+v\n", getStats(s1, s2)) | |
} | |
// AbstractInh is a function to demostrate abstract inheritence | |
func main() { | |
var wg sync.WaitGroup | |
for y := 0; y < 3; y++ { | |
for x := 0; x < 2; x++ { | |
wg.Add(1) | |
go func(num int) { | |
defer wg.Done() | |
time.Sleep(2 * time.Second) | |
fmt.Println("Hello", strconv.Itoa(num)) | |
time.Sleep(time.Duration(num) * time.Second) | |
}(x + y) | |
} | |
} | |
perf(func() { | |
wg.Wait() | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment