aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pkg/csource/csource.go2
-rw-r--r--prog/decodeexec.go69
-rw-r--r--prog/encoding_test.go4
-rw-r--r--prog/encodingexec_test.go10
-rw-r--r--prog/test/fuzz.go2
5 files changed, 54 insertions, 33 deletions
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index 53821a854..96237e64b 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -244,7 +244,7 @@ func (ctx *context) generateProgCalls(p *prog.Prog, trace bool) ([]string, []uin
if err != nil {
return nil, nil, fmt.Errorf("failed to serialize program: %w", err)
}
- decoded, err := ctx.target.DeserializeExec(exec[:progSize])
+ decoded, err := ctx.target.DeserializeExec(exec[:progSize], nil)
if err != nil {
return nil, nil, err
}
diff --git a/prog/decodeexec.go b/prog/decodeexec.go
index 2113d24c7..2356e051b 100644
--- a/prog/decodeexec.go
+++ b/prog/decodeexec.go
@@ -7,6 +7,7 @@ import (
"encoding/binary"
"fmt"
"reflect"
+ "strings"
)
type ExecProg struct {
@@ -71,8 +72,8 @@ type ExecCsumChunk struct {
Size uint64
}
-func (target *Target) DeserializeExec(exec []byte) (ExecProg, error) {
- dec := &execDecoder{target: target, data: exec}
+func (target *Target) DeserializeExec(exec []byte, stats map[string]int) (ExecProg, error) {
+ dec := &execDecoder{target: target, data: exec, stats: stats}
dec.parse()
if dec.err != nil {
return ExecProg{}, dec.err
@@ -96,22 +97,23 @@ type execDecoder struct {
vars []uint64
call ExecCall
calls []ExecCall
+ stats map[string]int
}
func (dec *execDecoder) parse() {
for dec.err == nil {
- switch instr := dec.read(); instr {
+ switch instr := dec.read("instr/opcode"); instr {
case execInstrCopyin:
dec.commitCall()
dec.call.Copyin = append(dec.call.Copyin, ExecCopyin{
- Addr: dec.read() + dec.target.DataOffset,
+ Addr: dec.read("instr/copyin") + dec.target.DataOffset,
Arg: dec.readArg(),
})
case execInstrCopyout:
dec.call.Copyout = append(dec.call.Copyout, ExecCopyout{
- Index: dec.read(),
- Addr: dec.read() + dec.target.DataOffset,
- Size: dec.read(),
+ Index: dec.read("instr/copyout/index"),
+ Addr: dec.read("instr/copyout/addr") + dec.target.DataOffset,
+ Size: dec.read("instr/copyout/size"),
})
case execInstrEOF:
dec.commitCall()
@@ -126,8 +128,8 @@ func (dec *execDecoder) parse() {
return
}
dec.call.Meta = dec.target.Syscalls[instr]
- dec.call.Index = dec.read()
- for i := dec.read(); i > 0; i-- {
+ dec.call.Index = dec.read("instr/index")
+ for i := dec.read("instr/nargs"); i > 0; i-- {
switch arg := dec.readArg(); arg.(type) {
case ExecArgConst, ExecArgResult:
dec.call.Args = append(dec.call.Args, arg)
@@ -142,7 +144,7 @@ func (dec *execDecoder) parse() {
func (dec *execDecoder) readCallProps(props *CallProps) {
props.ForeachProp(func(_, _ string, value reflect.Value) {
- arg := dec.read()
+ arg := dec.read("call prop")
switch kind := value.Kind(); kind {
case reflect.Int:
value.SetInt(int64(arg))
@@ -157,11 +159,11 @@ func (dec *execDecoder) readCallProps(props *CallProps) {
}
func (dec *execDecoder) readArg() ExecArg {
- switch typ := dec.read(); typ {
+ switch typ := dec.read("arg/type"); typ {
case execArgConst:
- meta := dec.read()
+ meta := dec.read("arg/const/meta")
return ExecArgConst{
- Value: dec.read(),
+ Value: dec.read("arg/const/value"),
Size: meta & 0xff,
Format: BinaryFormat((meta >> 8) & 0xff),
BitfieldOffset: (meta >> 16) & 0xff,
@@ -176,18 +178,18 @@ func (dec *execDecoder) readArg() ExecArg {
size = 8
}
return ExecArgConst{
- Value: dec.read() + dec.target.DataOffset,
+ Value: dec.read("arg/addr") + dec.target.DataOffset,
Size: uint64(size),
}
case execArgResult:
- meta := dec.read()
+ meta := dec.read("arg/result/meta")
arg := ExecArgResult{
Size: meta & 0xff,
Format: BinaryFormat((meta >> 8) & 0xff),
- Index: dec.read(),
- DivOp: dec.read(),
- AddOp: dec.read(),
- Default: dec.read(),
+ Index: dec.read("arg/result/index"),
+ DivOp: dec.read("arg/result/divop"),
+ AddOp: dec.read("arg/result/addop"),
+ Default: dec.read("arg/result/default"),
}
for uint64(len(dec.vars)) <= arg.Index {
dec.vars = append(dec.vars, 0)
@@ -195,22 +197,23 @@ func (dec *execDecoder) readArg() ExecArg {
dec.vars[arg.Index] = arg.Default
return arg
case execArgData:
- flags := dec.read()
+ flags := dec.read("arg/data/size")
size := flags & ^execArgDataReadable
+ dec.addStat("arg/data/blob", int(size))
readable := flags&execArgDataReadable != 0
return ExecArgData{
Data: dec.readBlob(size),
Readable: readable,
}
case execArgCsum:
- size := dec.read()
- switch kind := dec.read(); kind {
+ size := dec.read("arg/csum/size")
+ switch kind := dec.read("arg/csum/kind"); kind {
case ExecArgCsumInet:
- chunks := make([]ExecCsumChunk, dec.read())
+ chunks := make([]ExecCsumChunk, dec.read("arg/csum/chunks"))
for i := range chunks {
- kind := dec.read()
- addr := dec.read()
- size := dec.read()
+ kind := dec.read("arg/csum/chunk/kind")
+ addr := dec.read("arg/csum/chunk/addr")
+ size := dec.read("arg/csum/chunk/size")
if kind == ExecArgCsumChunkData {
addr += dec.target.DataOffset
}
@@ -235,7 +238,7 @@ func (dec *execDecoder) readArg() ExecArg {
}
}
-func (dec *execDecoder) read() uint64 {
+func (dec *execDecoder) read(stat string) uint64 {
if dec.err != nil {
return 0
}
@@ -244,6 +247,7 @@ func (dec *execDecoder) read() uint64 {
dec.setErr(fmt.Errorf("exec program overflow"))
return 0
}
+ dec.addStat(stat, n)
dec.data = dec.data[n:]
return uint64(v)
}
@@ -281,3 +285,14 @@ func (dec *execDecoder) commitCall() {
dec.calls = append(dec.calls, dec.call)
dec.call = ExecCall{}
}
+
+func (dec *execDecoder) addStat(stat string, n int) {
+ if dec.stats == nil {
+ return
+ }
+ prefix := ""
+ for _, part := range strings.Split(stat, "/") {
+ dec.stats[prefix+part] += n
+ prefix += part + "/"
+ }
+}
diff --git a/prog/encoding_test.go b/prog/encoding_test.go
index 42f16036c..e5d5a2d38 100644
--- a/prog/encoding_test.go
+++ b/prog/encoding_test.go
@@ -404,11 +404,11 @@ func TestSerializeDeserializeRandom(t *testing.T) {
if ok {
t.Log("flaky?")
}
- decoded0, err := target.DeserializeExec(data0[:n0])
+ decoded0, err := target.DeserializeExec(data0[:n0], nil)
if err != nil {
t.Fatal(err)
}
- decoded1, err := target.DeserializeExec(data1[:n1])
+ decoded1, err := target.DeserializeExec(data1[:n1], nil)
if err != nil {
t.Fatal(err)
}
diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go
index 1b34f4cab..68e42f07e 100644
--- a/prog/encodingexec_test.go
+++ b/prog/encodingexec_test.go
@@ -19,16 +19,19 @@ func TestSerializeForExecRandom(t *testing.T) {
buf := make([]byte, ExecBufferSize)
execSizes := histogram.New(1000)
textSizes := histogram.New(1000)
+ totalSize := 0
+ sizes := make(map[string]int)
for i := 0; i < iters; i++ {
p := target.Generate(rs, 10, ct)
n, err := p.SerializeForExec(buf)
if err != nil {
t.Fatalf("failed to serialize: %v", err)
}
- _, err = target.DeserializeExec(buf[:n])
+ _, err = target.DeserializeExec(buf[:n], sizes)
if err != nil {
t.Fatal(err)
}
+ totalSize += n
execSizes.Add(float64(n))
textSizes.Add(float64(len(p.Serialize())))
}
@@ -36,6 +39,9 @@ func TestSerializeForExecRandom(t *testing.T) {
int(execSizes.Quantile(0.1)), int(execSizes.Quantile(0.5)), int(execSizes.Quantile(0.9)))
t.Logf("text sizes: 10%%:%v 50%%:%v 90%%:%v",
int(textSizes.Quantile(0.1)), int(textSizes.Quantile(0.5)), int(textSizes.Quantile(0.9)))
+ for what, size := range sizes {
+ t.Logf("%-24v: %5.2f%%", what, float64(size)/float64(totalSize)*100)
+ }
}
// nolint: funlen
@@ -675,7 +681,7 @@ test$res1(r0)
t.Logf("got: %q", data)
t.Fatalf("mismatch")
}
- decoded, err := target.DeserializeExec(data)
+ decoded, err := target.DeserializeExec(data, nil)
if err != nil {
t.Fatal(err)
}
diff --git a/prog/test/fuzz.go b/prog/test/fuzz.go
index 5857ff98d..354d6c3cd 100644
--- a/prog/test/fuzz.go
+++ b/prog/test/fuzz.go
@@ -49,7 +49,7 @@ func FuzzDeserialize(data []byte) int {
panic("got different data")
}
if n, err := p0.SerializeForExec(fuzzBuffer); err == nil {
- if _, err := fuzzTarget.DeserializeExec(fuzzBuffer[:n]); err != nil {
+ if _, err := fuzzTarget.DeserializeExec(fuzzBuffer[:n], nil); err != nil {
panic(err)
}
}