// Save multiplot of histograms as SVG to file name. // Construct a grid of histogram with the columns a test in the testsuite // and a row per background load. func writeStressHistograms(data []suite.StressResult, name, bgname string) { numLoads := len(data) numTests := len(data[0].Detail) maxRT := float64(-1) for i := range data { for _, rt := range data[i].Detail { for _, t := range rt { if float64(t) > maxRT { maxRT = float64(t) } } } } step := maxRT / 4 maxRT, step = beautifulX(maxRT, step) tests := []string{} for t, _ := range data[0].Detail { tests = append(tests, t) } sort.Strings(tests) // A histogram now := time.Now() filename := outputPath + "stresstest_" + now.Format("2006-01-02_15-04-05") + ".svg" file, err := os.Create(filename) if err != nil { errorf("Cannot write to %q: %s", filename, err.Error()) return } thesvg := svg.New(file) width, height := svgLeft+svgWidth*numTests, svgTop+svgHeight*numLoads+20 thesvg.Start(width, height) thesvg.Title("Response Times") thesvg.Rect(0, 0, width, height, "fill: #ffffff") title := fmt.Sprintf("Distribution of response times in ms (suite: %s; bg: %s; %d samples; finished: %s)", name, bgname, len(data[0].Detail[tests[0]]), now.Format("Mon 2. Jan. 2006 15:04:05")) thesvg.Text(20, svgTop/2, title, "", "text-anchor: begin; font-size: 20;") for k, name := range tests { thesvg.Text(20+svgLeft+k*svgWidth, svgTop-2, name, "", "text-anchor: begin; font-size: 14;") } white := color.RGBA{255, 255, 255, 255} for i := range data { thesvg.Text(svgLeft-10, svgTop+svgHeight*i+0.5*svgHeight, fmt.Sprintf("%d || Req", data[i].Load+1), "", "text-anchor: end; font-size: 14;") for j, t := range tests { showTime, hd := false, 0 if i == len(data)-1 { showTime = true hd += 20 } thesvg.Gtransform(fmt.Sprintf("translate(%d %d)", svgLeft+svgWidth*j, svgTop+svgHeight*i)) svggraphics := svgg.New(thesvg, svgWidth, svgHeight+hd, "Arial", 12, white) plotHistogram(svggraphics, data[i].Detail[t], maxRT, step, showTime) thesvg.Gend() } } thesvg.End() file.Close() warnf("Wrote stresstest histogram to file %s\n", filename) }
func InitStatsHUD() { plots := chart.ScatterChart{Title: "", Options: glchart.DarkStyle} start := time.Now() l := float64(start.UnixNano()) r := float64(start.Add(2 * time.Second).UnixNano()) plots.XRange.Fixed(l, r, 1e9) plots.YRange.Fixed(0.1, 100, 10) plots.XRange.TicSetting.Tics, plots.YRange.TicSetting.Tics = 1, 1 plots.XRange.TicSetting.Mirror, plots.YRange.TicSetting.Mirror = 2, 2 plots.XRange.TicSetting.Grid, plots.YRange.TicSetting.Grid = 2, 2 plots.YRange.ShowZero = true //plots.XRange.Log = true //plots.YRange.Log = true plots.Key.Pos, plots.Key.Cols = "obc", 3 plots.XRange.TicSetting.Format = func(f float64) string { t := time.Unix(int64(f)/1e9, int64(f)%1e9) return fmt.Sprintf("%.3v", time.Since(t)) } memhelper.GetMaxRSS() var gpufree float64 gpupoll := gpuinfo.PollGPUMemory() go func() { for gpustatus := range gpupoll { gpufree = float64(memhelper.ByteSize(gpustatus.Free()) * memhelper.MiB) } }() statistics := &Statistics{} statistics.Add(&plots, "GPU Free", "#FF9F00", func() float64 { return gpufree }) statistics.Add(&plots, "SpareRAM()", "#ff0000", func() float64 { return float64(SpareRAM() * 1e6) }) statistics.Add(&plots, "MaxRSS", "#FFE240", func() float64 { return float64(memhelper.GetMaxRSS()) }) statistics.Add(&plots, "Heap Idle", "#33ff33", func() float64 { return float64(memstats.HeapIdle) }) statistics.Add(&plots, "Alloc", "#FF6600", func() float64 { return float64(memstats.Alloc) }) statistics.Add(&plots, "Heap Alloc", "#006699", func() float64 { return float64(memstats.HeapAlloc) }) statistics.Add(&plots, "Sys", "#996699", func() float64 { return float64(memstats.Sys) }) statistics.Add(&plots, "System Free", "#3333ff", func() float64 { return float64(SystemFree()) }) statistics.Add(&plots, "nBlocks x 1e6", "#FFCC00", func() float64 { return float64(nblocks * 1e6) }) statistics.Add(&plots, "nDrawn x 1e6", "#9C8AA5", func() float64 { return float64(blocks_rendered * 1e6) }) go func() { top := 0. i := -1 for { time.Sleep(250 * time.Millisecond) max := statistics.Update() if max > top { top = max } i++ if i%4 != 0 { continue } segment := float64(1e9) if time.Since(start) > 10*time.Second { segment = 5e9 } if time.Since(start) > 1*time.Minute { segment = 30e9 } // Update axis limits nr := float64(time.Now().Add(2 * time.Second).UnixNano()) plots.XRange.Fixed(l, nr, segment) plots.YRange.Fixed(-1e9, top*1.1, 500e6) } }() const pw, ph = 640, 480 scalex, scaley := 0.4, 0.5 chart_gfxcontext := glchart.New(pw, ph, "", 10, color.RGBA{}) StatsHUD = func() { glh.With(glh.Matrix{gl.PROJECTION}, func() { gl.LoadIdentity() gl.Translated(1-scalex, scaley-1, 0) gl.Scaled(scalex, scaley, 1) gl.Ortho(0, pw, ph, 0, -1, 1) gl.Translated(0, -50, 0) glh.With(glh.Attrib{gl.ENABLE_BIT}, func() { gl.Disable(gl.DEPTH_TEST) glh.With(&Timer{Name: "Chart"}, func() { plots.Plot(chart_gfxcontext) }) }) }) } // TODO: figure out why this is broken DumpStatsHUD = func() { s2f, _ := os.Create("statshud-dump.svg") mysvg := svg.New(s2f) mysvg.Start(1600, 800) mysvg.Rect(0, 0, 2000, 800, "fill: #ffffff") sgr := svgg.New(mysvg, 2000, 800, "Arial", 18, color.RGBA{0xff, 0xff, 0xff, 0xff}) sgr.Begin() plots.Plot(sgr) sgr.End() mysvg.End() s2f.Close() log.Print("Saved statshud-dump.svg") } //log.Print("InitStatsHUD()") }