mirror of
https://github.com/status-im/simulation.git
synced 2025-02-23 04:18:09 +00:00
Renamed folders
This commit is contained in:
parent
7e020a7f03
commit
d28400a24f
@ -1,3 +1,3 @@
|
||||
simulator
|
||||
propagation_simulator
|
||||
network.json
|
||||
propagation.json
|
196
stats/histogram.go
Normal file
196
stats/histogram.go
Normal file
@ -0,0 +1,196 @@
|
||||
package stats
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Histogram implements simple histogram for node counters.
|
||||
type Histogram struct {
|
||||
ranges []int
|
||||
counts []int
|
||||
|
||||
totalCount int
|
||||
|
||||
TotalDataPoint int
|
||||
MinDataPoint int
|
||||
MaxDataPoint int
|
||||
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
// NewHistogram creates a new, ready to use Histogram. The numBins
|
||||
// must be >= 2. The binFirst is the width of the first bin. The
|
||||
// binGrowthFactor must be > 1.0 or 0.0.
|
||||
//
|
||||
// A special case of binGrowthFactor of 0.0 means the the allocated
|
||||
// bins will have constant, non-growing size or "width".
|
||||
func NewHistogram(
|
||||
numBins int,
|
||||
binFirst int,
|
||||
binGrowthFactor float64) *Histogram {
|
||||
gh := &Histogram{
|
||||
ranges: make([]int, numBins),
|
||||
counts: make([]int, numBins),
|
||||
totalCount: 0,
|
||||
MinDataPoint: math.MaxInt64,
|
||||
MaxDataPoint: 0,
|
||||
}
|
||||
|
||||
gh.ranges[0] = 0
|
||||
gh.ranges[1] = binFirst
|
||||
|
||||
for i := 2; i < len(gh.ranges); i++ {
|
||||
if binGrowthFactor == 0.0 {
|
||||
gh.ranges[i] = gh.ranges[i-1] + binFirst
|
||||
} else {
|
||||
gh.ranges[i] =
|
||||
int(math.Ceil(binGrowthFactor * float64(gh.ranges[i-1])))
|
||||
}
|
||||
}
|
||||
|
||||
return gh
|
||||
}
|
||||
|
||||
// Add increases the count in the bin for the given dataPoint.
|
||||
func (gh *Histogram) Add(dataPoint int, count int) {
|
||||
gh.m.Lock()
|
||||
|
||||
idx := search(gh.ranges, dataPoint)
|
||||
if idx >= 0 {
|
||||
gh.counts[idx] += count
|
||||
gh.totalCount += count
|
||||
|
||||
gh.TotalDataPoint += dataPoint
|
||||
if gh.MinDataPoint > dataPoint {
|
||||
gh.MinDataPoint = dataPoint
|
||||
}
|
||||
if gh.MaxDataPoint < dataPoint {
|
||||
gh.MaxDataPoint = dataPoint
|
||||
}
|
||||
}
|
||||
|
||||
gh.m.Unlock()
|
||||
}
|
||||
|
||||
// Finds the last arr index where the arr entry <= dataPoint.
|
||||
func search(arr []int, dataPoint int) int {
|
||||
i, j := 0, len(arr)
|
||||
|
||||
for i < j {
|
||||
h := i + (j-i)/2 // Avoids h overflow, where i <= h < j.
|
||||
if dataPoint >= arr[h] {
|
||||
i = h + 1
|
||||
} else {
|
||||
j = h
|
||||
}
|
||||
}
|
||||
|
||||
return i - 1
|
||||
}
|
||||
|
||||
// AddAll adds all the counts from the src histogram into this
|
||||
// histogram. The src and this histogram must either have the same
|
||||
// exact creation parameters.
|
||||
func (gh *Histogram) AddAll(src *Histogram) {
|
||||
src.m.Lock()
|
||||
gh.m.Lock()
|
||||
|
||||
for i := 0; i < len(src.counts); i++ {
|
||||
gh.counts[i] += src.counts[i]
|
||||
}
|
||||
gh.totalCount += src.totalCount
|
||||
|
||||
gh.TotalDataPoint += src.TotalDataPoint
|
||||
if gh.MinDataPoint > src.MinDataPoint {
|
||||
gh.MinDataPoint = src.MinDataPoint
|
||||
}
|
||||
if gh.MaxDataPoint < src.MaxDataPoint {
|
||||
gh.MaxDataPoint = src.MaxDataPoint
|
||||
}
|
||||
|
||||
gh.m.Unlock()
|
||||
src.m.Unlock()
|
||||
}
|
||||
|
||||
// Graph emits an ascii graph to the optional out buffer, allocating a
|
||||
// out buffer if none was supplied. Returns the out buffer. Each
|
||||
// line emitted may have an optional prefix.
|
||||
//
|
||||
// For example:
|
||||
// 0+ 10=2 10.00% ********
|
||||
// 10+ 10=1 10.00% ****
|
||||
// 20+ 10=3 10.00% ************
|
||||
func (gh *Histogram) EmitGraph(prefix []byte,
|
||||
out *bytes.Buffer) *bytes.Buffer {
|
||||
gh.m.Lock()
|
||||
|
||||
ranges := gh.ranges
|
||||
rangesN := len(ranges)
|
||||
counts := gh.counts
|
||||
countsN := len(counts)
|
||||
|
||||
if out == nil {
|
||||
out = bytes.NewBuffer(make([]byte, 0, 80*countsN))
|
||||
}
|
||||
|
||||
var maxCount int
|
||||
for _, c := range counts {
|
||||
if maxCount < c {
|
||||
maxCount = c
|
||||
}
|
||||
}
|
||||
maxCountF := float64(maxCount)
|
||||
totCountF := float64(gh.totalCount)
|
||||
|
||||
widthRange := len(strconv.Itoa(int(ranges[rangesN-1])))
|
||||
widthWidth := len(strconv.Itoa(int(ranges[rangesN-1] - ranges[rangesN-2])))
|
||||
widthCount := len(strconv.Itoa(int(maxCount)))
|
||||
|
||||
// Each line looks like: "[prefix]START+WIDTH=COUNT PCT% BAR\n"
|
||||
f := fmt.Sprintf("%%%dd+%%%dd=%%%dd%% 7.2f%%%%",
|
||||
widthRange, widthWidth, widthCount)
|
||||
|
||||
var runCount int // Running total while emitting lines.
|
||||
|
||||
barLen := float64(len(bar))
|
||||
|
||||
for i, c := range counts {
|
||||
if prefix != nil {
|
||||
out.Write(prefix)
|
||||
}
|
||||
|
||||
var width int
|
||||
if i < countsN-1 {
|
||||
width = int(ranges[i+1] - ranges[i])
|
||||
}
|
||||
|
||||
runCount += c
|
||||
fmt.Fprintf(out, f, ranges[i], width, c,
|
||||
100.0*(float64(runCount)/totCountF))
|
||||
|
||||
if c > 0 {
|
||||
out.Write([]byte(" "))
|
||||
barWant := int(math.Floor(barLen * (float64(c) / maxCountF)))
|
||||
out.Write(bar[0:barWant])
|
||||
}
|
||||
|
||||
out.Write([]byte("\n"))
|
||||
}
|
||||
|
||||
gh.m.Unlock()
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
var bar = []byte("******************************")
|
||||
|
||||
// CallSync invokes the callback func while the histogram is locked.
|
||||
func (gh *Histogram) CallSync(f func()) {
|
||||
gh.m.Lock()
|
||||
f()
|
||||
gh.m.Unlock()
|
||||
}
|
@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"v.io/x/ref/lib/stats/histogram"
|
||||
|
||||
"github.com/divan/graph-experiments/graph"
|
||||
"github.com/status-im/simulator/simulation"
|
||||
)
|
||||
@ -13,6 +15,7 @@ type Stats struct {
|
||||
NodeHits map[string]int
|
||||
NodeCoverage Coverage
|
||||
LinkCoverage Coverage
|
||||
Hist *histogram.Histogram
|
||||
}
|
||||
|
||||
// PrintVerbose prints detailed terminal-friendly stats to
|
||||
@ -21,18 +24,12 @@ func (s *Stats) PrintVerbose() {
|
||||
fmt.Println("Stats:")
|
||||
fmt.Println("Nodes coverage:", s.NodeCoverage)
|
||||
fmt.Println("Links coverage:", s.LinkCoverage)
|
||||
for k, v := range s.NodeHits {
|
||||
fmt.Printf("%s: ", k)
|
||||
for i := 0; i < v; i++ {
|
||||
fmt.Printf(".")
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
fmt.Println("Node hits:", s.Hist.Value())
|
||||
}
|
||||
|
||||
// Analyze analyzes given propagation log and returns filled Stats object.
|
||||
func Analyze(g *graph.Graph, plog *simulation.Log) *Stats {
|
||||
nodeHits := analyzeNodeHits(g, plog)
|
||||
nodeHits, hist := analyzeNodeHits(g, plog)
|
||||
nodeCoverage := analyzeNodeCoverage(g, nodeHits)
|
||||
linkCoverage := analyzeLinkCoverage(g, plog)
|
||||
|
||||
@ -40,10 +37,11 @@ func Analyze(g *graph.Graph, plog *simulation.Log) *Stats {
|
||||
NodeHits: nodeHits,
|
||||
NodeCoverage: nodeCoverage,
|
||||
LinkCoverage: linkCoverage,
|
||||
Hist: hist,
|
||||
}
|
||||
}
|
||||
|
||||
func analyzeNodeHits(g *graph.Graph, plog *simulation.Log) map[string]int {
|
||||
func analyzeNodeHits(g *graph.Graph, plog *simulation.Log) (map[string]int, *histogram.Histogram) {
|
||||
nodeHits := make(map[string]int)
|
||||
|
||||
for _, nodes := range plog.Nodes {
|
||||
@ -56,7 +54,12 @@ func analyzeNodeHits(g *graph.Graph, plog *simulation.Log) map[string]int {
|
||||
}
|
||||
}
|
||||
|
||||
return nodeHits
|
||||
hist := NewHistogram(1, 1, 1)
|
||||
for _, v := range nodeHits {
|
||||
hist.Add(v)
|
||||
}
|
||||
|
||||
return nodeHits, hist
|
||||
}
|
||||
|
||||
func analyzeNodeCoverage(g *graph.Graph, nodeHits map[string]int) Coverage {
|
||||
|
Loading…
x
Reference in New Issue
Block a user