Code Monkey home page Code Monkey logo

gotraceui's Introduction

gotraceui - an efficient frontend for Go execution traces

Gotraceui is a tool for visualizing and analyzing Go execution traces. It is meant to be a faster, more accessible, and more powerful alternative to go tool trace. Unlike go tool trace, Gotraceui doesn’t use deprecated browser APIs (or a browser at all), and its UI is tuned specifically to the unique characteristics of Go traces.

Screenshot

Installation

Users of Nix can use the flake. There are no packages for other distributions or OSs yet and you will have to build honnef.co/go/gotraceui/cmd/gotraceui yourself. The manual contains information on how to.

Manual

Gotraceui includes a manual in PDF form. Each release includes the manual as an asset.

Notes for package maintainers

When packaging Gotraceui please take care to

  • pass -X gioui.org/app.ID=co.honnef.Gotraceui to the linker
  • install the share directory
  • call the package gotraceui, please
  • include the LICENSE-THIRD-PARTY file; it contains all the licenses and copyright notices of all dependencies and all code our code is derived from. Including this file satisfies the requirement of reproducing copyright notices and permission notices.

License

The source code of the program and all assets necessary to run the program are licensed under the MIT license. The manual (all files in doc/manual as well as the compiled output) is licensed under the CC BY-SA 4.0.

Copies of the licenses of all dependencies can be found in LICENSE-THIRD-PARTY.

Copyright

All original work is copyrighted by its respective authors (consult the git log.)
Parts of the code are derived from Go, © The Go Authors.
Parts of the code are derived from Gio, © The Gio authors.
Parts of the code are derived from go-tinylfu, © Damian Gryski
font/fallback.ttf is derived from the DejaVu fonts, © Bitstream, © Tavmjong Bah
doc/manual/images/olive.jpg is © Charlotte Brandhorst-Satzkorn, photographer and owner of the subject.

The compiled binary includes code from dependencies. These dependencies and their copyright holders can be found in LICENSE-THIRD-PARTY.

Known issues

gotraceui's People

Contributors

dominikh avatar felixge avatar mrunhap avatar nsrip-dd avatar srenatus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gotraceui's Issues

Crash when loading trace with unfinished user region

stack trace
panic: runtime error: index out of range [1099511627775] with length 1590912

goroutine 3 [running]:
panic({0x7d8840, 0xc00048c030})
/home/chris/.local/lib/go-1.19/src/runtime/panic.go:987 +0x3ba fp=0xc0006fb4e8 sp=0xc0006fb428 pc=0x4431ba
runtime.goPanicIndex(0xffffffffff, 0x184680)
/home/chris/.local/lib/go-1.19/src/runtime/panic.go:113 +0x7f fp=0xc0006fb528 sp=0xc0006fb4e8 pc=0x44131f
main.loadTrace({0x7ffd4c876024?, 0x15?}, 0xc000094480)
/home/chris/Code/builds/gotraceui/cmd/gotraceui/trace.go:666 +0x2a5c fp=0xc0006fbf40 sp=0xc0006fb528 pc=0x6fbe5c
main.main.func2()
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3364 +0xb7 fp=0xc0006fbfe0 sp=0xc0006fbf40 pc=0x6f8437
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0006fbfe8 sp=0xc0006fbfe0 pc=0x4734c1
created by main.main
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3362 +0x29d

