Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

Commit

Permalink
dramatically Increase performance of tool (#107)
Browse files Browse the repository at this point in the history
* done

* fix hardcode

* remove import

* remove comments

* Revert "remove comments"

This reverts commit e74459a.

* Revert "remove import"

This reverts commit 5aa5ffb.

* Revert "fix hardcode"

This reverts commit e5e62ed.

* Revert "done"

This reverts commit 0fe7a9e.

* remade logic to support not only local modules

* remove unused variables

* rename variables

* remade on package.Load function

* make with one call

* go mod tidy

* fix potential bug with name collisions because of use HasSuffix

* a bit optimize cycles and rename function to convertProfile back

* change from filepath to path

---------

Co-authored-by: artemikhaylov <artemikhaylov@ozon.ru>
  • Loading branch information
hihoak and artemikhaylov authored Oct 11, 2024
1 parent dd288a8 commit 383f7cd
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 49 deletions.
14 changes: 12 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
module github.com/axw/gocov

go 1.12
go 1.22.0

toolchain go1.22.7

require (
github.com/stretchr/testify v1.7.1
golang.org/x/tools v0.0.0-20190617190820-da514acc4774
golang.org/x/tools v0.13.0
)

require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/sys v0.12.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)
15 changes: 8 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774 h1:CQVOmarCBFzTx0kbOU0ru54Cvot8SdSrNYjZPhQl+gk=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down
90 changes: 50 additions & 40 deletions gocov/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,26 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/axw/gocov"
"github.com/axw/gocov/gocovutil"
"go/ast"
"go/build"
"go/parser"
"go/token"
"golang.org/x/tools/cover"
goPackages "golang.org/x/tools/go/packages"
"io"
"path"
"path/filepath"
"strings"

"github.com/axw/gocov"
"github.com/axw/gocov/gocovutil"
"golang.org/x/tools/cover"
)

func marshalJson(w io.Writer, packages []*gocov.Package) error {
return json.NewEncoder(w).Encode(struct{ Packages []*gocov.Package }{packages})
}

type packagesCache map[string]*build.Package

func ConvertProfiles(filenames ...string) ([]byte, error) {
var (
ps gocovutil.Packages
packages = make(packagesCache)
ps gocovutil.Packages
)

for i := range filenames {
Expand All @@ -57,9 +54,42 @@ func ConvertProfiles(filenames ...string) ([]byte, error) {
if err != nil {
return nil, err
}
for _, p := range profiles {
if err := converter.convertProfile(packages, p); err != nil {
return nil, err

mapUniqPackageNames := make(map[string]interface{})
uniqPackageNames := make([]string, 0, len(profiles))
for _, profile := range profiles {
packageName := path.Dir(profile.FileName)

if _, ok := mapUniqPackageNames[packageName]; ok {
continue
}

mapUniqPackageNames[packageName] = nil
uniqPackageNames = append(uniqPackageNames, packageName)
}

packages, err := goPackages.Load(&goPackages.Config{
Mode: goPackages.NeedName | goPackages.NeedCompiledGoFiles,
}, uniqPackageNames...)
if err != nil {
return nil, fmt.Errorf("load packages: %v", err)
}

pkgmap := make(map[string]*goPackages.Package, len(packages))
for _, pkg := range packages {
pkgmap[pkg.PkgPath] = pkg
}

for _, profile := range profiles {
pkgpath, filename := path.Split(profile.FileName)
pkgpath = strings.TrimSuffix(pkgpath, "/")
pkg := pkgmap[pkgpath]
for _, abspath := range pkg.CompiledGoFiles {
if filepath.Base(abspath) == filename {
if err := converter.convertProfile(profile, abspath, pkg.PkgPath); err != nil {
return nil, fmt.Errorf("convert profile %s: %w", profile.FileName, err)
}
}
}
}

Expand All @@ -84,29 +114,26 @@ type statement struct {
*StmtExtent
}

func (c *converter) convertProfile(packages packagesCache, p *cover.Profile) error {
file, pkgpath, err := findFile(packages, p.FileName)
if err != nil {
return err
}
pkg := c.packages[pkgpath]
func (c *converter) convertProfile(p *cover.Profile, absFilePath, pkgPath string) error {
pkg := c.packages[pkgPath]
if pkg == nil {
pkg = &gocov.Package{Name: pkgpath}
c.packages[pkgpath] = pkg
pkg = &gocov.Package{Name: pkgPath}
c.packages[pkgPath] = pkg
}
// Find function and statement extents; create corresponding
// gocov.Functions and gocov.Statements, and keep a separate
// slice of gocov.Statements so we can match them with profile
// blocks.
extents, err := findFuncs(file)
extents, err := findFuncs(absFilePath)
if err != nil {
return err
}

var stmts []statement
for _, fe := range extents {
f := &gocov.Function{
Name: fe.name,
File: file,
File: absFilePath,
Start: fe.startOffset,
End: fe.endOffset,
}
Expand Down Expand Up @@ -138,25 +165,8 @@ func (c *converter) convertProfile(packages packagesCache, p *cover.Profile) err
break
}
}
return nil
}

// findFile finds the location of the named file in GOROOT, GOPATH etc.
func findFile(packages packagesCache, file string) (filename, pkgpath string, err error) {
dir, file := filepath.Split(file)
if dir != "" {
dir = strings.TrimSuffix(dir, "/")
}
pkg, ok := packages[dir]
if !ok {
pkg, err = build.Import(dir, ".", build.FindOnly)
if err != nil {
return "", "", fmt.Errorf("can't find %q: %w", file, err)
}
packages[dir] = pkg
}

return filepath.Join(pkg.Dir, file), pkg.ImportPath, nil
return nil
}

// findFuncs parses the file and returns a slice of FuncExtent descriptors.
Expand Down

0 comments on commit 383f7cd

Please sign in to comment.