Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ygot.Diff performance #791

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions ygot/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,34 @@ func joingNMIPaths(parent *gnmipb.Path, child *gnmipb.Path) *gnmipb.Path {

// pathSpec is a wrapper type used to store a set of gNMI paths to which
// a value within a GoStruct corresponds to.
//
// NOTE: Once Equal() is called, no more changes must be made to pathSpec;
// otherwise, future calls to Equal() will give the incorrect result.
type pathSpec struct {
// gNMIPaths is the set of gNMI paths that the path represents.
gNMIPaths []*gnmipb.Path
// gNMIPathStrs is the set of gNMI paths that the path represents as strings.
gNMIPathStrs map[string]struct{}
}

func (p *pathSpec) populateStrs() {
if p == nil {
return
}

if p.gNMIPathStrs != nil {
return
}

p.gNMIPathStrs = map[string]struct{}{}
for _, path := range p.gNMIPaths {
str, err := PathToString(path)
if err != nil {
p.gNMIPathStrs = nil
return
}
p.gNMIPathStrs[str] = struct{}{}
}
}

// Equal compares two pathSpecs, returning true if all paths within the pathSpec
Expand All @@ -62,6 +87,13 @@ func (p *pathSpec) Equal(o *pathSpec) bool {
return p == o
}

p.populateStrs()
o.populateStrs()

if p.gNMIPathStrs != nil && o.gNMIPathStrs != nil {
return reflect.DeepEqual(p.gNMIPathStrs, o.gNMIPathStrs)
}

for _, path := range p.gNMIPaths {
var found bool
for _, otherPath := range o.gNMIPaths {
Expand Down
20 changes: 16 additions & 4 deletions ygot/schema_tests/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package schematest

import (
"fmt"
"io/ioutil"
"reflect"
"testing"
Expand Down Expand Up @@ -591,8 +592,11 @@ func TestNotificationOutput(t *testing.T) {
}
}

func getBenchmarkDevice() *exampleoc.Device {
intfs := []string{"eth0", "eth1", "eth2", "eth3"}
func getBenchmarkDevice(n int) *exampleoc.Device {
var intfs []string
for i := 0; i < n; i++ {
intfs = append(intfs, fmt.Sprintf("eth%d", i))
}
d := &exampleoc.Device{}
for _, intf := range intfs {
d.GetOrCreateInterface(intf)
Expand All @@ -603,7 +607,7 @@ func getBenchmarkDevice() *exampleoc.Device {
}

func BenchmarkNotificationOutput(b *testing.B) {
d := getBenchmarkDevice()
d := getBenchmarkDevice(4)
b.ResetTimer()
for i := 0; i != b.N; i++ {
if _, err := ygot.TogNMINotifications(d, 0, ygot.GNMINotificationsConfig{
Expand All @@ -615,7 +619,7 @@ func BenchmarkNotificationOutput(b *testing.B) {
}

func BenchmarkNotificationOutputElement(b *testing.B) {
d := getBenchmarkDevice()
d := getBenchmarkDevice(4)
b.ResetTimer()
for i := 0; i != b.N; i++ {
if _, err := ygot.TogNMINotifications(d, 0, ygot.GNMINotificationsConfig{
Expand All @@ -625,3 +629,11 @@ func BenchmarkNotificationOutputElement(b *testing.B) {
}
}
}

func BenchmarkDiff(b *testing.B) {
d1 := getBenchmarkDevice(1000)
d2 := getBenchmarkDevice(500)
for n := 0; n != b.N; n++ {
ygot.Diff(d1, d2)
}
}