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

@ -75,6 +75,7 @@ type GraphSignal interface {
Time() time.Time
Last() string
Trace(id string) GraphSignal
String() string
}
type BaseSignal struct {
@ -85,6 +86,15 @@ type BaseSignal struct {
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 {
return signal.time
}
@ -136,7 +146,7 @@ func NewBaseNode(name string, description string, id string) BaseNode {
name: name,
description: description,
id: id,
signal: make(chan GraphSignal, 1000),
signal: make(chan GraphSignal, 512),
listeners: map[chan GraphSignal]chan GraphSignal{},
}
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) {
if signal.Source() != nil {
log.Logf("update", "UPDATE %s -> %s: %+v", signal.Source().Name(), node.Name(), signal)
} else {
log.Logf("update", "UPDATE %s: %+v", node.Name(), signal)
source := signal.Source()
source_name := "nil"
if source != nil {
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.update(signal)
}

@ -2,6 +2,8 @@ package main
import (
"time"
"runtime/pprof"
"os"
)
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
}
func fake_data() (* EventManager, []*Arena, []*Arena) {
func fake_data() (* EventManager, []Arena, []Arena) {
resources := []Resource{}
teams_div1 := []*Team{}
@ -69,10 +71,10 @@ func fake_data() (* EventManager, []*Arena, []*Arena) {
resources = append(resources, m15[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 2"))
arenas_div2 := []*Arena{}
arenas_div2 := []Arena{}
arenas_div2 = append(arenas_div2, NewVirtualArena("Arena 3"))
arenas_div2 = append(arenas_div2, NewVirtualArena("Arena 4"))
@ -167,12 +169,12 @@ func fake_data() (* EventManager, []*Arena, []*Arena) {
type FakeClient struct {
state string
start time.Time
arena * Arena
arena Arena
update chan GraphSignal
games_done int
}
func NewFakeClient(arena *Arena) * FakeClient {
func NewFakeClient(arena Arena) * FakeClient {
client := &FakeClient{
state: "init",
start: time.Now(),
@ -187,7 +189,7 @@ func NewFakeClient(arena *Arena) * FakeClient {
func (client * FakeClient) process_update(update GraphSignal) {
arena := client.arena
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 {
log.Logf("test", "FAKE_CLIENT_UPDATE: nil -> %+v", update)
}
@ -236,12 +238,27 @@ func (client * FakeClient) process_update(update GraphSignal) {
func main() {
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
arena_1_client := NewFakeClient(arenas_div1[0])
arena_2_client := NewFakeClient(arenas_div1[1])
arena_3_client := NewFakeClient(arenas_div2[0])
arena_4_client := NewFakeClient(arenas_div2[1])
go func() {
for true {
select {
@ -267,4 +284,5 @@ func main() {
log.Logf("test", "Client 3 games: %d", arena_3_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() {
SendUpdate(parent, new_signal)
}
resource.lock_holder_lock.Lock()
if resource.lock_holder != nil {
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)
type Resource interface {
GraphNode
Owner() Event
Owner() GraphNode
Children() []Resource
Parents() []Resource
@ -37,12 +43,12 @@ type Resource interface {
LockParents()
UnlockParents()
SetOwner(owner Event)
SetOwner(owner GraphNode)
LockState()
UnlockState()
lock(event Event) error
unlock(event Event) error
lock(node GraphNode) error
unlock(node GraphNode) error
Connect(abort chan error) bool
}
@ -106,7 +112,7 @@ func UnlockResource(resource Resource, event Event) error {
return nil
}
func LockResource(resource Resource, event Event) error {
func LockResource(resource Resource, node GraphNode) error {
resource.LockState()
if resource.Owner() != nil {
resource.UnlockState()
@ -114,7 +120,7 @@ func LockResource(resource Resource, event Event) error {
return errors.New(err_str)
}
err := resource.lock(event)
err := resource.lock(node)
if err != nil {
resource.UnlockState()
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
locked_resources := []Resource{}
for _, child := range resource.Children() {
err := LockResource(child, event)
err := LockResource(child, node)
if err != nil{
lock_err = err
break
@ -138,7 +144,7 @@ func LockResource(resource Resource, event Event) error {
return errors.New(err_str)
}
resource.SetOwner(event)
resource.SetOwner(node)
resource.UnlockState()
@ -175,12 +181,15 @@ type BaseResource struct {
parents_lock sync.Mutex
children []Resource
children_lock sync.Mutex
lock_holder Event
lock_holder GraphNode
lock_holder_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_lock.Unlock()
}
func (resource * BaseResource) LockState() {
@ -195,16 +204,16 @@ func (resource * BaseResource) Connect(abort chan error) bool {
return false
}
func (resource * BaseResource) Owner() Event {
func (resource * BaseResource) Owner() GraphNode {
return resource.lock_holder
}
//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
}
func (resource * BaseResource) unlock(event Event) error {
func (resource * BaseResource) unlock(node GraphNode) error {
return nil
}

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