make container complicated, heap profiles
This commit is contained in:
parent
4dba7b22c7
commit
8dc7583884
4 changed files with 105 additions and 28 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
.DS_Store
|
||||
cpuprofile.pprof
|
||||
cpuprofile.pprof
|
||||
heapprofile.pprof
|
||||
|
|
|
@ -6,11 +6,35 @@ var _ interface {
|
|||
} = &Container{}
|
||||
|
||||
// Container contains many components, in order.
|
||||
type Container []interface{}
|
||||
type Container struct {
|
||||
Items []interface{}
|
||||
|
||||
free map[int]struct{}
|
||||
reverse map[interface{}]int
|
||||
}
|
||||
|
||||
func MakeContainer(items ...interface{}) *Container {
|
||||
c := &Container{Items: items}
|
||||
c.Prepare(nil)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Container) Prepare(*Game) error {
|
||||
if c.reverse == nil {
|
||||
c.reverse = make(map[interface{}]int, len(c.Items))
|
||||
for i, x := range c.Items {
|
||||
c.reverse[x] = i
|
||||
}
|
||||
}
|
||||
if c.free == nil {
|
||||
c.free = make(map[int]struct{})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Scan visits every component in the container.
|
||||
func (c Container) Scan(visit func(interface{}) error) error {
|
||||
for _, x := range c {
|
||||
func (c *Container) Scan(visit func(interface{}) error) error {
|
||||
for _, x := range c.Items {
|
||||
if err := visit(x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -18,12 +42,55 @@ func (c Container) Scan(visit func(interface{}) error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Len returns the number of items in the container.
|
||||
func (c *Container) Len() int { return len(c.Items) }
|
||||
|
||||
// Swap swaps two items in the container.
|
||||
func (c *Container) Swap(i, j int) {
|
||||
if i == j {
|
||||
return
|
||||
}
|
||||
ifree := c.Items[i] == nil
|
||||
jfree := c.Items[j] == nil
|
||||
switch {
|
||||
case ifree && jfree:
|
||||
return
|
||||
case ifree:
|
||||
c.Items[i] = c.Items[j]
|
||||
c.reverse[c.Items[i]] = i
|
||||
c.free[j] = struct{}{}
|
||||
delete(c.free, i)
|
||||
case jfree:
|
||||
c.Items[j] = c.Items[i]
|
||||
c.reverse[c.Items[j]] = j
|
||||
c.free[i] = struct{}{}
|
||||
delete(c.free, j)
|
||||
default:
|
||||
c.Items[i], c.Items[j] = c.Items[j], c.Items[i]
|
||||
c.reverse[c.Items[i]] = i
|
||||
c.reverse[c.Items[j]] = j
|
||||
}
|
||||
}
|
||||
|
||||
func (c Container) String() string { return "Container" }
|
||||
|
||||
// Register records component in the slice, if parent is the container.
|
||||
// Register records component in the slice, if parent is this container. It
|
||||
// writes the component to an arbitrary free index in the slice, or appends if
|
||||
// there are none free.
|
||||
func (c *Container) Register(component, parent interface{}) error {
|
||||
if parent == c {
|
||||
*c = append(*c, component)
|
||||
if parent != c {
|
||||
return nil
|
||||
}
|
||||
if len(c.free) == 0 {
|
||||
c.reverse[component] = len(c.Items)
|
||||
c.Items = append(c.Items, component)
|
||||
return nil
|
||||
}
|
||||
for i := range c.free {
|
||||
c.reverse[component] = i
|
||||
c.Items[i] = component
|
||||
delete(c.free, i)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -32,28 +99,25 @@ func (c *Container) Register(component, parent interface{}) error {
|
|||
// to nil. If the number of nil items is greater than half the slice, the slice
|
||||
// is compacted.
|
||||
func (c *Container) Unregister(component interface{}) {
|
||||
free := 0
|
||||
for i, x := range *c {
|
||||
switch x {
|
||||
case component:
|
||||
(*c)[i] = nil
|
||||
free++
|
||||
case nil:
|
||||
free++
|
||||
}
|
||||
if i, found := c.reverse[component]; found {
|
||||
c.Items[i] = nil
|
||||
c.free[i] = struct{}{}
|
||||
delete(c.reverse, i)
|
||||
}
|
||||
if free > len(*c)/2 {
|
||||
if len(c.free) > len(c.Items)/2 {
|
||||
c.compact()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Container) compact() {
|
||||
i := 0
|
||||
for _, x := range *c {
|
||||
for _, x := range c.Items {
|
||||
if x != nil {
|
||||
(*c)[i] = x
|
||||
c.Items[i] = x
|
||||
c.reverse[x] = i
|
||||
i++
|
||||
}
|
||||
}
|
||||
*c = (*c)[:i]
|
||||
c.Items = c.Items[:i]
|
||||
c.free = make(map[int]struct{})
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ func Level1() *engine.Scene {
|
|||
return &engine.Scene{
|
||||
ID: "level_1",
|
||||
Bounds: engine.Bounds(image.Rect(-32, -32, 320+32, 240+32)),
|
||||
Child: &engine.Container{
|
||||
Child: engine.MakeContainer(
|
||||
&engine.Parallax{
|
||||
CameraID: "game_camera",
|
||||
Child: &engine.Billboard{
|
||||
|
@ -310,6 +310,6 @@ func Level1() *engine.Scene {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
24
main.go
24
main.go
|
@ -17,10 +17,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
enableCPUProfile = true
|
||||
enableREPL = true
|
||||
hardcodedLevel1 = true
|
||||
rewriteLevel1 = false
|
||||
enableCPUProfile = true
|
||||
enableHeapProfile = true
|
||||
enableREPL = true
|
||||
hardcodedLevel1 = true
|
||||
rewriteLevel1 = false
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -64,7 +65,7 @@ func main() {
|
|||
Z: math.Sqrt(3),
|
||||
},
|
||||
Root: &engine.DrawDFS{
|
||||
Child: &engine.Container{
|
||||
Child: engine.MakeContainer(
|
||||
&engine.Fill{
|
||||
ID: "bg_fill",
|
||||
Color: color.Gray{100},
|
||||
|
@ -78,7 +79,7 @@ func main() {
|
|||
},
|
||||
&engine.DebugToast{ID: "toast", Pos: image.Pt(0, 15)},
|
||||
engine.PerfDisplay{},
|
||||
},
|
||||
),
|
||||
},
|
||||
}
|
||||
if err := g.LoadAndPrepare(game.Assets); err != nil {
|
||||
|
@ -92,4 +93,15 @@ func main() {
|
|||
if err := ebiten.RunGame(g); err != nil {
|
||||
log.Fatalf("Game error: %v", err)
|
||||
}
|
||||
|
||||
if enableHeapProfile && runtime.GOOS != "js" {
|
||||
f, err := os.Create("heapprofile.pprof")
|
||||
if err != nil {
|
||||
log.Fatal("could not create heap profile: ", err)
|
||||
}
|
||||
defer f.Close()
|
||||
if err := pprof.WriteHeapProfile(f); err != nil {
|
||||
log.Fatal("could not write heap profile: ", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue