Memory and CPU profiling

graph-rework
noah metz 2023-06-04 17:23:49 -06:00
parent cdc682f844
commit bfd295b3db
5 changed files with 105 additions and 39 deletions

@ -1,4 +1,4 @@
module graphvent module git.metznet.ca/MetzNet/graphvent
go 1.20 go 1.20

@ -75,6 +75,7 @@ type GraphSignal interface {
Time() time.Time Time() time.Time
Last() string Last() string
Trace(id string) GraphSignal Trace(id string) GraphSignal
String() string
} }
type BaseSignal struct { type BaseSignal struct {
@ -85,6 +86,15 @@ type BaseSignal struct {
last_id string last_id string
} }
func (signal BaseSignal) String() string {
source_name := "nil"
source := signal.source
if source != nil {
source_name = source.Name()
}
return fmt.Sprintf("{type: %s, description: %s, source: %s, last: %s}", signal.signal_type, signal.description, source_name, signal.last_id)
}
func (signal BaseSignal) Time() time.Time { func (signal BaseSignal) Time() time.Time {
return signal.time return signal.time
} }
@ -136,7 +146,7 @@ func NewBaseNode(name string, description string, id string) BaseNode {
name: name, name: name,
description: description, description: description,
id: id, id: id,
signal: make(chan GraphSignal, 1000), signal: make(chan GraphSignal, 512),
listeners: map[chan GraphSignal]chan GraphSignal{}, listeners: map[chan GraphSignal]chan GraphSignal{},
} }
log.Logf("graph", "NEW_NODE: %s - %s", node.ID(), node.Name()) log.Logf("graph", "NEW_NODE: %s - %s", node.ID(), node.Name())
@ -225,12 +235,17 @@ func (node * BaseNode) update(signal GraphSignal) {
} }
func SendUpdate(node GraphNode, signal GraphSignal) { func SendUpdate(node GraphNode, signal GraphSignal) {
if signal.Source() != nil { source := signal.Source()
log.Logf("update", "UPDATE %s -> %s: %+v", signal.Source().Name(), node.Name(), signal) source_name := "nil"
} else { if source != nil {
log.Logf("update", "UPDATE %s: %+v", node.Name(), signal) source_name = source.Name()
}
node_name := "nil"
if node != nil {
node_name = node.Name()
} }
log.Logf("update", "UPDATE %s -> %s: %+v", source_name, node_name, signal)
node.UpdateListeners(signal) node.UpdateListeners(signal)
node.update(signal) node.update(signal)
} }

