mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-22 14:56:56 +00:00
Faster report merging through mutating objects
When we know we have the only reference to a Report or Node object we can avoid copying the data to change it. Add "Unsafe" variants of various Merge operations which mutate the receiver, and a new Merger which takes advantage of them.
This commit is contained in:
@@ -72,6 +72,15 @@ func BenchmarkReportMerge(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReportFastMerge(b *testing.B) {
|
||||
reports := upgradeReports(readReportFiles(b, *benchReportPath))
|
||||
merger := NewFastMerger()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
merger.Merge(reports)
|
||||
}
|
||||
}
|
||||
|
||||
func getReport(b *testing.B) report.Report {
|
||||
r := fixture.Report
|
||||
if *benchReportPath != "" {
|
||||
|
||||
@@ -60,3 +60,21 @@ func (smartMerger) Merge(reports []report.Report) report.Report {
|
||||
}
|
||||
return <-c
|
||||
}
|
||||
|
||||
type fastMerger struct{}
|
||||
|
||||
// NewFastMerger makes a Merger which merges together reports, mutating the one we are building up
|
||||
func NewFastMerger() Merger {
|
||||
return fastMerger{}
|
||||
}
|
||||
|
||||
func (fastMerger) Merge(reports []report.Report) report.Report {
|
||||
rpt := report.MakeReport()
|
||||
id := murmur3.New64()
|
||||
for _, r := range reports {
|
||||
rpt.UnsafeMerge(r)
|
||||
id.Write([]byte(r.ID))
|
||||
}
|
||||
rpt.ID = fmt.Sprintf("%x", id.Sum64())
|
||||
return rpt
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ func BenchmarkDumbMerger(b *testing.B) {
|
||||
benchmarkMerger(b, app.MakeDumbMerger())
|
||||
}
|
||||
|
||||
func BenchmarkFastMerger(b *testing.B) {
|
||||
benchmarkMerger(b, app.NewFastMerger())
|
||||
}
|
||||
|
||||
const numHosts = 15
|
||||
|
||||
func benchmarkMerger(b *testing.B, merger app.Merger) {
|
||||
|
||||
@@ -305,16 +305,21 @@ func (r Report) Copy() Report {
|
||||
// original is not modified.
|
||||
func (r Report) Merge(other Report) Report {
|
||||
newReport := r.Copy()
|
||||
newReport.DNS = newReport.DNS.Merge(other.DNS)
|
||||
newReport.Sampling = newReport.Sampling.Merge(other.Sampling)
|
||||
newReport.Window = newReport.Window + other.Window
|
||||
newReport.Plugins = newReport.Plugins.Merge(other.Plugins)
|
||||
newReport.WalkPairedTopologies(&other, func(ourTopology, theirTopology *Topology) {
|
||||
*ourTopology = ourTopology.Merge(*theirTopology)
|
||||
})
|
||||
newReport.UnsafeMerge(other)
|
||||
return newReport
|
||||
}
|
||||
|
||||
// UnsafeMerge merges another Report into the receiver. The original is modified.
|
||||
func (r *Report) UnsafeMerge(other Report) {
|
||||
r.DNS = r.DNS.Merge(other.DNS)
|
||||
r.Sampling = r.Sampling.Merge(other.Sampling)
|
||||
r.Window = r.Window + other.Window
|
||||
r.Plugins = r.Plugins.Merge(other.Plugins)
|
||||
r.WalkPairedTopologies(&other, func(ourTopology, theirTopology *Topology) {
|
||||
ourTopology.UnsafeMerge(*theirTopology)
|
||||
})
|
||||
}
|
||||
|
||||
// WalkTopologies iterates through the Topologies of the report,
|
||||
// potentially modifying them
|
||||
func (r *Report) WalkTopologies(f func(*Topology)) {
|
||||
|
||||
@@ -163,6 +163,21 @@ func (t Topology) Merge(other Topology) Topology {
|
||||
}
|
||||
}
|
||||
|
||||
// UnsafeMerge merges the other object into this one, modifying the original.
|
||||
func (t *Topology) UnsafeMerge(other Topology) {
|
||||
if t.Shape == "" {
|
||||
t.Shape = other.Shape
|
||||
}
|
||||
if t.Label == "" {
|
||||
t.Label, t.LabelPlural = other.Label, other.LabelPlural
|
||||
}
|
||||
t.Nodes.UnsafeMerge(other.Nodes)
|
||||
t.Controls = t.Controls.Merge(other.Controls)
|
||||
t.MetadataTemplates = t.MetadataTemplates.Merge(other.MetadataTemplates)
|
||||
t.MetricTemplates = t.MetricTemplates.Merge(other.MetricTemplates)
|
||||
t.TableTemplates = t.TableTemplates.Merge(other.TableTemplates)
|
||||
}
|
||||
|
||||
// Nodes is a collection of nodes in a topology. Keys are node IDs.
|
||||
// TODO(pb): type Topology map[string]Node
|
||||
type Nodes map[string]Node
|
||||
@@ -186,14 +201,19 @@ func (n Nodes) Merge(other Nodes) Nodes {
|
||||
return n
|
||||
}
|
||||
cp := n.Copy()
|
||||
cp.UnsafeMerge(other)
|
||||
return cp
|
||||
}
|
||||
|
||||
// UnsafeMerge merges the other object into this one, modifying the original.
|
||||
func (n *Nodes) UnsafeMerge(other Nodes) {
|
||||
for k, v := range other {
|
||||
if n, ok := cp[k]; ok { // don't overwrite
|
||||
cp[k] = v.Merge(n)
|
||||
if existing, ok := (*n)[k]; ok { // don't overwrite
|
||||
(*n)[k] = v.Merge(existing)
|
||||
} else {
|
||||
cp[k] = v
|
||||
(*n)[k] = v
|
||||
}
|
||||
}
|
||||
return cp
|
||||
}
|
||||
|
||||
// Validate checks the topology for various inconsistencies.
|
||||
|
||||
Reference in New Issue
Block a user