aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorAleksandr Nogikh <nogikh@google.com>2025-07-28 19:30:11 +0200
committerAleksandr Nogikh <nogikh@google.com>2025-07-29 08:30:56 +0000
commit5971223333d76c5f21de85038c78785ac766d696 (patch)
tree2a2e397a2638f4d81f617df35be9aec21569ce8a /prog
parentc4a9548758bac1c6dc231afd7543b5e8c5b6a65e (diff)
prog: generate choice table only for enabled calls
We used to generate a choice table and do its normalization for all present syscalls, also it was not considered during the /prio page generation. Enabled/disabled syscalls were accounted for in the choice table construction, but there's a chance that the resulting table was still somewhat skewed. The situation must have become worse after several thousands of auto syscalls were added.
Diffstat (limited to 'prog')
-rw-r--r--prog/prio.go124
-rw-r--r--prog/prio_test.go2
2 files changed, 80 insertions, 46 deletions
diff --git a/prog/prio.go b/prog/prio.go
index a18008271..b64a8a9e2 100644
--- a/prog/prio.go
+++ b/prog/prio.go
@@ -26,11 +26,14 @@ import (
// Note: the current implementation is very basic, there is no theory behind any
// constants.
-func (target *Target) CalculatePriorities(corpus []*Prog) [][]int32 {
- static := target.calcStaticPriorities()
+// CalculatePriorities returns the priority matrix as well as the map of generatable syscalls.
+// The rows/columns corresponding to the non-generatable syscalls are left to be 0.
+func (target *Target) CalculatePriorities(corpus []*Prog, enabled map[*Syscall]bool) ([][]int32, map[*Syscall]bool) {
+ enabled = target.prepareEnabledSyscalls(corpus, enabled)
+ static := target.calcStaticPriorities(enabled)
if len(corpus) != 0 {
// Let's just sum the static and dynamic distributions.
- dynamic := target.calcDynamicPrio(corpus)
+ dynamic := target.calcDynamicPrio(corpus, enabled)
for i, prios := range dynamic {
dst := static[i]
for j, p := range prios {
@@ -38,11 +41,58 @@ func (target *Target) CalculatePriorities(corpus []*Prog) [][]int32 {
}
}
}
- return static
+ if debug {
+ for _, syscall := range target.Syscalls {
+ if enabled[syscall] {
+ continue
+ }
+ for i := range static {
+ if static[i][syscall.ID] != 0 || static[syscall.ID][i] != 0 {
+ panic(fmt.Sprintf("prio matrix has non-zero value for a disabled syscall %d",
+ syscall.ID))
+ }
+ }
+ }
+ }
+ return static, enabled
+}
+
+func (target *Target) prepareEnabledSyscalls(corpus []*Prog, enabled map[*Syscall]bool) map[*Syscall]bool {
+ if enabled == nil {
+ enabled = make(map[*Syscall]bool)
+ for _, c := range target.Syscalls {
+ enabled[c] = true
+ }
+ }
+ noGenerateCalls := make(map[int]bool)
+ enabledCalls := make(map[*Syscall]bool)
+ for call := range enabled {
+ if call.Attrs.NoGenerate {
+ noGenerateCalls[call.ID] = true
+ } else if !call.Attrs.Disabled {
+ enabledCalls[call] = true
+ }
+ }
+ // Some validation checks.
+ if len(enabledCalls) == 0 {
+ panic("no syscalls enabled and generatable")
+ }
+ for _, p := range corpus {
+ for _, call := range p.Calls {
+ if !enabledCalls[call.Meta] && !noGenerateCalls[call.Meta.ID] {
+ fmt.Printf("corpus contains disabled syscall %v\n", call.Meta.Name)
+ for call := range enabled {
+ fmt.Printf("%s: enabled\n", call.Name)
+ }
+ panic("disabled syscall")
+ }
+ }
+ }
+ return enabledCalls
}
-func (target *Target) calcStaticPriorities() [][]int32 {
- uses := target.calcResourceUsage()
+func (target *Target) calcStaticPriorities(enabled map[*Syscall]bool) [][]int32 {
+ uses := target.calcResourceUsage(enabled)
prios := make([][]int32, len(target.Syscalls))
for i := range prios {
prios[i] = make([]int32, len(target.Syscalls))
@@ -61,22 +111,27 @@ func (target *Target) calcStaticPriorities() [][]int32 {
}
}
// The value assigned for self-priority (call wrt itself) have to be high, but not too high.
- for c0, pp := range prios {
+ for c := range enabled {
+ id, pp := c.ID, prios[c.ID]
max := slices.Max(pp)
if max == 0 {
- pp[c0] = 1
+ pp[id] = 1
} else {
- pp[c0] = max * 3 / 4
+ pp[id] = max * 3 / 4
}
}
- normalizePrios(prios)
+ normalizePrios(prios, len(enabled))
return prios
}
-func (target *Target) calcResourceUsage() map[string]map[int]weights {
+func (target *Target) calcResourceUsage(enabled map[*Syscall]bool) map[string]map[int]weights {
uses := make(map[string]map[int]weights)
ForeachType(target.Syscalls, func(t Type, ctx *TypeCtx) {
c := ctx.Meta
+ if !enabled[c] {
+ ctx.Stop = true
+ return
+ }
switch a := t.(type) {
case *ResourceType:
if target.AuxResources[a.Desc.Name] {
@@ -155,14 +210,20 @@ func noteUsagef(uses map[string]map[int]weights, c *Syscall, weight int32, dir D
uses[id][c.ID] = callWeight
}
-func (target *Target) calcDynamicPrio(corpus []*Prog) [][]int32 {
+func (target *Target) calcDynamicPrio(corpus []*Prog, enabled map[*Syscall]bool) [][]int32 {
prios := make([][]int32, len(target.Syscalls))
for i := range prios {
prios[i] = make([]int32, len(target.Syscalls))
}
for _, p := range corpus {
for idx0, c0 := range p.Calls {
+ if !enabled[c0.Meta] {
+ continue
+ }
for _, c1 := range p.Calls[idx0+1:] {
+ if !enabled[c1.Meta] {
+ continue
+ }
prios[c0.Meta.ID][c1.Meta.ID]++
}
}
@@ -175,13 +236,14 @@ func (target *Target) calcDynamicPrio(corpus []*Prog) [][]int32 {
prios[i][j] = int32(2.0 * math.Sqrt(float64(val)))
}
}
- normalizePrios(prios)
+ normalizePrios(prios, len(enabled))
return prios
}
// normalizePrio distributes |N| * 10 points proportional to the values in the matrix.
-func normalizePrios(prios [][]int32) {
- total := 10 * int32(len(prios))
+// |N| is the number of the generatable syscalls.
+func normalizePrios(prios [][]int32, n int) {
+ total := 10 * int32(n)
for _, prio := range prios {
sum := int32(0)
for _, p := range prio {
@@ -205,43 +267,15 @@ type ChoiceTable struct {
}
func (target *Target) BuildChoiceTable(corpus []*Prog, enabled map[*Syscall]bool) *ChoiceTable {
- if enabled == nil {
- enabled = make(map[*Syscall]bool)
- for _, c := range target.Syscalls {
- enabled[c] = true
- }
- }
- noGenerateCalls := make(map[int]bool)
- enabledCalls := make(map[*Syscall]bool)
- for call := range enabled {
- if call.Attrs.NoGenerate {
- noGenerateCalls[call.ID] = true
- } else if !call.Attrs.Disabled {
- enabledCalls[call] = true
- }
- }
+ prios, enabledCalls := target.CalculatePriorities(corpus, enabled)
var generatableCalls []*Syscall
for c := range enabledCalls {
generatableCalls = append(generatableCalls, c)
}
- if len(generatableCalls) == 0 {
- panic("no syscalls enabled and generatable")
- }
sort.Slice(generatableCalls, func(i, j int) bool {
return generatableCalls[i].ID < generatableCalls[j].ID
})
- for _, p := range corpus {
- for _, call := range p.Calls {
- if !enabledCalls[call.Meta] && !noGenerateCalls[call.Meta.ID] {
- fmt.Printf("corpus contains disabled syscall %v\n", call.Meta.Name)
- for call := range enabled {
- fmt.Printf("%s: enabled\n", call.Name)
- }
- panic("disabled syscall")
- }
- }
- }
- prios := target.CalculatePriorities(corpus)
+
run := make([][]int32, len(target.Syscalls))
// ChoiceTable.runs[][] contains cumulated sum of weighted priority numbers.
// This helps in quick binary search with biases when generating programs.
diff --git a/prog/prio_test.go b/prog/prio_test.go
index 93555818e..2e1208822 100644
--- a/prog/prio_test.go
+++ b/prog/prio_test.go
@@ -23,7 +23,7 @@ func TestNormalizePrios(t *testing.T) {
{10, 20, 0},
}
t.Logf("had: %+v", prios)
- normalizePrios(prios)
+ normalizePrios(prios, len(prios))
if !reflect.DeepEqual(prios, want) {
t.Logf("got: %+v", prios)
t.Errorf("want: %+v", want)