mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.fuzz] internal/fuzz: coarsen each coverage counter when taking a snapshot
When taking a snapshot of coverage counters, round each counter down to the nearest power of 2. After coarsening, at most 1 bit per byte will be set. This lets the coordinator use a coverage array as a mask that distinguish between code that's executed many times for a given input and code that's executed once or a few times. For example, if a byte in this array has the value 12, it means the block has been executed at least 4 times and at least 8 times with different inputs. Also change the term "edge" to "bits" or just be more vague about how coverage is represented. Also add more code that may be "interesting" in test_fuzz_cache. Change-Id: I67bf2adb298fb8efd7680b069a476c27e5fdbdae Reviewed-on: https://go-review.googlesource.com/c/go/+/338829 Trust: Jay Conrod <jayconrod@google.com> Run-TryBot: Jay Conrod <jayconrod@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
f89b4c8d82
commit
7b6893d2d2
3 changed files with 96 additions and 49 deletions
|
|
@ -6,6 +6,7 @@ package fuzz
|
|||
|
||||
import (
|
||||
"internal/unsafeheader"
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
|
@ -36,26 +37,70 @@ func ResetCoverage() {
|
|||
}
|
||||
|
||||
// SnapshotCoverage copies the current counter values into coverageSnapshot,
|
||||
// preserving them for later inspection.
|
||||
// preserving them for later inspection. SnapshotCoverage also rounds each
|
||||
// counter down to the nearest power of two. This lets the coordinator store
|
||||
// multiple values for each counter by OR'ing them together.
|
||||
func SnapshotCoverage() {
|
||||
cov := coverage()
|
||||
if coverageSnapshot == nil {
|
||||
coverageSnapshot = make([]byte, len(cov))
|
||||
for i, b := range cov {
|
||||
b |= b >> 1
|
||||
b |= b >> 2
|
||||
b |= b >> 4
|
||||
b -= b >> 1
|
||||
coverageSnapshot[i] = b
|
||||
}
|
||||
copy(coverageSnapshot, cov)
|
||||
}
|
||||
|
||||
func countEdges(cov []byte) int {
|
||||
n := 0
|
||||
for _, c := range cov {
|
||||
if c > 0 {
|
||||
n++
|
||||
// diffCoverage returns a set of bits set in snapshot but not in base.
|
||||
// If there are no new bits set, diffCoverage returns nil.
|
||||
func diffCoverage(base, snapshot []byte) []byte {
|
||||
found := false
|
||||
for i := range snapshot {
|
||||
if snapshot[i]&^base[i] != 0 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
diff := make([]byte, len(snapshot))
|
||||
for i := range diff {
|
||||
diff[i] = snapshot[i] &^ base[i]
|
||||
}
|
||||
return diff
|
||||
}
|
||||
|
||||
// countNewCoverageBits returns the number of bits set in snapshot that are not
|
||||
// set in base.
|
||||
func countNewCoverageBits(base, snapshot []byte) int {
|
||||
n := 0
|
||||
for i := range snapshot {
|
||||
n += bits.OnesCount8(snapshot[i] &^ base[i])
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
var coverageSnapshot []byte
|
||||
// hasCoverageBit returns true if snapshot has at least one bit set that is
|
||||
// also set in base.
|
||||
func hasCoverageBit(base, snapshot []byte) bool {
|
||||
for i := range snapshot {
|
||||
if snapshot[i]&base[i] != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func countBits(cov []byte) int {
|
||||
n := 0
|
||||
for _, c := range cov {
|
||||
n += bits.OnesCount8(c)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
var coverageSnapshot = make([]byte, len(coverage()))
|
||||
|
||||
// _counters and _ecounters mark the start and end, respectively, of where
|
||||
// the 8-bit coverage counters reside in memory. They're known to cmd/link,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue