Commit 524c5c7b by Ben Clayton

Regres: Keep coverage span groups stable.

Update tests. Bug: b/152192800 Change-Id: I4e57f0d2b049f0bce7459b29f7ffc3a2ca03534a Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43309 Kokoro-Presubmit: kokoro <noreply+kokoro@google.com> Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent f5da9d9c
...@@ -88,7 +88,7 @@ func TestTree(t *testing.T) { ...@@ -88,7 +88,7 @@ func TestTree(t *testing.T) {
// i // i
checkSpans(t, tree.Spans(), span0, span1, span2) checkSpans(t, tree.Spans(), span0, span1, span2)
checkTests(t, tree, `{a:{b:{d:{i} e}}}`) checkTests(t, tree, `{a:{b:{d:{i} e}}}`)
checkCoverage(t, tree, fileA, `a:{[0,1] b:{[] e:{[2]}}}`) checkCoverage(t, tree, fileA, `a:{[0,1] b:{e:{[2]}}}`)
t.Log("Add 'n' with the coverage [0,3]") t.Log("Add 'n' with the coverage [0,3]")
tree.Add(cov.Path{"a", "c", "g", "n"}, coverage(fileA, span0, span3)) tree.Add(cov.Path{"a", "c", "g", "n"}, coverage(fileA, span0, span3))
...@@ -132,7 +132,7 @@ func TestTree(t *testing.T) { ...@@ -132,7 +132,7 @@ func TestTree(t *testing.T) {
// i n o // i n o
checkSpans(t, tree.Spans(), span0, span1, span2, span3) checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e} c:{f g:{n o}}}}`) checkTests(t, tree, `{a:{b:{d:{i} e} c:{f g:{n o}}}}`)
checkCoverage(t, tree, fileA, `a:{[] b:{[0,1] e:{[2]}} c:{[] f:{[1]} g:{[0,3]}}}`) checkCoverage(t, tree, fileA, `a:{b:{[0,1] e:{[2]}} c:{f:{[1]} g:{[0,3]}}}`)
t.Log("Add 'j' with the coverage [3]") t.Log("Add 'j' with the coverage [3]")
tree.Add(cov.Path{"a", "b", "e", "j"}, coverage(fileA, span3)) tree.Add(cov.Path{"a", "b", "e", "j"}, coverage(fileA, span3))
...@@ -146,7 +146,7 @@ func TestTree(t *testing.T) { ...@@ -146,7 +146,7 @@ func TestTree(t *testing.T) {
// i j n o // i j n o
checkSpans(t, tree.Spans(), span0, span1, span2, span3) checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e:{j}} c:{f g:{n o}}}}`) checkTests(t, tree, `{a:{b:{d:{i} e:{j}} c:{f g:{n o}}}}`)
checkCoverage(t, tree, fileA, `a:{[] b:{[] d:{[0,1]} e:{[3]}} c:{[] f:{[1]} g:{[0,3]}}}`) checkCoverage(t, tree, fileA, `a:{b:{d:{[0,1]} e:{[3]}} c:{f:{[1]} g:{[0,3]}}}`)
t.Log("Add 'k' with the coverage [3]") t.Log("Add 'k' with the coverage [3]")
tree.Add(cov.Path{"a", "b", "e", "k"}, coverage(fileA, span3)) tree.Add(cov.Path{"a", "b", "e", "k"}, coverage(fileA, span3))
...@@ -160,7 +160,7 @@ func TestTree(t *testing.T) { ...@@ -160,7 +160,7 @@ func TestTree(t *testing.T) {
// i j k n o // i j k n o
checkSpans(t, tree.Spans(), span0, span1, span2, span3) checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f g:{n o}}}}`) checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f g:{n o}}}}`)
checkCoverage(t, tree, fileA, `a:{[] b:{[] d:{[0,1]} e:{[3]}} c:{[] f:{[1]} g:{[0,3]}}}`) checkCoverage(t, tree, fileA, `a:{b:{d:{[0,1]} e:{[3]}} c:{f:{[1]} g:{[0,3]}}}`)
t.Log("Add 'v' with the coverage [1,2]") t.Log("Add 'v' with the coverage [1,2]")
tree.Add(cov.Path{"a", "c", "f", "l", "v"}, coverage(fileA, span1, span2)) tree.Add(cov.Path{"a", "c", "f", "l", "v"}, coverage(fileA, span1, span2))
...@@ -176,7 +176,7 @@ func TestTree(t *testing.T) { ...@@ -176,7 +176,7 @@ func TestTree(t *testing.T) {
// v // v
checkSpans(t, tree.Spans(), span0, span1, span2, span3) checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v}} g:{n o}}}}`) checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v}} g:{n o}}}}`)
checkCoverage(t, tree, fileA, `a:{[] b:{[] d:{[0,1]} e:{[3]}} c:{[] f:{[1,2]} g:{[0,3]}}}`) checkCoverage(t, tree, fileA, `a:{b:{d:{[0,1]} e:{[3]}} c:{f:{[1,2]} g:{[0,3]}}}`)
t.Log("Add 'x' with the coverage [1,2]") t.Log("Add 'x' with the coverage [1,2]")
tree.Add(cov.Path{"a", "c", "f", "l", "x"}, coverage(fileA, span1, span2)) tree.Add(cov.Path{"a", "c", "f", "l", "x"}, coverage(fileA, span1, span2))
...@@ -192,7 +192,7 @@ func TestTree(t *testing.T) { ...@@ -192,7 +192,7 @@ func TestTree(t *testing.T) {
// v x // v x
checkSpans(t, tree.Spans(), span0, span1, span2, span3) checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v x}} g:{n o}}}}`) checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v x}} g:{n o}}}}`)
checkCoverage(t, tree, fileA, `a:{[] b:{[] d:{[0,1]} e:{[3]}} c:{[] f:{[1,2]} g:{[0,3]}}}`) checkCoverage(t, tree, fileA, `a:{b:{d:{[0,1]} e:{[3]}} c:{f:{[1,2]} g:{[0,3]}}}`)
t.Log("Add 'z' with the coverage [2]") t.Log("Add 'z' with the coverage [2]")
tree.Add(cov.Path{"a", "c", "g", "n", "z"}, coverage(fileA, span2)) tree.Add(cov.Path{"a", "c", "g", "n", "z"}, coverage(fileA, span2))
...@@ -208,7 +208,22 @@ func TestTree(t *testing.T) { ...@@ -208,7 +208,22 @@ func TestTree(t *testing.T) {
// v x z // v x z
checkSpans(t, tree.Spans(), span0, span1, span2, span3) checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v x}} g:{n: {z} o}}}}`) checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v x}} g:{n: {z} o}}}}`)
checkCoverage(t, tree, fileA, `a:{[] b:{[] d:{[0,1]} e:{[3]}} c:{[] f:{[1,2]} g:{[] n:{[2]} o:{[0,3]}}}}`) checkCoverage(t, tree, fileA, `a:{b:{d:{[0,1]} e:{[3]}} c:{f:{[1,2]} g:{n:{[2]} o:{[0,3]}}}}`)
tree.Optimize()
// (a)
// ┏━━━━━━━━┻━━━━━━━━━━━━┓
// (b) (c)
// ┏━━━┻━━━┓ ┏━━━━┻━━━━┓
// <0>(d) (e)[3] <2>(f) (g)
// ╰─╮ ╭─┴─╮ ╭─╯ ┏━┻━┓
// i j k l [2](n) (o)<1>
// ╭┴╮ ╭╯
// v x z
checkSpans(t, tree.Spans(), span0, span1, span2, span3)
checkTests(t, tree, `{a:{b:{d:{i} e:{j k}} c:{f:{l:{v x}} g:{n: {z} o}}}}`)
checkCoverage(t, tree, fileA, `a:{b:{d:{<0>} e:{[3]}} c:{f:{<2>} g:{n:{[2]} o:{<1>}}}}`)
} }
func checkSpans(t *testing.T, got []cov.Span, expect ...cov.Span) { func checkSpans(t *testing.T, got []cov.Span, expect ...cov.Span) {
......
...@@ -37,15 +37,47 @@ func (l Location) String() string { ...@@ -37,15 +37,47 @@ func (l Location) String() string {
return fmt.Sprintf("%v:%v", l.Line, l.Column) return fmt.Sprintf("%v:%v", l.Line, l.Column)
} }
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
func (l Location) Compare(o Location) int {
switch {
case l.Line < o.Line:
return -1
case l.Line > o.Line:
return 1
}
return 0
}
// Before returns true if l comes before o.
func (l Location) Before(o Location) bool { return l.Compare(o) == -1 }
// Span describes a start and end interval in a source file. // Span describes a start and end interval in a source file.
type Span struct { type Span struct {
Start, End Location Start, End Location
} }
func (l Span) String() string { func (s Span) String() string {
return fmt.Sprintf("%v-%v", l.Start, l.End) return fmt.Sprintf("%v-%v", s.Start, s.End)
} }
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
func (s Span) Compare(o Span) int {
switch {
case s.Start.Before(o.Start):
return -1
case o.Start.Before(s.Start):
return 1
case s.End.Before(o.End):
return -1
case o.End.Before(s.End):
return 1
}
return 0
}
// Before returns true if span s comes before o.
func (s Span) Before(o Span) bool { return s.Compare(o) == -1 }
// File describes the coverage spans in a single source file. // File describes the coverage spans in a single source file.
type File struct { type File struct {
Path string Path string
......
...@@ -54,21 +54,35 @@ func (t *Tree) init() { ...@@ -54,21 +54,35 @@ func (t *Tree) init() {
} }
} }
// SpanList is a list of Spans
type SpanList []Span
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
func (l SpanList) Compare(o SpanList) int {
switch {
case len(l) < len(o):
return -1
case len(l) > len(o):
return 1
}
for i, a := range l {
switch a.Compare(o[i]) {
case -1:
return -1
case 1:
return 1
}
}
return 0
}
// Spans returns all the spans used by the tree // Spans returns all the spans used by the tree
func (t *Tree) Spans() []Span { func (t *Tree) Spans() SpanList {
out := make([]Span, 0, len(t.spans)) out := make(SpanList, 0, len(t.spans))
for span := range t.spans { for span := range t.spans {
out = append(out, span) out = append(out, span)
} }
sort.Slice(out, func(i, j int) bool { sort.Slice(out, func(i, j int) bool { return out[i].Before(out[j]) })
if out[i].Start.Line < out[j].Start.Line {
return true
}
if out[i].Start.Line > out[j].Start.Line {
return false
}
return out[i].Start.Column < out[j].Start.Column
})
return out return out
} }
...@@ -259,7 +273,15 @@ type TestCoverage struct { ...@@ -259,7 +273,15 @@ type TestCoverage struct {
func (tc TestCoverage) String(t *Test, s Strings) string { func (tc TestCoverage) String(t *Test, s Strings) string {
sb := strings.Builder{} sb := strings.Builder{}
sb.WriteString(fmt.Sprintf("{%v", tc.Spans)) sb.WriteString("{")
if len(tc.Spans) > 0 {
sb.WriteString(tc.Spans.String())
}
if tc.Group != nil {
sb.WriteString(" <")
sb.WriteString(fmt.Sprintf("%v", *tc.Group))
sb.WriteString(">")
}
if len(tc.Children) > 0 { if len(tc.Children) > 0 {
sb.WriteString(" ") sb.WriteString(" ")
sb.WriteString(tc.Children.String(t, s)) sb.WriteString(tc.Children.String(t, s))
...@@ -313,9 +335,32 @@ type SpanID int ...@@ -313,9 +335,32 @@ type SpanID int
// SpanSet is a set of SpanIDs. // SpanSet is a set of SpanIDs.
type SpanSet map[SpanID]struct{} type SpanSet map[SpanID]struct{}
// SpanIDList is a list of SpanIDs
type SpanIDList []SpanID
// Compare returns -1 if l comes before o, 1 if l comes after o, otherwise 0.
func (l SpanIDList) Compare(o SpanIDList) int {
switch {
case len(l) < len(o):
return -1
case len(l) > len(o):
return 1
}
for i, a := range l {
b := o[i]
switch {
case a < b:
return -1
case a > b:
return 1
}
}
return 0
}
// List returns the full list of sorted span ids. // List returns the full list of sorted span ids.
func (s SpanSet) List() []SpanID { func (s SpanSet) List() SpanIDList {
out := make([]SpanID, 0, len(s)) out := make(SpanIDList, 0, len(s))
for span := range s { for span := range s {
out = append(out, span) out = append(out, span)
} }
...@@ -422,7 +467,6 @@ func (f *treeFile) optimize() { ...@@ -422,7 +467,6 @@ func (f *treeFile) optimize() {
return return
} }
// Sort by number of spans in each sets.
type spansetInfo struct { type spansetInfo struct {
key spansetKey key spansetKey
set SpanSet // fully expanded set set SpanSet // fully expanded set
...@@ -435,10 +479,25 @@ func (f *treeFile) optimize() { ...@@ -435,10 +479,25 @@ func (f *treeFile) optimize() {
key: key, key: key,
set: set, set: set,
grp: SpanGroup{spans: set}, grp: SpanGroup{spans: set},
id: SpanGroupID(len(spansets)),
}) })
} }
sort.Slice(spansets, func(i, j int) bool { return len(spansets[i].set) > len(spansets[j].set) })
// Sort by number of spans in each sets starting with the largest.
sort.Slice(spansets, func(i, j int) bool {
a, b := spansets[i].set, spansets[j].set
switch {
case len(a) > len(b):
return true
case len(a) < len(b):
return false
}
return a.List().Compare(b.List()) == -1 // Just to keep output stable
})
// Assign IDs now that we have stable order.
for i := range spansets {
spansets[i].id = SpanGroupID(i)
}
// Loop over the spanGroups starting from the largest, and try to fold them // Loop over the spanGroups starting from the largest, and try to fold them
// into the larger sets. // into the larger sets.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment