aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/rpcserver/last_executing.go
blob: 341ae6534cbbb93b20cc69a4d91ee402bb4e9fa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// Copyright 2024 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package rpcserver

import (
	"sort"
	"time"
)

// LastExecuting keeps the given number of last executed programs
// for each proc in a VM, and allows to query this set after a crash.
type LastExecuting struct {
	count     int
	procs     []ExecRecord
	positions []int
}

type ExecRecord struct {
	ID   int
	Proc int
	Prog []byte
	Time time.Duration
}

func MakeLastExecuting(procs, count int) *LastExecuting {
	return &LastExecuting{
		count:     count,
		procs:     make([]ExecRecord, procs*count),
		positions: make([]int, procs),
	}
}

// Note execution of the 'prog' on 'proc' at time 'now'.
func (last *LastExecuting) Note(id, proc int, prog []byte, now time.Duration) {
	pos := &last.positions[proc]
	last.procs[proc*last.count+*pos] = ExecRecord{
		ID:   id,
		Proc: proc,
		Prog: prog,
		Time: now,
	}
	*pos++
	if *pos == last.count {
		*pos = 0
	}
}

// Returns a sorted set of last executing programs.
// The records are sorted by time in ascending order.
// ExecRecord.Time is the difference in start executing time between this
// program and the program that started executing last.
func (last *LastExecuting) Collect() []ExecRecord {
	procs := last.procs
	last.procs = nil // The type must not be used after this.
	sort.Slice(procs, func(i, j int) bool {
		return procs[i].Time < procs[j].Time
	})
	max := procs[len(procs)-1].Time
	for i := len(procs) - 1; i >= 0; i-- {
		if procs[i].Time == 0 {
			procs = procs[i+1:]
			break
		}
		procs[i].Time = max - procs[i].Time
	}
	return procs
}