aboutsummaryrefslogtreecommitdiffstats
path: root/prog/prio.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2021-01-05 10:35:30 +0100
committerDmitry Vyukov <dvyukov@google.com>2021-01-05 11:15:55 +0100
commit270cde8ebe422a3197eec97faf00d3f10b0b0148 (patch)
tree3b534453949994c2a17ba6a02a2b0ee07cebd792 /prog/prio.go
parenta0234d980eccaa87f5821ac8e95ed9c94a104acf (diff)
prog: make priority calculation faster
Switch from float32 to int32. Float32 is super slow in arm emulation. Plus flats are generally non-deterministic due to order of operations, so we needed to do additional sorts to deal with that. Now we don't.
Diffstat (limited to 'prog/prio.go')
-rw-r--r--prog/prio.go120
1 files changed, 44 insertions, 76 deletions
diff --git a/prog/prio.go b/prog/prio.go
index 25ecfd41a..2c3436151 100644
--- a/prog/prio.go
+++ b/prog/prio.go
@@ -24,38 +24,27 @@ import (
// Note: the current implementation is very basic, there is no theory behind any
// constants.
-func (target *Target) CalculatePriorities(corpus []*Prog) [][]float32 {
+func (target *Target) CalculatePriorities(corpus []*Prog) [][]int32 {
static := target.calcStaticPriorities()
if len(corpus) != 0 {
dynamic := target.calcDynamicPrio(corpus)
for i, prios := range dynamic {
+ dst := static[i]
for j, p := range prios {
- static[i][j] *= p
+ dst[j] = dst[j] * p / prioHigh
}
}
}
return static
}
-func (target *Target) calcStaticPriorities() [][]float32 {
+func (target *Target) calcStaticPriorities() [][]int32 {
uses := target.calcResourceUsage()
- prios := make([][]float32, len(target.Syscalls))
+ prios := make([][]int32, len(target.Syscalls))
for i := range prios {
- prios[i] = make([]float32, len(target.Syscalls))
+ prios[i] = make([]int32, len(target.Syscalls))
}
- var keys []string
- for key := range uses {
- keys = append(keys, key)
- }
- sort.Strings(keys)
- for _, key := range keys {
- weights := make([]weights, 0, len(uses[key]))
- for _, weight := range uses[key] {
- weights = append(weights, weight)
- }
- sort.Slice(weights, func(i, j int) bool {
- return weights[i].call < weights[j].call
- })
+ for _, weights := range uses {
for _, w0 := range weights {
for _, w1 := range weights {
if w0.call == w1.call {
@@ -64,14 +53,14 @@ func (target *Target) calcStaticPriorities() [][]float32 {
}
// The static priority is assigned based on the direction of arguments. A higher priority will be
// assigned when c0 is a call that produces a resource and c1 a call that uses that resource.
- prios[w0.call][w1.call] += w0.inout*w1.in + 0.7*w0.inout*w1.inout
+ prios[w0.call][w1.call] += w0.inout*w1.in*3/2 + w0.inout*w1.inout
}
}
}
normalizePrio(prios)
// The value assigned for self-priority (call wrt itself) have to be high, but not too high.
for c0, pp := range prios {
- pp[c0] = 0.9
+ pp[c0] = prioHigh * 9 / 10
}
return prios
}
@@ -83,42 +72,42 @@ func (target *Target) calcResourceUsage() map[string]map[int]weights {
switch a := t.(type) {
case *ResourceType:
if target.AuxResources[a.Desc.Name] {
- noteUsage(uses, c, 0.1, ctx.Dir, "res%v", a.Desc.Name)
+ noteUsage(uses, c, 1, ctx.Dir, "res%v", a.Desc.Name)
} else {
str := "res"
for i, k := range a.Desc.Kind {
str += "-" + k
- w := 1.0
+ w := int32(10)
if i < len(a.Desc.Kind)-1 {
- w = 0.2
+ w = 2
}
- noteUsage(uses, c, float32(w), ctx.Dir, str)
+ noteUsage(uses, c, w, ctx.Dir, str)
}
}
case *PtrType:
if _, ok := a.Elem.(*StructType); ok {
- noteUsage(uses, c, 1.0, ctx.Dir, "ptrto-%v", a.Elem.Name())
+ noteUsage(uses, c, 10, ctx.Dir, "ptrto-%v", a.Elem.Name())
}
if _, ok := a.Elem.(*UnionType); ok {
- noteUsage(uses, c, 1.0, ctx.Dir, "ptrto-%v", a.Elem.Name())
+ noteUsage(uses, c, 10, ctx.Dir, "ptrto-%v", a.Elem.Name())
}
if arr, ok := a.Elem.(*ArrayType); ok {
- noteUsage(uses, c, 1.0, ctx.Dir, "ptrto-%v", arr.Elem.Name())
+ noteUsage(uses, c, 10, ctx.Dir, "ptrto-%v", arr.Elem.Name())
}
case *BufferType:
switch a.Kind {
case BufferBlobRand, BufferBlobRange, BufferText:
case BufferString:
if a.SubKind != "" {
- noteUsage(uses, c, 0.2, ctx.Dir, fmt.Sprintf("str-%v", a.SubKind))
+ noteUsage(uses, c, 2, ctx.Dir, fmt.Sprintf("str-%v", a.SubKind))
}
case BufferFilename:
- noteUsage(uses, c, 1.0, DirIn, "filename")
+ noteUsage(uses, c, 10, DirIn, "filename")
default:
panic("unknown buffer kind")
}
case *VmaType:
- noteUsage(uses, c, 0.5, ctx.Dir, "vma")
+ noteUsage(uses, c, 5, ctx.Dir, "vma")
case *IntType:
switch a.Kind {
case IntPlain, IntRange:
@@ -132,11 +121,11 @@ func (target *Target) calcResourceUsage() map[string]map[int]weights {
type weights struct {
call int
- in float32
- inout float32
+ in int32
+ inout int32
}
-func noteUsage(uses map[string]map[int]weights, c *Syscall, weight float32, dir Dir, str string, args ...interface{}) {
+func noteUsage(uses map[string]map[int]weights, c *Syscall, weight int32, dir Dir, str string, args ...interface{}) {
id := fmt.Sprintf(str, args...)
if uses[id] == nil {
uses[id] = make(map[int]weights)
@@ -154,17 +143,15 @@ func noteUsage(uses map[string]map[int]weights, c *Syscall, weight float32, dir
uses[id][c.ID] = callWeight
}
-func (target *Target) calcDynamicPrio(corpus []*Prog) [][]float32 {
- prios := make([][]float32, len(target.Syscalls))
+func (target *Target) calcDynamicPrio(corpus []*Prog) [][]int32 {
+ prios := make([][]int32, len(target.Syscalls))
for i := range prios {
- prios[i] = make([]float32, len(target.Syscalls))
+ prios[i] = make([]int32, len(target.Syscalls))
}
for _, p := range corpus {
for idx0, c0 := range p.Calls {
for _, c1 := range p.Calls[idx0+1:] {
- id0 := c0.Meta.ID
- id1 := c1.Meta.ID
- prios[id0][id1] += 1.0
+ prios[c0.Meta.ID][c1.Meta.ID]++
}
}
}
@@ -172,43 +159,22 @@ func (target *Target) calcDynamicPrio(corpus []*Prog) [][]float32 {
return prios
}
-// normalizePrio assigns some minimal priorities to calls with zero priority,
-// and then normalizes priorities to 0.1..1 range.
-func normalizePrio(prios [][]float32) {
+const (
+ prioLow = 10
+ prioHigh = 1000
+)
+
+// normalizePrio normalizes priorities to [prioLow..prioHigh] range.
+func normalizePrio(prios [][]int32) {
for _, prio := range prios {
- max := float32(0)
- min := float32(1e10)
- nzero := 0
+ max := int32(1)
for _, p := range prio {
if max < p {
max = p
}
- if p != 0 && min > p {
- min = p
- }
- if p == 0 {
- nzero++
- }
- }
- if nzero != 0 {
- min /= 2 * float32(nzero)
- }
- if min == max {
- max = 0
}
for i, p := range prio {
- if max == 0 {
- prio[i] = 1
- continue
- }
- if p == 0 {
- p = min
- }
- p = (p-min)/(max-min)*0.9 + 0.1
- if p > 1 {
- p = 1
- }
- prio[i] = p
+ prio[i] = prioLow + p*(prioHigh-prioLow)/max
}
}
}
@@ -217,7 +183,7 @@ func normalizePrio(prios [][]float32) {
// based on call-to-call priorities and a set of enabled syscalls.
type ChoiceTable struct {
target *Target
- runs [][]int
+ runs [][]int32
calls []*Syscall
}
@@ -252,16 +218,16 @@ func (target *Target) BuildChoiceTable(corpus []*Prog, enabled map[*Syscall]bool
}
}
prios := target.CalculatePriorities(corpus)
- run := make([][]int, len(target.Syscalls))
+ run := make([][]int32, len(target.Syscalls))
for i := range run {
if !enabled[target.Syscalls[i]] {
continue
}
- run[i] = make([]int, len(target.Syscalls))
- sum := 0
+ run[i] = make([]int32, len(target.Syscalls))
+ var sum int32
for j := range run[i] {
if enabled[target.Syscalls[j]] {
- sum += int(prios[i][j] * 1000)
+ sum += prios[i][j]
}
run[i][j] = sum
}
@@ -282,8 +248,10 @@ func (ct *ChoiceTable) choose(r *rand.Rand, bias int) int {
panic("disabled syscall")
}
run := ct.runs[bias]
- x := r.Intn(run[len(run)-1]) + 1
- res := sort.SearchInts(run, x)
+ x := int32(r.Intn(int(run[len(run)-1])) + 1)
+ res := sort.Search(len(run), func(i int) bool {
+ return run[i] >= x
+ })
if !ct.Enabled(res) {
panic("selected disabled syscall")
}