Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Mar 18, 2022. It is now read-only.
/preallocPublic archive
forked fromalexkohler/prealloc

prealloc is a Go static analysis tool to find slice declarations that could potentially be preallocated.

License

NotificationsYou must be signed in to change notification settings

golangci/prealloc

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

43 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

prealloc is a Go static analysis tool to find slice declarations that could potentially be preallocated.

Installation

go get -u github.com/alexkohler/prealloc

Usage

Similar to other Go static analysis tools (such as golint, go vet), prealloc can be invoked with one or more filenames, directories, or packages named by its import path. Prealloc also supports the... wildcard.

prealloc [flags] files/directories/packages

Flags

  • -simple (default true) - Report preallocation suggestions only on simple loops that have no returns/breaks/continues/gotos in them. Setting this to false may increase false positives.
  • -rangeloops (default true) - Report preallocation suggestions on range loops.
  • -forloops (default false) - Report preallocation suggestions on for loops. This is false by default due to there generally being weirder things happening inside for loops (at least from what I've observed in the Standard Library).
  • -set_exit_status (default false) - Set exit status to 1 if any issues are found.

Purpose

While theGodoes attempt to avoid reallocation by growing the capacity in advance, this sometimes isn't enough for longer slices. If the size of a slice is known at the time of its creation, it should be specified.

Consider the following benchmark: (this can be found in prealloc_test.go in this repo)

import"testing"funcBenchmarkNoPreallocate(b*testing.B) {existing:=make([]int64,10,10)b.ResetTimer()fori:=0;i<b.N;i++ {// Don't preallocate our initial slicevarinit []int64for_,element:=rangeexisting {init=append(init,element)}}}funcBenchmarkPreallocate(b*testing.B) {existing:=make([]int64,10,10)b.ResetTimer()fori:=0;i<b.N;i++ {// Preallocate our initial sliceinit:=make([]int64,0,len(existing))for_,element:=rangeexisting {init=append(init,element)}}}
$ gotest -bench=. -benchmemgoos: linuxgoarch: amd64BenchmarkNoPreallocate-4    3000000       510 ns/op     248 B/op       5 allocs/opBenchmarkPreallocate-4     20000000       111 ns/op      80 B/op       1 allocs/op

As you can see, not preallocating can cause a performance hit, primarily due to Go having to reallocate the underlying array. The pattern benchmarked above is common in Go: declare a slice, then write some sort of range or for loop that appends or indexes into it. The purpose of this tool is to flag slice/loop declarations like the one inBenchmarkNoPreallocate.

Example

Some examples from the Go 1.9.2 source:

$ prealloc go/src/....archive/tar/reader_test.go:854 Consider preallocating ssarchive/zip/zip_test.go:201 Consider preallocating allcmd/api/goapi.go:301 Consider preallocating missingcmd/api/goapi.go:476 Consider preallocating filescmd/asm/internal/asm/endtoend_test.go:345 Consider preallocating extracmd/cgo/main.go:60 Consider preallocating kscmd/cgo/ast.go:149 Consider preallocating piecescmd/compile/internal/ssa/flagalloc.go:64 Consider preallocating oldSchedcmd/compile/internal/ssa/regalloc.go:719 Consider preallocating phiscmd/compile/internal/ssa/regalloc.go:718 Consider preallocating oldSchedcmd/compile/internal/ssa/regalloc.go:1674 Consider preallocating oldSchedcmd/compile/internal/ssa/gen/rulegen.go:145 Consider preallocating opscmd/compile/internal/ssa/gen/rulegen.go:145 Consider preallocating opscmd/dist/build.go:893 Consider preallocating allcmd/dist/build.go:1246 Consider preallocating platscmd/dist/build.go:1264 Consider preallocating resultscmd/dist/buildgo.go:59 Consider preallocating listcmd/doc/pkg.go:363 Consider preallocating namescmd/fix/typecheck.go:219 Consider preallocating bcmd/go/internal/base/path.go:34 Consider preallocating outcmd/go/internal/get/get.go:175 Consider preallocating outcmd/go/internal/load/pkg.go:1894 Consider preallocating direntcmd/go/internal/work/build.go:2402 Consider preallocating absOfilescmd/go/internal/work/build.go:2731 Consider preallocating absOfilescmd/internal/objfile/pe.go:48 Consider preallocating symscmd/internal/objfile/pe.go:38 Consider preallocating addrscmd/internal/objfile/goobj.go:43 Consider preallocating symscmd/internal/objfile/elf.go:35 Consider preallocating symscmd/link/internal/ld/lib.go:1070 Consider preallocating argvcmd/vet/all/main.go:91 Consider preallocating ppdatabase/sql/sql.go:66 Consider preallocating listdebug/macho/file.go:506 Consider preallocating allinternal/trace/order.go:55 Consider preallocating batchesmime/quotedprintable/reader_test.go:191 Consider preallocating outcomesnet/dnsclient_unix_test.go:954 Consider preallocating confLinesnet/interface_solaris.go:85 Consider preallocating ifatnet/interface_linux_test.go:91 Consider preallocating ifmat4net/interface_linux_test.go:100 Consider preallocating ifmat6net/internal/socktest/switch.go:34 Consider preallocating stos/os_windows_test.go:766 Consider preallocating argsruntime/pprof/internal/profile/filter.go:77 Consider preallocating linesruntime/pprof/internal/profile/profile.go:554 Consider preallocating namestext/template/parse/node.go:189 Consider preallocating decl
// cmd/api/goapi.go:301varmissing []stringforfeature:=rangeoptionalSet {missing=append(missing,feature)}// cmd/fix/typecheck.go:219varb []ast.Exprfor_,x:=rangea {b=append(b,x)}// net/internal/socktest/switch.go:34varst []Statsw.smu.RLock()for_,s:=rangesw.stats {ns:=*sst=append(st,ns)}sw.smu.RUnlock()// cmd/api/goapi.go:301varmissing []stringforfeature:=rangeoptionalSet {missing=append(missing,feature)}

Even if the size the slice is being preallocated to is small, there's still a performance gain to be had in explicitly specifying the capacity rather than leaving it up toappend to discover that it needs to preallocate. Of course, preallocation doesn't need to be doneeverywhere. This tool's job is just to help suggest places where one should consider preallocating.

How do I fix prealloc's suggestions?

During the declaration of your slice, rather than using the zero value of the slice withvar, initialize it with Go's built-inmake function, passing the appropriate type and length. This length will generally be whatever you are ranging over. Fixing the examples from above would look like so:

// cmd/api/goapi.go:301missing:=make([]string,0,len(optionalSet))forfeature:=rangeoptionalSet {missing=append(missing,feature)}// cmd/fix/typecheck.go:219b:=make([]ast.Expr,0,len(a))for_,x:=rangea {b=append(b,x)}// net/internal/socktest/switch.go:34st:=make([]Stat,0,len(sw.stats))sw.smu.RLock()for_,s:=rangesw.stats {ns:=*sst=append(st,ns)}sw.smu.RUnlock()// cmd/api/goapi.go:301missing:=make ([]string,0,len(optionalSet))forfeature:=rangeoptionalSet {missing=append(missing,feature)}

TODO

  • Configuration on whether or not to run on test files
  • Support for embedded ifs (currently, prealloc will only find breaks/returns/continues/gotos if they are in a single if block, I'd like to expand this to supporting multiple if blocks in the future).
  • Globbing support (e.g. prealloc *.go)

Contributing

Pull requests welcome!

Other static analysis tools

If you've enjoyed prealloc, take a look at my other static anaylsis tools!

About

prealloc is a Go static analysis tool to find slice declarations that could potentially be preallocated.

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go100.0%

[8]ページ先頭

©2009-2025 Movatter.jp