mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-22 23:28:16 +00:00
design: update tracer design
Update the tracer event classes section. Add a performance section.
This commit is contained in:
parent
d7acb27dee
commit
77fd813760
1 changed files with 103 additions and 53 deletions
|
@ -36,7 +36,7 @@ condition to check if active.
|
||||||
Certain GStreamer core function (such as gst_pad_push or gst_element_add_pad)
|
Certain GStreamer core function (such as gst_pad_push or gst_element_add_pad)
|
||||||
will call into the tracer subsystem to dispatch into active tracing modules.
|
will call into the tracer subsystem to dispatch into active tracing modules.
|
||||||
Developers will be able to select a list of plugins by setting an environment
|
Developers will be able to select a list of plugins by setting an environment
|
||||||
variable, such as GST_TRACE="meminfo,dbus". One can also pass parameters to
|
variable, such as GST_TRACE="meminfo;dbus". One can also pass parameters to
|
||||||
plugins: GST_TRACE="log(events,buffers);stats(all)".
|
plugins: GST_TRACE="log(events,buffers);stats(all)".
|
||||||
When then plugins are loaded, we'll add them to certain hooks according to which
|
When then plugins are loaded, we'll add them to certain hooks according to which
|
||||||
they are interested in.
|
they are interested in.
|
||||||
|
@ -81,7 +81,10 @@ TODO(ensonic): liblttng-ust provides such a mechanism for user-space
|
||||||
|
|
||||||
In addition to api hooks we should also provide timer hooks. Interval timers are
|
In addition to api hooks we should also provide timer hooks. Interval timers are
|
||||||
useful to get e.g. resource usage snapshots. Also absolute timers might make
|
useful to get e.g. resource usage snapshots. Also absolute timers might make
|
||||||
sense. All this could be implemented with a clock thread.
|
sense. All this could be implemented with a clock thread. We can use another
|
||||||
|
env-var GST_TRACE_TIMERS="100ms,75ms" to configure timers and then pass them to
|
||||||
|
the tracers like, GST_TRACE="rusage(timer=100ms);meminfo(timer=75ms)". Maybe
|
||||||
|
we can create them ad-hoc and avoid the GST_TRACE_TIMERS var.
|
||||||
|
|
||||||
Hooks (* already implemented)
|
Hooks (* already implemented)
|
||||||
-----
|
-----
|
||||||
|
@ -98,64 +101,89 @@ Hooks (* already implemented)
|
||||||
* gst_pad_push_event
|
* gst_pad_push_event
|
||||||
- gst_pad_unlink
|
- gst_pad_unlink
|
||||||
|
|
||||||
Plugin api
|
Tracer api
|
||||||
----------
|
----------
|
||||||
|
Tracers are plugin features. They have a simple api:
|
||||||
|
|
||||||
TracerPlugins are plugin features. They have a simple api:
|
class init
|
||||||
|
Here the tracers describe the data the will emit.
|
||||||
|
|
||||||
instance creation
|
instance init
|
||||||
Plugins can attach handlers to one or more hooks. They use a HookMask to tell
|
Tracers attach handlers to one or more hooks using gst_tracer_register_hook().
|
||||||
which events they are interested in. The params are the extra detail from the
|
In case the are configurable, they can read the options from the 'params'
|
||||||
environment var.
|
property. This is the extra detail from the environment var.
|
||||||
|
|
||||||
void invoke(GstTracerHookId id, GstStructure *s);
|
hook functions
|
||||||
Hooks marshal the parameters given to a trace hook into varargs and also
|
Hooks marshal the parameters given to a trace hook into varargs and also
|
||||||
add some extra into such as a timestamp. Hooks will be called from misc threads.
|
add some extra into such as a timestamp. Hooks will be called from misc threads.
|
||||||
The trace plugins should only consume (=read) the provided data.
|
The trace plugins should only consume (=read) the provided data. Expensive
|
||||||
|
computation should be avoided to not affect the execution too much.
|
||||||
Most trace plugins will log data to a trace channel.
|
Most trace plugins will log data to a trace channel.
|
||||||
|
|
||||||
instance destruction
|
instance destruction
|
||||||
Plugins can output results and release data. This would ideally be done at the
|
Tracers can output results and release data. This would ideally be done at the
|
||||||
end of the applications, but gst_deinit() is not mandatory. gst_tracelib was
|
end of the applications, but gst_deinit() is not mandatory. gst_tracelib was
|
||||||
using a gcc_destructor. Ideally tracer modules log data as they have it and
|
using a gcc_destructor. Ideally tracer modules log data as they have them and
|
||||||
leave aggregation to a tool that processed the log.
|
leave aggregation to a tool that processes the log.
|
||||||
|
|
||||||
tracer event classes (not implemented yet)
|
tracer event classes
|
||||||
--------------------
|
--------------------
|
||||||
tracers will describe the data the log here (gst_tracer_class_add_event_class).
|
|
||||||
Most tracers will log some kind of 'events' : a data transfer, an event,
|
Most tracers will log some kind of 'events' : a data transfer, an event,
|
||||||
a message, a query or a measurement.
|
a message, a query or a measurement. Every tracers should describe the data
|
||||||
|
format. This way tools that process tracer logs can show the data in a
|
||||||
|
meaningful way without having to know about the tracer plugin.
|
||||||
|
|
||||||
GstTraceEventClass { // meta data for events, can be printed from gst-inspect
|
One way would be to introspect the data from the plugin. This has the
|
||||||
gchar *name; // something that front ends can use as a label for a graph
|
disadvantage that the postprocessing app needs to load the plugins or talk to
|
||||||
// should ideally contain a unit
|
the gstreamer registry. An alternative is to also log the format description
|
||||||
gchar *description; // something that front ends can use as a tooltip
|
into the log. Right now we're logging several nested GstStructure from the
|
||||||
|
_tracer_class_init() function (except in the log tracer).
|
||||||
GstTraceEventScope scope; // a way to associate the event
|
|
||||||
// enum(per process, thread, element, pad, ...)
|
|
||||||
|
|
||||||
Gst??? type; // some kind of hierarchical event type? or make name a 'path'
|
// the name is the value name + ".class"
|
||||||
// event.eos, event.seek.flushing, measurement.cpu.load, ...
|
// the content describes a single log record
|
||||||
|
gst_structure_new ("thread-rusage.class",
|
||||||
GstTraceEventClassFlags flags; // cummulative, ...
|
// value in the log record (order does not matter)
|
||||||
}
|
// 'thread-id' is a 'key' to related the record to something as indicated
|
||||||
|
// by 'scope' substructure
|
||||||
|
"thread-id", GST_TYPE_STRUCTURE, gst_structure_new ("scope",
|
||||||
|
// enum { process, thread, element, pad, context?, ... }
|
||||||
|
"related-to", G_TYPE_STRING, "thread",
|
||||||
|
NULL),
|
||||||
|
// next value in the record
|
||||||
|
// 'average-cpuload' is a measurement as indicated by the 'value'
|
||||||
|
// substructure
|
||||||
|
"average-cpuload", GST_TYPE_STRUCTURE, gst_structure_new ("value",
|
||||||
|
// value type
|
||||||
|
"type", G_TYPE_GTYPE, G_TYPE_UINT,
|
||||||
|
// human readable description, that can be used as a graph label
|
||||||
|
"description", G_TYPE_STRING, "average cpu usage per thread",
|
||||||
|
// flags that help to use the right graph type
|
||||||
|
// flags { aggregated, windowed, cumulative, ... }
|
||||||
|
"flags", G_TYPE_STRING, "aggregated",
|
||||||
|
// value range
|
||||||
|
"min", G_TYPE_UINT, 0,
|
||||||
|
"max", G_TYPE_UINT, 100,
|
||||||
|
NULL),
|
||||||
|
...
|
||||||
|
NULL);
|
||||||
|
|
||||||
GstTraceEvent {
|
A few ideas that are not yet in the above spec:
|
||||||
GstClockTime ts; // when did it happen
|
- it would be nice to describe the unit of values
|
||||||
gpointer owner; // GThread, GObject, ...
|
- putting it into the description is not flexible though, e.g. time would be
|
||||||
// payloads:
|
a guint64 but a ui would reformat it to e.g. h:m:s.ms
|
||||||
// - array of unions
|
- other units are e.g.: percent, per-mille, or kbit/s
|
||||||
// - GstStructure
|
- we'd like to have some metadata on scopes
|
||||||
// - we can just serialize this for logging and easily deserialize it in
|
- e.g. we'd like to log the thread-names, so that a UI can show that instead
|
||||||
// the front-ends using gst_structure_{from,to}_string()
|
of thread-ids
|
||||||
// - we would have 'ts' and 'owner' in the structure
|
- the stats tracer logs 'new-element' and 'new-pad' messages
|
||||||
// - the structure 'name-id' can be used to lookup the GstTraceEventClass
|
- they add a unique 'ix' to each instance as the memory ptr can be reused
|
||||||
// - GVariant ?
|
for new instances, the data is attached to the objects as qdata
|
||||||
}
|
- the latency tracer would like to also ref this metadata
|
||||||
|
- right now we log the classes as structures, it would be nice to add them to
|
||||||
|
the registry, so that gst-inspect can show them
|
||||||
|
|
||||||
instead of "gpointer owner", we could send a trace-events that register new
|
In addition to the above spec, each log event will contain a "ts" field as a
|
||||||
owners with an id (atomic int) and unregister them at the end of their
|
G_TYPE_UINT64 to specify the time of the event.
|
||||||
live-time. Then we can reference the owner as "guint owner".
|
|
||||||
|
|
||||||
We could also consider to add each value as a READABLE gobject property. The
|
We could also consider to add each value as a READABLE gobject property. The
|
||||||
property has name/description. We could use qdata for scope and flags (or have
|
property has name/description. We could use qdata for scope and flags (or have
|
||||||
|
@ -167,9 +195,6 @@ log.
|
||||||
Or we just add a gst_tracer_class_install_event() and that mimics the
|
Or we just add a gst_tracer_class_install_event() and that mimics the
|
||||||
g_object_class_install_property().
|
g_object_class_install_property().
|
||||||
|
|
||||||
The log would have a bunch of streams. A stream has a reference to the
|
|
||||||
GstTraceEventClass.
|
|
||||||
|
|
||||||
Frontends can:
|
Frontends can:
|
||||||
- do an events over time histogram
|
- do an events over time histogram
|
||||||
- plot curves of values over time or deltas
|
- plot curves of values over time or deltas
|
||||||
|
@ -217,6 +242,12 @@ stats
|
||||||
- register to buffer, event, message and query flow
|
- register to buffer, event, message and query flow
|
||||||
- tracing apps can do e.g. statistics
|
- tracing apps can do e.g. statistics
|
||||||
|
|
||||||
|
refcounts (not yet implemented)
|
||||||
|
---------
|
||||||
|
- log ref-counts of objects
|
||||||
|
- just logging them outside of glib/gobject would still make it hard to detect
|
||||||
|
issues though
|
||||||
|
|
||||||
User interfaces
|
User interfaces
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
@ -245,9 +276,6 @@ Maybe we can even feed the log into existing live graphers, with a little driver
|
||||||
Problems / Open items
|
Problems / Open items
|
||||||
=====================
|
=====================
|
||||||
- should tracers log into the debug.log or into a separate log?
|
- should tracers log into the debug.log or into a separate log?
|
||||||
- in the log we need a bit of protocol:
|
|
||||||
- log the GST_TRACE var, so that front-ends can understand what tracers
|
|
||||||
where active and what parameters where passed.
|
|
||||||
- separate log
|
- separate log
|
||||||
- use a binary format?
|
- use a binary format?
|
||||||
- worse performance (we're writing two logs at the same time)
|
- worse performance (we're writing two logs at the same time)
|
||||||
|
@ -271,8 +299,8 @@ Problems / Open items
|
||||||
GST_TRACER="timer(10ms);rusage"
|
GST_TRACER="timer(10ms);rusage"
|
||||||
right now the tracer hooks are defined as an enum though.
|
right now the tracer hooks are defined as an enum though.
|
||||||
- when connecting to a running app, we can't easily get the 'current' state if
|
- when connecting to a running app, we can't easily get the 'current' state if
|
||||||
logging is using a socket, as past events are not explicitly stored, we could
|
logging is using a socket, as past events are not explicitly stored, we could
|
||||||
determine the current topology and emit events with GST_CLOCK_TIME_NONE as ts
|
determine the current topology and emit events with GST_CLOCK_TIME_NONE as ts
|
||||||
to indicate that the events are synthetic.
|
to indicate that the events are synthetic.
|
||||||
|
|
||||||
Try it
|
Try it
|
||||||
|
@ -284,8 +312,30 @@ GST_DEBUG="GST_TRACER:7" GST_TRACE="stats;rusage" gst-launch-1.0 2>trace.log fak
|
||||||
gst-stats-1.0 trace.log
|
gst-stats-1.0 trace.log
|
||||||
- print some pipeline stats on exit
|
- print some pipeline stats on exit
|
||||||
|
|
||||||
grep "proc-rusage" trace.log | cut -c154- | sed -e 's#ts=(guint64)##' -e 's#cpuload=(uint)##' -e 's#time=(guint64)##' -e 's#;##'
|
GST_DEBUG="GST_TRACER:7" GST_TRACE="stats;rusage" /usr/bin/gst-play-1.0 2>trace.log --interactive $HOME/Videos/movie.mp4
|
||||||
|
./tools/gst-plot-traces.sh --format=png | gnuplot
|
||||||
|
eog trace.log.*.png
|
||||||
|
- get ts, average-cpuload, current-cpuload, time and plot
|
||||||
|
|
||||||
GST_DEBUG="GST_TRACER:7" GST_TRACE=latency gst-launch-1.0 audiotestsrc num-buffers=10 ! audioconvert ! volume volume=0.7 ! autoaudiosink
|
GST_DEBUG="GST_TRACER:7" GST_TRACE=latency gst-launch-1.0 audiotestsrc num-buffers=10 ! audioconvert ! volume volume=0.7 ! autoaudiosink
|
||||||
- print processing latencies
|
- print processing latencies
|
||||||
|
|
||||||
|
Performance
|
||||||
|
===========
|
||||||
|
GST_DEBUG="GST_TRACER:7" GST_TRACE="stats;rusage" /usr/bin/gst-launch-1.0 2>trace.log playbin uri=file:///home/ensonic/Music/1.mp3 audio-sink="fakesink sync=false"
|
||||||
|
0:00:42.531147106 (GList)
|
||||||
|
0:00:09.273174008 (GQueue)!
|
||||||
|
|
||||||
|
GST_DEBUG="GST_TRACER:7" GST_TRACE="rusage" /usr/bin/gst-launch-1.0 2>trace.log playbin uri=file:///home/ensonic/Music/1.mp3 audio-sink="fakesink sync=false"
|
||||||
|
0:00:07.388375834
|
||||||
|
|
||||||
|
GST_TRACE="rusage" /usr/bin/gst-launch-1.0 2>trace.log playbin uri=file:///home/ensonic/Music/1.mp3 audio-sink="fakesink sync=false"
|
||||||
|
0:00:01.691596186
|
||||||
|
|
||||||
|
/usr/bin/gst-launch-1.0 playbin uri=file:///home/ensonic/Music/1.mp3 audio-sink="fakesink sync=false"
|
||||||
|
0:00:00.788497775
|
||||||
|
|
||||||
|
egrep -c "(proc|thread)-rusage" trace.log
|
||||||
|
658618
|
||||||
|
|
||||||
|
- we can optimize most with using quarks in structures or eventually avoid structures totally
|
||||||
|
|
Loading…
Reference in a new issue