Commit dc23b088 by Ben Clayton

Regres: Optimize coverage processing

This had regressed mostly due to a single thread processing a huge number of `Span.Add()`s. Optimize for the common case, avoid `Span.Add()` in places where the data is already sorted, don't scan the entire file system for every test run. Bug: b/152192800 Change-Id: Id183468263e65bfbcf387ec1c978d8b9de547cee Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43570Reviewed-by: 's avatarAntonio Maiorano <amaiorano@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com>
parent 79b4b0ed
......@@ -27,15 +27,6 @@ import (
"../llvm"
)
var ignorePaths = map[string]bool{
"src/Common": true,
"src/Main": true,
"src/OpenGL": true,
"src/Renderer": true,
"src/Shader": true,
"src/System": true,
}
// File describes the coverage spans in a single source file.
type File struct {
Path string
......@@ -63,6 +54,45 @@ func AppendRuntimeEnv(env []string, coverageFile string) []string {
return append(env, "LLVM_PROFILE_FILE="+coverageFile)
}
// AllSourceFiles returns a *Coverage containing all the source files without
// coverage data. This populates the coverage view with files even if they
// didn't get compiled.
func (e Env) AllSourceFiles() *Coverage {
var ignorePaths = map[string]bool{
"src/Common": true,
"src/Main": true,
"src/OpenGL": true,
"src/Renderer": true,
"src/Shader": true,
"src/System": true,
}
// Gather all the source files to include them even if there is no coverage
// information produced for these files. This highlights files that aren't
// even compiled.
cov := Coverage{}
allFiles := map[string]struct{}{}
filepath.Walk(filepath.Join(e.RootDir, "src"), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(e.RootDir, path)
if err != nil || ignorePaths[rel] {
return filepath.SkipDir
}
if !info.IsDir() {
switch filepath.Ext(path) {
case ".h", ".c", ".cc", ".cpp", ".hpp":
if _, seen := allFiles[rel]; !seen {
cov.Files = append(cov.Files, File{Path: rel})
}
}
}
return nil
})
return &cov
}
// Import uses the llvm-profdata and llvm-cov tools to import the coverage
// information from a .profraw file.
func (e Env) Import(profrawPath string) (*Coverage, error) {
......@@ -108,32 +138,6 @@ func (e Env) Import(profrawPath string) (*Coverage, error) {
return nil, cause.Wrap(err, "Couldn't process turbo-cov output")
}
// Gather all the source files to include them even if there is no coverage
// information produced for these files. This highlights files that aren't
// even compiled.
allFiles := map[string]struct{}{}
for _, file := range cov.Files {
allFiles[file.Path] = struct{}{}
}
filepath.Walk(filepath.Join(e.RootDir, "src"), func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
rel, err := filepath.Rel(e.RootDir, path)
if err != nil || ignorePaths[rel] {
return filepath.SkipDir
}
if !info.IsDir() {
switch filepath.Ext(path) {
case ".h", ".c", ".cc", ".cpp", ".hpp":
if _, seen := allFiles[rel]; !seen {
cov.Files = append(cov.Files, File{Path: rel})
}
}
}
return nil
})
return cov, nil
}
......@@ -185,9 +189,9 @@ func (e Env) parseCov(raw []byte) (*Coverage, error) {
start := Location{(int)(f.Segments[sIdx][0].(float64)), (int)(f.Segments[sIdx][1].(float64))}
end := Location{(int)(f.Segments[sIdx+1][0].(float64)), (int)(f.Segments[sIdx+1][1].(float64))}
if covered := f.Segments[sIdx][2].(float64) != 0; covered {
file.Covered.Add(Span{start, end})
file.Covered = appendSpan(file.Covered, Span{start, end})
} else {
file.Uncovered.Add(Span{start, end})
file.Uncovered = appendSpan(file.Uncovered, Span{start, end})
}
}
if len(file.Covered) > 0 {
......@@ -251,9 +255,9 @@ func (e Env) parseTurboCov(data []byte) (*Coverage, error) {
end := segments[sIdx+1].location
if segments[sIdx].covered {
if segments[sIdx].count > 0 {
file.Covered.Add(Span{start, end})
file.Covered = appendSpan(file.Covered, Span{start, end})
} else {
file.Uncovered.Add(Span{start, end})
file.Uncovered = appendSpan(file.Uncovered, Span{start, end})
}
}
}
......
......@@ -76,6 +76,9 @@ func (s Span) Compare(o Span) int {
// Before returns true if span s comes before o.
func (s Span) Before(o Span) bool { return s.Compare(o) == -1 }
// Inside returns true if span s fits entirely inside o.
func (s Span) Inside(o Span) bool { return s.Start.Compare(o.Start) >= 0 && s.End.Compare(o.End) <= 0 }
// SpanList is a sorted list of spans. Use SpanList.Add() to insert new spans.
type SpanList []Span
......@@ -87,6 +90,11 @@ func (l *SpanList) Add(s Span) {
// [ 0 ] [ 1 ] [ 2 ] [ 3 ] | idxStart: 1 | idxEnd: 2
// [0] [1] [2] [3] [4] | idxStart: 2 | idxEnd: 2
idxStart := sort.Search(len(*l), func(i int) bool { return (*l)[i].End.Compare(s.Start) >= 0 })
if idxStart < len(*l) && s.Inside((*l)[idxStart]) {
return // No change.
}
idxEnd := sort.Search(len(*l), func(i int) bool { return (*l)[i].Start.Compare(s.End) > 0 })
if idxStart < idxEnd {
......
......@@ -216,6 +216,7 @@ func (c *Config) Run() (*Results, error) {
if c.CoverageEnv != nil {
out.Coverage = &cov.Tree{}
out.Coverage.Add(cov.Path{}, c.CoverageEnv.AllSourceFiles())
}
// Collect the results.
......
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