G_DEFINE_TYPE_WITH_CODE (GstRUsageTracer, gst_rusage_tracer, GST_TYPE_TRACER,
_do_init);
+/* for ts calibration */
+static gpointer main_thread_id = NULL;
+static guint64 tproc_base = G_GINT64_CONSTANT (0);
+
typedef struct
{
/* time spend in this thread */
- GstClockTime treal;
- guint max_cpuload;
+ GstClockTime tthread;
} GstThreadStats;
static void gst_rusage_tracer_invoke (GstTracer * self, GstTracerHookId id,
{
g_object_set (self, "mask", GST_TRACER_HOOK_ALL, NULL);
self->threads = g_hash_table_new_full (NULL, NULL, NULL, free_thread_stats);
+
+ main_thread_id = g_thread_self ();
+ GST_DEBUG ("rusage: main thread=%p", main_thread_id);
}
static void
GstTracerMessageId mid, va_list var_args)
{
GstRUsageTracer *self = GST_RUSAGE_TRACER_CAST (obj);
- guint64 treal = va_arg (var_args, guint64);
+ guint64 ts = va_arg (var_args, guint64);
GstThreadStats *stats;
gpointer thread_id = g_thread_self ();
guint cpuload = 0;
struct rusage ru;
- GstClockTime tusersys = G_GUINT64_CONSTANT (0);
+ GstClockTime tproc = G_GUINT64_CONSTANT (0);
// FIXME(ensonic): not threadsafe
static GstClockTime last_ts = G_GUINT64_CONSTANT (0);
struct timespec now;
if (!clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &now)) {
- tusersys = GST_TIMESPEC_TO_TIME (now);
+ tproc = GST_TIMESPEC_TO_TIME (now);
} else {
GST_WARNING ("clock_gettime (CLOCK_PROCESS_CPUTIME_ID,...) failed.");
- tusersys =
+ tproc =
GST_TIMEVAL_TO_TIME (ru.ru_utime) + GST_TIMEVAL_TO_TIME (ru.ru_stime);
}
/* cpu time per thread */
if (!clock_gettime (CLOCK_THREAD_CPUTIME_ID, &now)) {
- stats->treal = GST_TIMESPEC_TO_TIME (now);
+ stats->tthread = GST_TIMESPEC_TO_TIME (now);
} else {
GST_WARNING ("clock_gettime (CLOCK_THREAD_CPUTIME_ID,...) failed.");
- stats->treal += GST_CLOCK_DIFF (last_ts, treal);
+ stats->tthread += GST_CLOCK_DIFF (last_ts, ts);
}
}
#else
- tusersys =
- GST_TIMEVAL_TO_TIME (ru.ru_utime) + GST_TIMEVAL_TO_TIME (ru.ru_stime);
+ tproc = GST_TIMEVAL_TO_TIME (ru.ru_utime) + GST_TIMEVAL_TO_TIME (ru.ru_stime);
/* crude way to meassure time spend in which thread */
- stats->treal += GST_CLOCK_DIFF (last_ts, treal);
+ stats->tthread += GST_CLOCK_DIFF (last_ts, ts);
#endif
- /* remember last timestamp for percentage calculations */
- last_ts = treal;
+ /* remember last timestamp for fallback calculations */
+ last_ts = ts;
+
+ /* Calibrate ts for the process and main thread. For tthread[main] and tproc
+ * the time is larger than ts, as our base-ts is taken after the process has
+ * started.
+ */
+ if (G_UNLIKELY (thread_id == main_thread_id)) {
+ main_thread_id = NULL;
+ /* when the registry gets updated, the tproc is less than the debug time ? */
+ /* TODO(ensonic): we still see cases where tproc overtakes ts, especially
+ * when with sync=false, can this be due to multiple cores in use? */
+ if (tproc > ts) {
+ tproc_base = tproc - ts;
+ GST_DEBUG ("rusage: calibrating by %" G_GUINT64_FORMAT ", thread: %"
+ G_GUINT64_FORMAT ", proc: %" G_GUINT64_FORMAT,
+ tproc_base, stats->tthread, tproc);
+ stats->tthread -= tproc_base;
+ }
+ }
+ /* we always need to corect proc time */
+ tproc -= tproc_base;
/* FIXME: how can we take cpu-frequency scaling into account?
* - looking at /sys/devices/system/cpu/cpu0/cpufreq/
* cpufreq-selector -g performance
* cpufreq-selector -g ondemand
*/
- cpuload =
- (guint) gst_util_uint64_scale (tusersys, G_GINT64_CONSTANT (100), treal);
- gst_tracer_log_trace (gst_structure_new ("rusage", "ts", G_TYPE_UINT64, treal, "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (thread_id), "cpuload", G_TYPE_UINT, cpuload, "treal", G_TYPE_UINT64, stats->treal, /* time in thread */
- "tsum", G_TYPE_UINT64, tusersys, /* time in process */
+ cpuload = (guint) gst_util_uint64_scale (tproc, G_GINT64_CONSTANT (100), ts);
+ gst_tracer_log_trace (gst_structure_new ("rusage", "ts", G_TYPE_UINT64, ts, "thread-id", G_TYPE_UINT, GPOINTER_TO_UINT (thread_id), "cpuload", G_TYPE_UINT, cpuload, /* cpu usage per thread - FIXME: not used in gst-stats */
+ "thread-time", G_TYPE_UINT64, stats->tthread, /* time spent in thread */
+ "proc-time", G_TYPE_UINT64, tproc, /* time spent in process */
NULL));
}
0;
static guint num_elements = 0, num_bins = 0, num_pads = 0, num_ghostpads = 0;
static GstClockTime last_ts = G_GUINT64_CONSTANT (0);
-static GstClockTime tusersys = G_GUINT64_CONSTANT (0);
-static guint64 total_cpuload = 0;
+static GstClockTime tproc = G_GUINT64_CONSTANT (0);
typedef struct
{
/* first activity on the element */
GstClockTime first_ts, last_ts;
/* time spend in this element */
- GstClockTime treal;
+ GstClockTime tthread;
/* hierarchy */
guint parent_ix;
} GstElementStats;
typedef struct
{
/* time spend in this thread */
- GstClockTime treal;
+ GstClockTime tthread;
} GstThreadStats;
/* stats helper */
"buffer-ts", G_TYPE_UINT64, &buffer_ts,
"buffer-duration", G_TYPE_UINT64, &buffer_dur,
"buffer-flags", GST_TYPE_BUFFER_FLAGS, &buffer_flags, NULL);
- last_ts = ts;
+ last_ts = MAX (last_ts, ts);
if (!(pad_stats = get_pad_stats (pad_ix))) {
GST_WARNING ("no pad stats found for ix=%u", pad_ix);
return;
num_events++;
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts,
"pad-ix", G_TYPE_UINT, &pad_ix, "elem-ix", G_TYPE_UINT, &elem_ix, NULL);
- last_ts = ts;
+ last_ts = MAX (last_ts, ts);
if (!(pad_stats = get_pad_stats (pad_ix))) {
GST_WARNING ("no pad stats found for ix=%u", pad_ix);
return;
num_messages++;
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts,
"elem-ix", G_TYPE_UINT, &elem_ix, NULL);
- last_ts = ts;
+ last_ts = MAX (last_ts, ts);
if (!(elem_stats = get_element_stats (elem_ix))) {
GST_WARNING ("no element stats found for ix=%u", elem_ix);
return;
num_queries++;
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts,
"elem-ix", G_TYPE_UINT, &elem_ix, NULL);
- last_ts = ts;
+ last_ts = MAX (last_ts, ts);
if (!(elem_stats = get_element_stats (elem_ix))) {
GST_WARNING ("no element stats found for ix=%u", elem_ix);
return;
static void
do_rusage_stats (GstStructure * s)
{
- guint64 ts, treal;
- guint thread_id, cpuload;
+ guint64 ts, tthread;
+ guint thread_id;
GstThreadStats *thread_stats;
gst_structure_get (s, "ts", G_TYPE_UINT64, &ts,
"thread-id", G_TYPE_UINT, &thread_id,
- "cpuload", G_TYPE_UINT, &cpuload,
- "treal", G_TYPE_UINT64, &treal, "tsum", G_TYPE_UINT64, &tusersys, NULL);
+ "thread-time", G_TYPE_UINT64, &tthread,
+ "proc-time", G_TYPE_UINT64, &tproc, NULL);
thread_stats = get_thread_stats (thread_id);
- thread_stats->treal = treal;
- last_ts = ts;
+ thread_stats->tthread = tthread;
+ last_ts = MAX (last_ts, ts);
}
/* reporting */
GSList *list = user_data;
GSList *node = g_slist_find_custom (list, key, find_pad_stats_for_thread);
GstThreadStats *stats = (GstThreadStats *) value;
- guint cpuload = 0;
- guint time_percent;
+ guint cpuload;
/* skip stats if there are no pads for that thread (e.g. a pipeline) */
if (!node)
return;
- time_percent =
- (guint) gst_util_uint64_scale (stats->treal, G_GINT64_CONSTANT (100),
+ cpuload =
+ (guint) gst_util_uint64_scale (stats->tthread, G_GINT64_CONSTANT (100),
last_ts);
- if (total_cpuload) {
- cpuload =
- (guint) gst_util_uint64_scale (total_cpuload, stats->treal, last_ts);
- }
-
printf ("Thread %p Statistics:\n", key);
- printf (" Time: %" GST_TIME_FORMAT ", %u %%\n", GST_TIME_ARGS (stats->treal),
- (guint) time_percent);
+ printf (" Time: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (stats->tthread));
printf (" Avg CPU load: %u %%\n", cpuload);
puts (" Pad Statistics:");
print_stats (void)
{
guint num_threads = g_hash_table_size (threads);
+ guint64 total_cpuload = 0;
/* print overall stats */
puts ("\nOverall Statistics:");
printf ("Number of Message sent: %" G_GUINT64_FORMAT "\n", num_messages);
printf ("Number of Queries sent: %" G_GUINT64_FORMAT "\n", num_queries);
printf ("Time: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (last_ts));
- if (tusersys) {
- total_cpuload = gst_util_uint64_scale (tusersys,
+ if (tproc) {
+ total_cpuload = gst_util_uint64_scale (tproc,
G_GINT64_CONSTANT (100), last_ts);
printf ("Avg CPU load: %u %%\n", (guint) total_cpuload);
}