@ -2,6 +2,8 @@ package main
import ( import (
"time" "time"
"runtime/pprof"
"os"
) )
func fake_team(org string, id string, names []string) (*Team, []*Member) { func fake_team(org string, id string, names []string) (*Team, []*Member) {
@ -13,7 +15,7 @@ func fake_team(org string, id string, names []string) (*Team, []*Member) {
return team, members return team, members
} }
func fake_data() (* EventManager, []*Arena, []*Arena) { func fake_data() (* EventManager, []Arena, []Arena) {
resources := []Resource{} resources := []Resource{}
teams_div1 := []*Team{} teams_div1 := []*Team{}
@ -69,10 +71,10 @@ func fake_data() (* EventManager, []*Arena, []*Arena) {
resources = append(resources, m15[0]) resources = append(resources, m15[0])
resources = append(resources, m16[0]) resources = append(resources, m16[0])
arenas_div1 := []*Arena{} arenas_div1 := []Arena{}
arenas_div1 = append(arenas_div1, NewVirtualArena("Arena 1")) arenas_div1 = append(arenas_div1, NewVirtualArena("Arena 1"))
arenas_div1 = append(arenas_div1, NewVirtualArena("Arena 2")) arenas_div1 = append(arenas_div1, NewVirtualArena("Arena 2"))
arenas_div2 := []*Arena{} arenas_div2 := []Arena{}
arenas_div2 = append(arenas_div2, NewVirtualArena("Arena 3")) arenas_div2 = append(arenas_div2, NewVirtualArena("Arena 3"))
arenas_div2 = append(arenas_div2, NewVirtualArena("Arena 4")) arenas_div2 = append(arenas_div2, NewVirtualArena("Arena 4"))
@ -167,12 +169,12 @@ func fake_data() (* EventManager, []*Arena, []*Arena) {
type FakeClient struct { type FakeClient struct {
state string state string
start time.Time start time.Time
arena * Arena arena Arena
update chan GraphSignal update chan GraphSignal
games_done int games_done int
} }
func NewFakeClient(arena *Arena) * FakeClient { func NewFakeClient(arena Arena) * FakeClient {
client := &FakeClient{ client := &FakeClient{
state: "init", state: "init",
start: time.Now(), start: time.Now(),
@ -187,7 +189,7 @@ func NewFakeClient(arena *Arena) * FakeClient {
func (client * FakeClient) process_update(update GraphSignal) { func (client * FakeClient) process_update(update GraphSignal) {
arena := client.arena arena := client.arena
if update.Source() != nil { if update.Source() != nil {
log.Logf("test", "FAKE_CLIENT_UPDATE: %s -> %+v", update.Source().ID(), update) log.Logf("test", "FAKE_CLIENT_UPDATE: %s -> %+v", update.Source().Name(), update)
} else { } else {
log.Logf("test", "FAKE_CLIENT_UPDATE: nil -> %+v", update) log.Logf("test", "FAKE_CLIENT_UPDATE: nil -> %+v", update)
} }
@ -236,12 +238,27 @@ func (client * FakeClient) process_update(update GraphSignal) {
func main() { func main() {
event_manager, arenas_div1, arenas_div2 := fake_data() event_manager, arenas_div1, arenas_div2 := fake_data()
go func() {
cpufile, err := os.OpenFile("graphvent.cpu", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
panic("Failed to open cpu profile file")
}
memfile, err := os.OpenFile("graphvent.mem", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
panic("Failed to open mem profile file")
}
pprof.StartCPUProfile(cpufile)
time.Sleep(3000 * time.Millisecond)
pprof.WriteHeapProfile(memfile)
}()
// Fake arena clients // Fake arena clients
arena_1_client := NewFakeClient(arenas_div1[0]) arena_1_client := NewFakeClient(arenas_div1[0])
arena_2_client := NewFakeClient(arenas_div1[1]) arena_2_client := NewFakeClient(arenas_div1[1])
arena_3_client := NewFakeClient(arenas_div2[0]) arena_3_client := NewFakeClient(arenas_div2[0])
arena_4_client := NewFakeClient(arenas_div2[1]) arena_4_client := NewFakeClient(arenas_div2[1])
go func() { go func() {
for true { for true {
select { select {
@ -267,4 +284,5 @@ func main() {
log.Logf("test", "Client 3 games: %d", arena_3_client.games_done) log.Logf("test", "Client 3 games: %d", arena_3_client.games_done)
log.Logf("test", "Client 4 games: %d", arena_4_client.games_done) log.Logf("test", "Client 4 games: %d", arena_4_client.games_done)
} }
pprof.StopCPUProfile()
} }

@ -14,11 +14,17 @@ func (resource * BaseResource) update(signal GraphSignal) {
for _, parent := range resource.Parents() { for _, parent := range resource.Parents() {
SendUpdate(parent, new_signal) SendUpdate(parent, new_signal)
} }
resource.lock_holder_lock.Lock()
if resource.lock_holder != nil { if resource.lock_holder != nil {
if resource.lock_holder.ID() != signal.Last() { if resource.lock_holder.ID() != signal.Last() {
SendUpdate(resource.lock_holder, new_signal) lock_holder := resource.lock_holder
resource.lock_holder_lock.Unlock()
SendUpdate(lock_holder, new_signal)
} else {
resource.lock_holder_lock.Unlock()
} }
} else {
resource.lock_holder_lock.Unlock()
} }
} }
@ -29,7 +35,7 @@ func (resource * BaseResource) update(signal GraphSignal) {
// The device connection should be maintained as much as possible(requiring some reconnection behaviour in the background) // The device connection should be maintained as much as possible(requiring some reconnection behaviour in the background)
type Resource interface { type Resource interface {
GraphNode GraphNode
Owner() Event Owner() GraphNode
Children() []Resource Children() []Resource
Parents() []Resource Parents() []Resource
@ -37,12 +43,12 @@ type Resource interface {
LockParents() LockParents()
UnlockParents() UnlockParents()
SetOwner(owner Event) SetOwner(owner GraphNode)
LockState() LockState()
UnlockState() UnlockState()
lock(event Event) error lock(node GraphNode) error
unlock(event Event) error unlock(node GraphNode) error
Connect(abort chan error) bool Connect(abort chan error) bool
} }
@ -106,7 +112,7 @@ func UnlockResource(resource Resource, event Event) error {
return nil return nil
} }
func LockResource(resource Resource, event Event) error { func LockResource(resource Resource, node GraphNode) error {
resource.LockState() resource.LockState()
if resource.Owner() != nil { if resource.Owner() != nil {
resource.UnlockState() resource.UnlockState()
@ -114,7 +120,7 @@ func LockResource(resource Resource, event Event) error {
return errors.New(err_str) return errors.New(err_str)
} }
err := resource.lock(event) err := resource.lock(node)
if err != nil { if err != nil {
resource.UnlockState() resource.UnlockState()
err_str := fmt.Sprintf("Failed to lock resource: %s", err) err_str := fmt.Sprintf("Failed to lock resource: %s", err)
@ -124,7 +130,7 @@ func LockResource(resource Resource, event Event) error {
var lock_err error = nil var lock_err error = nil
locked_resources := []Resource{} locked_resources := []Resource{}
for _, child := range resource.Children() { for _, child := range resource.Children() {
err := LockResource(child, event) err := LockResource(child, node)
if err != nil{ if err != nil{
lock_err = err lock_err = err
break break
@ -138,7 +144,7 @@ func LockResource(resource Resource, event Event) error {
return errors.New(err_str) return errors.New(err_str)
} }
resource.SetOwner(event) resource.SetOwner(node)
resource.UnlockState() resource.UnlockState()
@ -175,12 +181,15 @@ type BaseResource struct {
parents_lock sync.Mutex parents_lock sync.Mutex
children []Resource children []Resource
children_lock sync.Mutex children_lock sync.Mutex
lock_holder Event lock_holder GraphNode
lock_holder_lock sync.Mutex
state_lock sync.Mutex state_lock sync.Mutex
} }
func (resource * BaseResource) SetOwner(owner Event) { func (resource * BaseResource) SetOwner(owner GraphNode) {
resource.lock_holder_lock.Lock()
resource.lock_holder = owner resource.lock_holder = owner
resource.lock_holder_lock.Unlock()
} }
func (resource * BaseResource) LockState() { func (resource * BaseResource) LockState() {
@ -195,16 +204,16 @@ func (resource * BaseResource) Connect(abort chan error) bool {
return false return false
} }
func (resource * BaseResource) Owner() Event { func (resource * BaseResource) Owner() GraphNode {
return resource.lock_holder return resource.lock_holder
} }
//BaseResources don't check anything special when locking/unlocking //BaseResources don't check anything special when locking/unlocking
func (resource * BaseResource) lock(event Event) error { func (resource * BaseResource) lock(node GraphNode) error {
return nil return nil
} }
func (resource * BaseResource) unlock(event Event) error { func (resource * BaseResource) unlock(node GraphNode) error {
return nil return nil
} }

@ -63,13 +63,17 @@ func NewAlliance(team0 * Team, team1 * Team) * Alliance {
return resource return resource
} }
type Arena struct { type Arena interface {
Resource
}
type VirtualArena struct {
BaseResource BaseResource
connected bool connected bool
} }
func NewVirtualArena(name string) * Arena { func NewVirtualArena(name string) * VirtualArena {
arena := &Arena{ arena := &VirtualArena{
BaseResource: NewBaseResource(name, "A virtual vex arena", []Resource{}), BaseResource: NewBaseResource(name, "A virtual vex arena", []Resource{}),
connected: false, connected: false,
} }
@ -77,7 +81,7 @@ func NewVirtualArena(name string) * Arena {
return arena return arena
} }
func (arena * Arena) lock(event Event) error { func (arena * VirtualArena) lock(node GraphNode) error {
if arena.connected == false { if arena.connected == false {
log.Logf("vex", "ARENA NOT CONNECTED: %s", arena.Name()) log.Logf("vex", "ARENA NOT CONNECTED: %s", arena.Name())
error_str := fmt.Sprintf("%s is not connected, cannot lock", arena.Name()) error_str := fmt.Sprintf("%s is not connected, cannot lock", arena.Name())
@ -86,15 +90,15 @@ func (arena * Arena) lock(event Event) error {
return nil return nil
} }
func (arena * Arena) update(signal GraphSignal) { func (arena * VirtualArena) update(signal GraphSignal) {
log.Logf("vex", "ARENA_UPDATE: %s", arena.Name()) log.Logf("vex", "ARENA_UPDATE: %s", arena.Name())
arena.signal <- signal arena.signal <- signal
arena.BaseResource.update(signal) arena.BaseResource.update(signal)
} }
func (arena * Arena) Connect(abort chan error) bool { func (arena * VirtualArena) Connect(abort chan error) bool {
log.Logf("vex", "Connecting %s", arena.Name()) log.Logf("vex", "Connecting %s", arena.Name())
go func(arena * Arena, abort chan error) { go func(arena * VirtualArena, abort chan error) {
update_str := fmt.Sprintf("VIRTUAL_ARENA connected: %s", arena.Name()) update_str := fmt.Sprintf("VIRTUAL_ARENA connected: %s", arena.Name())
signal := NewSignal(arena, "resource_connected") signal := NewSignal(arena, "resource_connected")
signal.description = update_str signal.description = update_str
@ -114,13 +118,31 @@ func (arena * Arena) Connect(abort chan error) bool {
return true return true
} }
type VexEvent struct {
BaseEvent
}
func NewVexEvent(name string, description string) * VexEvent {
event := &VexEvent{
BaseEvent: NewBaseEvent(name, description, []Resource{}),
}
event.actions["wait"] = EventWait(event)
event.actions["start"] = func() (string, error) {
log.Logf("vex", "STARTING_VEX_TOURNAMENT %s", event.Name())
return "wait", nil
}
return event
}
const start_slack = 250 * time.Millisecond const start_slack = 250 * time.Millisecond
const TEMP_AUTON_TIME = time.Second * 1 const TEMP_AUTON_TIME = 250 * time.Millisecond
const TEMP_DRIVE_TIME = time.Second * 1 const TEMP_DRIVE_TIME = 250 * time.Millisecond
type Match struct { type Match struct {
BaseEvent BaseEvent
arena * Arena arena Arena
state string state string
control string control string
control_start time.Time control_start time.Time
@ -131,7 +153,7 @@ func (match * Match) update(signal GraphSignal) {
match.BaseEvent.update(new_signal) match.BaseEvent.update(new_signal)
} }
func NewMatch(alliance0 * Alliance, alliance1 * Alliance, arena * Arena) * Match { func NewMatch(alliance0 * Alliance, alliance1 * Alliance, arena Arena) * Match {
name := fmt.Sprintf("Match: %s vs. %s on %s", alliance0.Name(), alliance1.Name(), arena.Name()) name := fmt.Sprintf("Match: %s vs. %s on %s", alliance0.Name(), alliance1.Name(), arena.Name())
description := "A vex match" description := "A vex match"
@ -239,6 +261,8 @@ func NewMatch(alliance0 * Alliance, alliance1 * Alliance, arena * Arena) * Match
} }
match.actions["driver_done"] = func() (string, error) { match.actions["driver_done"] = func() (string, error) {
new_signal := NewSignal(match, "driver_done")
new_signal.time = time.Now()
SendUpdate(match, NewSignal(match, "driver_done")) SendUpdate(match, NewSignal(match, "driver_done"))
return "wait", nil return "wait", nil
} }