goroutine 1 [select (no cases)]:
runtime.gopark(0x44e4e0?, 0xc0000b2380?, 0xa0?, 0x61?, 0x6f7d7c?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc000055ee0 sp=0xc000055ec0 pc=0x446216
runtime.block()
/home/chris/.local/lib/go-1.19/src/runtime/select.go:104 +0x2c fp=0xc000055f10 sp=0xc000055ee0 pc=0x45572c
gioui.org/app.osMain(...)
/home/chris/Code/gioui/gio/app/os_unix.go:43
gioui.org/app.Main(...)
/home/chris/Code/gioui/gio/app/app.go:45
main.main()
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3420 +0x325 fp=0xc000055f80 sp=0xc000055f10 pc=0x6f7d85
runtime.main()
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:250 +0x212 fp=0xc000055fe0 sp=0xc000055f80 pc=0x445e52
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc000055fe8 sp=0xc000055fe0 pc=0x4734c1

goroutine 2 [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc000040fb0 sp=0xc000040f90 pc=0x446216
runtime.goparkunlock(...)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:369
runtime.forcegchelper()
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:302 +0xad fp=0xc000040fe0 sp=0xc000040fb0 pc=0x4460ad
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc000040fe8 sp=0xc000040fe0 pc=0x4734c1
created by runtime.init.6
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:290 +0x25

goroutine 18 [GC sweep wait]:
runtime.gopark(0x1?, 0x0?, 0x0?, 0x0?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00003c790 sp=0xc00003c770 pc=0x446216
runtime.goparkunlock(...)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:369
runtime.bgsweep(0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/mgcsweep.go:297 +0xd7 fp=0xc00003c7c8 sp=0xc00003c790 pc=0x4321b7
runtime.gcenable.func1()
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:178 +0x26 fp=0xc00003c7e0 sp=0xc00003c7c8 pc=0x426e26
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00003c7e8 sp=0xc00003c7e0 pc=0x4734c1
created by runtime.gcenable
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:178 +0x6b

goroutine 19 [GC scavenge wait]:
runtime.gopark(0xc00008e000?, 0x8bac40?, 0x0?, 0x0?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00003cf70 sp=0xc00003cf50 pc=0x446216
runtime.goparkunlock(...)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:369
runtime.(*scavengerState).park(0xd33c00)
/home/chris/.local/lib/go-1.19/src/runtime/mgcscavenge.go:389 +0x53 fp=0xc00003cfa0 sp=0xc00003cf70 pc=0x430213
runtime.bgscavenge(0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/mgcscavenge.go:622 +0x65 fp=0xc00003cfc8 sp=0xc00003cfa0 pc=0x430805
runtime.gcenable.func2()
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:179 +0x26 fp=0xc00003cfe0 sp=0xc00003cfc8 pc=0x426dc6
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00003cfe8 sp=0xc00003cfe0 pc=0x4734c1
created by runtime.gcenable
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:179 +0xaa

goroutine 20 [finalizer wait]:
runtime.gopark(0x0?, 0x85fa50?, 0xa0?, 0x60?, 0x2000000020?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc000040628 sp=0xc000040608 pc=0x446216
runtime.goparkunlock(...)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:369
runtime.runfinq()
/home/chris/.local/lib/go-1.19/src/runtime/mfinal.go:180 +0x10f fp=0xc0000407e0 sp=0xc000040628 pc=0x425f2f
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0000407e8 sp=0xc0000407e0 pc=0x4734c1
created by runtime.createfing
/home/chris/.local/lib/go-1.19/src/runtime/mfinal.go:157 +0x45

goroutine 21 [GC worker (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00003d750 sp=0xc00003d730 pc=0x446216
runtime.gcBgMarkWorker()
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1235 +0xf1 fp=0xc00003d7e0 sp=0xc00003d750 pc=0x428f71
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00003d7e8 sp=0xc00003d7e0 pc=0x4734c1
created by runtime.gcBgMarkStartWorkers
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1159 +0x25

goroutine 22 [GC worker (idle)]:
runtime.gopark(0x65308073a1f0?, 0x0?, 0x0?, 0x0?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00003df50 sp=0xc00003df30 pc=0x446216
runtime.gcBgMarkWorker()
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1235 +0xf1 fp=0xc00003dfe0 sp=0xc00003df50 pc=0x428f71
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00003dfe8 sp=0xc00003dfe0 pc=0x4734c1
created by runtime.gcBgMarkStartWorkers
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1159 +0x25

goroutine 23 [GC worker (idle)]:
runtime.gopark(0x653080727adb?, 0x3?, 0x41?, 0x50?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00003e750 sp=0xc00003e730 pc=0x446216
runtime.gcBgMarkWorker()
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1235 +0xf1 fp=0xc00003e7e0 sp=0xc00003e750 pc=0x428f71
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00003e7e8 sp=0xc00003e7e0 pc=0x4734c1
created by runtime.gcBgMarkStartWorkers
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1159 +0x25

goroutine 24 [GC worker (idle)]:
runtime.gopark(0x6530806defb9?, 0x0?, 0x0?, 0x0?, 0x0?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00003ef50 sp=0xc00003ef30 pc=0x446216
runtime.gcBgMarkWorker()
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1235 +0xf1 fp=0xc00003efe0 sp=0xc00003ef50 pc=0x428f71
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00003efe8 sp=0xc00003efe0 pc=0x4734c1
created by runtime.gcBgMarkStartWorkers
/home/chris/.local/lib/go-1.19/src/runtime/mgc.go:1159 +0x25

goroutine 4 [runnable]:
runtime.gopark(0xc0006ddcf8?, 0x3?, 0x0?, 0x10?, 0xc0006dd82a?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc0006dd5b0 sp=0xc0006dd590 pc=0x446216
runtime.selectgo(0xc0006ddcf8, 0xc0006dd824, 0x1?, 0x0, 0x4?, 0x1)
/home/chris/.local/lib/go-1.19/src/runtime/select.go:328 +0x7bc fp=0xc0006dd6f0 sp=0xc0006dd5b0 pc=0x455efc
main.(*MainWindow).Run(0xc0004f5400, 0xc0006f4000)
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:2368 +0x18b fp=0xc0006ddf90 sp=0xc0006dd6f0 pc=0x6ee2cb
main.main.func3()
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3381 +0x9f fp=0xc0006ddfe0 sp=0xc0006ddf90 pc=0x6f82bf
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0006ddfe8 sp=0xc0006ddfe0 pc=0x4734c1
created by main.main
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3378 +0x2dd

goroutine 5 [select]:
runtime.gopark(0xc000042750?, 0x2?, 0xe8?, 0x25?, 0xc000042714?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc0000425a0 sp=0xc000042580 pc=0x446216
runtime.selectgo(0xc000042750, 0xc000042710, 0x0?, 0x0, 0x0?, 0x1)
/home/chris/.local/lib/go-1.19/src/runtime/select.go:328 +0x7bc fp=0xc0000426e0 sp=0xc0000425a0 pc=0x455efc
main.main.func4()
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3396 +0x1bb fp=0xc0000427e0 sp=0xc0000426e0 pc=0x6f805b
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0000427e8 sp=0xc0000427e0 pc=0x4734c1
created by main.main
/home/chris/Code/builds/gotraceui/cmd/gotraceui/main.go:3384 +0x31c

goroutine 6 [select]:
runtime.gopark(0xc00004ef50?, 0x5?, 0x1?, 0x0?, 0xc00004eeee?)
/home/chris/.local/lib/go-1.19/src/runtime/proc.go:363 +0xd6 fp=0xc00004ed60 sp=0xc00004ed40 pc=0x446216
runtime.selectgo(0xc00004ef50, 0xc00004eee4, 0x5?, 0x0, 0x0?, 0x1)
/home/chris/.local/lib/go-1.19/src/runtime/select.go:328 +0x7bc fp=0xc00004eea0 sp=0xc00004ed60 pc=0x455efc
gioui.org/app.(*Window).run(0xc0006f4000, {0xc000092440?, 0x783d80?, 0x8bb8f0?})
/home/chris/Code/gioui/gio/app/window.go:963 +0x1d9 fp=0xc00004efb0 sp=0xc00004eea0 pc=0x68daf9
gioui.org/app.NewWindow.func4()
/home/chris/Code/gioui/gio/app/window.go:187 +0x32 fp=0xc00004efe0 sp=0xc00004efb0 pc=0x6898b2
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc00004efe8 sp=0xc00004efe0 pc=0x4734c1
created by gioui.org/app.NewWindow
/home/chris/Code/gioui/gio/app/window.go:187 +0x96a

goroutine 50 [syscall, locked to thread]:
syscall.Syscall6(0x68c2dd?, 0x0?, 0xc0006e1ce8?, 0x44de71?, 0x0?, 0x0?, 0xc000083380?)
/home/chris/.local/lib/go-1.19/src/syscall/syscall_linux.go:90 +0x36 fp=0xc0006e1c90 sp=0xc0006e1c08 pc=0x4a6776
syscall.Syscall6(0x10f, 0xc0006e1e54, 0x2, 0x0, 0x0, 0x0, 0x0)
:1 +0x45 fp=0xc0006e1cd8 sp=0xc0006e1c90 pc=0x4a6a65
golang.org/x/sys/unix.ppoll(0xd34460?, 0xc0006e1d88?, 0x68f3b6?, 0x702cf0?)
/home/chris/Code/go/pkg/mod/golang.org/x/[email protected]/unix/zsyscall_linux.go:124 +0x58 fp=0xc0006e1d58 sp=0xc0006e1cd8 pc=0x683038
golang.org/x/sys/unix.Ppoll({0xc0006e1e54?, 0x6a0c06?, 0x19e53c0?}, 0xc000000000?, 0x0?)
/home/chris/Code/go/pkg/mod/golang.org/x/[email protected]/unix/syscall_linux.go:148 +0x45 fp=0xc0006e1d88 sp=0xc0006e1d58 pc=0x682dc5
golang.org/x/sys/unix.Poll({0xc0006e1e54?, 0xc0000c40c0?, 0x0?}, 0x0?)
/home/chris/Code/go/pkg/mod/golang.org/x/[email protected]/unix/syscall_linux.go:157 +0x99 fp=0xc0006e1dd0 sp=0xc0006e1d88 pc=0x682eb9
gioui.org/app.(*wlDisplay).dispatch(0xc0000c40c0, 0xc0006e1e54)
/home/chris/Code/gioui/gio/app/os_wayland.go:1389 +0xdd fp=0xc0006e1e18 sp=0xc0006e1dd0 pc=0x6a095d
gioui.org/app.(*window).loop(0xc0006f4600)
/home/chris/Code/gioui/gio/app/os_wayland.go:1342 +0x73 fp=0xc0006e1f18 sp=0xc0006e1e18 pc=0x6a04f3
gioui.org/app.newWLWindow.func1()
/home/chris/Code/gioui/gio/app/os_wayland.go:279 +0x1cf fp=0xc0006e1fe0 sp=0xc0006e1f18 pc=0x696eaf
runtime.goexit()
/home/chris/.local/lib/go-1.19/src/runtime/asm_amd64.s:1594 +0x1 fp=0xc0006e1fe8 sp=0xc0006e1fe0 pc=0x4734c1
created by gioui.org/app.newWLWindow
/home/chris/Code/gioui/gio/app/os_wayland.go:264 +0x118
fish: Job 3, 'gotraceui /tmp/2489294363.trace' terminated by signal SIGABRT (Abort)

Commit ec795e2. I've shared the trace elsewhere, as it can't be uploaded here.

Improve performance of trace parser

We're currently vendoring Go's internal/trace package and use that for parsing traces. It's taking 12 seconds to parse a 7.3 MB trace file, produced by go test -trace=... net/http. Parsing (and post-processing) at 600 kB/s feels "a bit" slow.

That parsing the file results in 500 MB of memory usage also isn't great.

Display all activities in "G" window

Right now, "G" brings up a goroutine selector. Really it should select from all activities: processors, goroutines, and potential future ones. Not all that difficult, but needs some restructuring of our types.

Improve "scroll to goroutine" and processor

When selecting "scroll to goroutine" from a span's context menu, the goroutine should be scrolled to the Y position of the activity we interacted with, not the top of the screen. That way, the user can immediately interact with it, without having to move the mouse.

Need to consider how this should work with the first couple activities in the timeline; we'd need a gap at the top to move them further down.

Add context menus providing more navigation options

Left-clicking on a goroutine ID currently opens a goroutine window. We should also provide a context menu that allows the user to scroll to or zoom to the goroutine instead. For timestamps, the user could choose between setting the start or the end of the timeline to the timestamp.

A goroutine span's context menu could let the user jump to the matching span in the processor view, for example.

Handle truncated stack traces

The stacks associated with events have a maximum length and are truncated, containing only the last N frames. This means that we may be missing frames up to the root. This is especially troublesome for the stack trace timeline because it can cause misalignment:

image

We can detect that a stack is truncated, when the last frame doesn't correspond to the goroutine's function, but we can't tell how many frames are missing. That means we can indicate that the stack is incomplete, but we cannot fix the alignment. Drawing the stack upside down, with leaves at the top, would fix the alignment issue, but is generally not intuitive.

Filtering

Implement customizable filtering of goroutines and spans.

At a minimum we want to filter goroutines based on

  • the function name at the bottom of their stack
  • their ID
  • whether they contain any spans matching span filters
  • interactions; given a primary goroutine, show goroutines that interact with it, i.e. unblock it or get unblocked by it
  • their user regions, tasks, and logs
  • the proc they ran on

At a minimum we want to filter spans based on

  • their state
  • their tags
  • their duration
  • their start or end time
  • whether they overlap with GC or STW
  • their user regions, tasks, and logs

Display per-thread activities

We get ProcStart (and matching ProcStop) events whenever a P is associated with an M. We can thus display activities for Ms, to analyze how Ps get scheduled onto Ms.

(It'd be great if we also knew what CPU core an M ran on, but that's not information that the Go runtime has.)

Most state in TimelineWidget isn't needed for invisible timelines

We have thousands to millions of timelines (at least one per goroutine), but only a tiny fraction of them can be visible at any one time. Similar to how we already drop state of track widgets, drop state of timelines that aren't visible. Currently, TimelineWidget is 456 bytes long, and I reckon that at most 64 bytes are necessary to keep around all the time.

Turn user logs into proper metadata

The documentation of runtime/trace says to use a finite set of region and task names, and to use user logs to attach additional information, such as IDs. It'd be nice if we could (semi-)automatically turn user logs into proper metadata that can be displayed, searched on etc. The problem is, of course, that user logs can also be used for actual logging, and that it's all just strings.

User logs are made up of a category and a message, so it would be possible to let users configure mappings from category to kind of metadata.

Support external command invocation

(From a user request:)

Add a way for other programs to manipulate gotraceui, e.g. to scroll to a certain goroutine or timestamp, or to open goroutine windows.

Difficulties: there may be multiple instances of gotraceui, and multiple main windows per instance, making it hard to know which window to send the command to.

Most text should be copyable

Virtually all text we display, such as goroutine statistics, cannot be selected or copied. This is awful. We probably don't need proper text selection, however, and a way to copy text should be enough. For example, clicking on a label could copy it.

Labels that contain numbers formatted with thousands separators should have a second way of copying that drops the separators. This is useful for feeding numbers into other tools.

Display user-defined tasks and regions on timeline

runtime/trace allows users to create application-defined tasks and regions of processing within those tasks, but no existing tooling surfaces them.

I lack the domain expertise to know how difficult of a feature this is, or whether it makes sense to tackle it now. I am willing to contribute time/code towards implementing this when/if doing so is deemed appropriate. Let me know your thoughts @dominikh.

Implement animations

Currently, all manipulation of the timeline is instant. For actions that change the scale, i.e. zooming, this can be disorienting, particularly when zooming to a single span or a selection. We should animate this over a couple of frames.

Low priority until we actually have a UI that surpasses a prototype.

Provide menu for changing UI settings

Implement a popup windows that can be used to customize UI settings. e.g. instead of needing different shortcuts for toggling labels, compact mode, tooltips etc, have one shortcut that opens a menu that allows toggling these features.

Support multiple main windows

Sometimes it is useful to compare two parts of a trace that aren't close to each other (in either the time or the goroutine dimension). Instead of implementing our own split screen mechanism, just allow the user to create additional main windows, viewing the same trace, but each with their own timeline and independent controls. Provide an optional toggle to couple multiple windows so that relative motion in one gets mirrored to the other.

Add custom file format

Come up with our own file format for storing traces in. The runtime's trace format is optimized for being cheap to write, but we should be able to optimize for fast parsing and space-efficient storage since we get to do it offline. This will also let us store additional data, such as per-trace settings (active filters, saved filters, …), annotations, etc.

A file saved in our format would be a compact, annotated trace, and it would be stored in a compressed format. Its file extension would therefore be .catz.

Make use of CPU samples

Go 1.19 adds CPU samples to runtime traces. This gives us multiple stacks per span. We should expose those somehow. The most straightforward would be to expose them like other events. It's also tempting to recreate timelines from samples, but we have to be clear about the sampled nature; a single sample doesn't tell us if a function got called once or a dozen times, and if the call lasted a nanosecond or 10ms.

Add more keyboard based navigation

We should probably support the page up and page down keys for scrolling the timeline. We could also support WASD for panning (that's very gaming-focused, but I've found myself trying to use it at least once, and Tracy recently added support for it, too). We should also support Spacebar as an alternative to the middle mouse button.

Support different kinds of axes

The relative axis works well for analyzing a specific piece of the trace, but it makes it difficult (or at least unintuitive) to navigate to that piece; here, users would prefer an absolute timeline, especially because it makes motion during scrolling more apparent.

Another feature that got suggested is a relative axis but with a fixed start point:

That sounds almost like there should be a way to set a "zero time". To be in absolute mode while navigating, then to say "I'm very interested in time 216,522,272 ns, turn that into the zero mark" and then to see times as relative to that offset.

Support sorting and reordering activity widgets

Right now, activity widgets have a fixed order: GC, STW, Ps, Gs, with Ps and Gs sorted by their ID. We should allow alternate sorts (for example sorting Gs in topological order with regard to their family tree), and let users reorder individual widgets.

Other useful sorts are:

  • Creation time. Goroutine IDs are allocated to Ps in batches of 16 to avoid contention on the counter, but this can lead to ID n+1 being used before ID n.
  • Relatedness. We could group goroutines that interact with each other.
  • Activity. We could sort busier goroutines to the top, although it's not clear how to define busy. Time spent on-CPU?

Detect common patterns from stack traces

As rich as the execution trace is, a lot of higher level events are represented as many smaller events. For example, a goroutine might block on a mutex because it tried to allocate memory and the allocation triggered a garbage collection, and starting the garbage collection needs to hold a lock.

At a glance, this just looks like user code blocking on a mutex. Only from the stack trace does it become obvious that we're blocking because of an allocation. Instead of expecting every user to be able to recognize these patterns, we should detect them and make them visible.

This might also allow us to provide more detail for the generic EvGoBlock event.

Magnifying glass

A lot of the time we want to look at the bigger picture of execution, but temporarily zoom in on very small (and often merged) spans. The least disruptive way of doing this would be a magnifying glass overlay that shows a magnified version of the region surrounding the mouse cursor, similar to the accessibility tool. We will want to bind this feature to a key, though I am not yet sure if it should be a toggle, or "hold to use".

Truncate long labels

Labels that are too long just get cut off, which means that g1234 might display as g1, which is confusing. We should correctly truncate labels and append ellipses.

Configurable number format in goroutine statistics

We implement 3 different ways of displaying goroutine statistics: units with SI prefixes, fixed width scientific notation, and displaying exact numbers. By default we use SI prefixes, and there is currently no way to change this setting. This should be configurable.

Related: #23

image
image
image

Implement our own theme

We're currently using Gio's material theme for some UI elements. This isn't a viable option in the long run, because we don't actually like material design. The scrollbar is alright, but we'll get into trouble the moment we need a button.

It's fine to use for prototyping, but the final product should have its own theme.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.