qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log
@ 2013-10-25 22:30 Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 1/4] Timers: add debugging macros wrapping timer functions and debug structures Alex Bligh
                   ` (4 more replies)
  0 siblings, 5 replies; 10+ messages in thread
From: Alex Bligh @ 2013-10-25 22:30 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Anthony Liguori, Alex Bligh, Jan Kiszka, liu ping fan,
	Stefan Hajnoczi, Paolo Bonzini, MORITA Kazutaka, rth

This patch set adds facilities for debugging timers using the additional
command line option -timer-debug-log=FILE. If this option is selected,
a debugging file will be written showing information about the current
state of timers in the system, which the author feels will be useful for
debugging in the field.

Note that the option is a command line option rather than a configure
time option. This is because users in the field having issues are unlikely
to have a compile time option enabled.

It would be useful to get this feature in prior to 1.7 as it has little
impact other than making a major change to a subsystem more debuggable.
This patch has been lightly test.

Impact of changes whether or not -timer-debug-log is specified:

1. QEMUTimer is expanded to hold additional debugging information. Some
   of this is unused when the command line option is unspecified.

2. The file and line number of the caller that allocated the timer are
   recorded. This is useful for debugging in gdb.

It is felt these are minimal in nature.

Additional impact of changes only when -timer-debug-log is specified:

1. On every timer modification, the current clock time for that timer
   is read, and the additional debug information filled in.

2. Every second (roughly) a file is written (atomically) containing the
   timer debug information.

The debug information includes information on the number of timer
expiries since the timer was created, the average expiry time (in
nanoseconds), and the number of short expiries, being the number of
times the timer was asked to expire in less than one microsecond
(these usually but not always indicate a bug).

The file format is designed to be useful both to a mailing list and
to a user armed with gdb. An example of the output follows:

Timer list at 0x7f4d6cf0d6e0 clock 0:
           Address       Expiries      AvgLength       NumShort Source

Timer list at 0x7f4d6cf0cbc0 clock 0:
           Address       Expiries      AvgLength       NumShort Source

Timer list at 0x7f4d6cf0d750 clock 1:
           Address       Expiries      AvgLength       NumShort Source

Timer list at 0x7f4d6cf0cc30 clock 1:
           Address       Expiries      AvgLength       NumShort Source
    0x7f4d6cf51550              1       27462700              0 i8254.c:333

Timer list at 0x7f4d6cf0d7c0 clock 2:
           Address       Expiries      AvgLength       NumShort Source

Timer list at 0x7f4d6cf0cca0 clock 2:
           Address       Expiries      AvgLength       NumShort Source
    0x7f4d6cf6eed0              1      999997000              0 mc146818rtc.c:858

Note that the somewhat strange choice to output to a file has been taken
because the tracing infrastructure is unlikely to be enabled in a distro
environment.

Alex Bligh (4):
  Timers: add debugging macros wrapping timer functions and debug
    structures
  Timers: add command line option -timer-debug-log
  Timers: Instrument timer_mod
  Timers: produce timer-debug-log file

 include/block/aio.h  |   20 ++++++---
 include/qemu/timer.h |   70 ++++++++++++++++++++++--------
 qemu-options.hx      |   11 +++++
 qemu-timer.c         |  118 ++++++++++++++++++++++++++++++++++++++++++++++++--
 vl.c                 |    3 ++
 5 files changed, 194 insertions(+), 28 deletions(-)

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCHv1 1/4] Timers: add debugging macros wrapping timer functions and debug structures
  2013-10-25 22:30 [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Alex Bligh
@ 2013-10-25 22:30 ` Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 2/4] Timers: add command line option -timer-debug-log Alex Bligh
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Alex Bligh @ 2013-10-25 22:30 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Anthony Liguori, Alex Bligh, Jan Kiszka, liu ping fan,
	Stefan Hajnoczi, Paolo Bonzini, MORITA Kazutaka, rth

Add debugging versions of functions creating timers to record the
file and line number that they were called from. Add macros to
call these transparently. Add fields to timer struct to store
debugging information.

Note this patch contains one checkpatch.pl warning (space before
parenthesis) and a rather arcane double stringify macro. These
are copied from audio_int.h and I believe are to work around
compiler incompatibilities.

Signed-off-by: Alex Bligh <alex@alex.org.uk>
---
 include/block/aio.h  |   20 ++++++++++-----
 include/qemu/timer.h |   69 ++++++++++++++++++++++++++++++++++++--------------
 qemu-timer.c         |    8 +++---
 3 files changed, 69 insertions(+), 28 deletions(-)

diff --git a/include/block/aio.h b/include/block/aio.h
index 2efdf41..199728f 100644
--- a/include/block/aio.h
+++ b/include/block/aio.h
@@ -262,13 +262,17 @@ void qemu_aio_set_fd_handler(int fd,
  *
  * Returns: a pointer to the new timer
  */
-static inline QEMUTimer *aio_timer_new(AioContext *ctx, QEMUClockType type,
-                                       int scale,
-                                       QEMUTimerCB *cb, void *opaque)
+static inline QEMUTimer *aio_timer_new_dbg(AioContext *ctx, QEMUClockType type,
+                                           int scale,
+                                           QEMUTimerCB *cb, void *opaque,
+                                           const char *dbg)
 {
-    return timer_new_tl(ctx->tlg.tl[type], scale, cb, opaque);
+    return timer_new_tl_dbg(ctx->tlg.tl[type], scale, cb, opaque, dbg);
 }
 
+#define aio_timer_new(ctx, type, scale, opaque) \
+    aio_timer_new_dbg(ctx, type, scale, opaque, TIMER_DBG)
+
 /**
  * aio_timer_init:
  * @ctx: the aio context
@@ -284,9 +288,13 @@ static inline QEMUTimer *aio_timer_new(AioContext *ctx, QEMUClockType type,
 static inline void aio_timer_init(AioContext *ctx,
                                   QEMUTimer *ts, QEMUClockType type,
                                   int scale,
-                                  QEMUTimerCB *cb, void *opaque)
+                                  QEMUTimerCB *cb, void *opaque,
+                                  const char *dbg)
 {
-    timer_init(ts, ctx->tlg.tl[type], scale, cb, opaque);
+    timer_init_dbg(ts, ctx->tlg.tl[type], scale, cb, opaque, dbg);
 }
 
+#define aio_timer_init(ctx, ts, type, scale, cb, opaque) \
+    aio_timer_init(ctx, ts, type, scale, cb, opaque, TIMER_DBG)
+
 #endif
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 5afcffc..d3ab5b0 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -11,6 +11,11 @@
 #define SCALE_US 1000
 #define SCALE_NS 1
 
+/* debugging macros */
+#define TIMER_STRINGIFY_(n) #n
+#define TIMER_STRINGIFY(n) TIMER_STRINGIFY_(n)
+#define TIMER_DBG __FILE__ ":" TIMER_STRINGIFY (__LINE__)
+
 /**
  * QEMUClockType:
  *
@@ -61,6 +66,12 @@ struct QEMUTimer {
     void *opaque;
     QEMUTimer *next;
     int scale;
+
+    /* these items are only used when debugging */
+    const char *dbg;
+    int64_t tot_deltas;
+    int64_t num_deltas;
+    int64_t num_short;
 };
 
 extern QEMUTimerListGroup main_loop_tlg;
@@ -415,9 +426,13 @@ int64_t timerlistgroup_deadline_ns(QEMUTimerListGroup *tlg);
  * You need not call an explicit deinit call. Simply make
  * sure it is not on a list with timer_del.
  */
-void timer_init(QEMUTimer *ts,
-                QEMUTimerList *timer_list, int scale,
-                QEMUTimerCB *cb, void *opaque);
+void timer_init_dbg(QEMUTimer *ts,
+                    QEMUTimerList *timer_list, int scale,
+                    QEMUTimerCB *cb, void *opaque,
+                    const char *dbg);
+
+#define timer_init(ts, timer_list, scale, cb, opaque) \
+    timer_init_dbg(ts, timer_list, scale, cb, opaque, TIMER_DBG)
 
 /**
  * timer_new_tl:
@@ -434,16 +449,20 @@ void timer_init(QEMUTimer *ts,
  *
  * Returns: a pointer to the timer
  */
-static inline QEMUTimer *timer_new_tl(QEMUTimerList *timer_list,
-                                      int scale,
-                                      QEMUTimerCB *cb,
-                                      void *opaque)
+static inline QEMUTimer *timer_new_tl_dbg(QEMUTimerList *timer_list,
+                                          int scale,
+                                          QEMUTimerCB *cb,
+                                          void *opaque,
+                                          const char *dbg)
 {
     QEMUTimer *ts = g_malloc0(sizeof(QEMUTimer));
-    timer_init(ts, timer_list, scale, cb, opaque);
+    timer_init_dbg(ts, timer_list, scale, cb, opaque, dbg);
     return ts;
 }
 
+#define timer_new_tl(timer_list, scale, cb, opaque) \
+    timer_new_tl_dbg(timer_list, scale, cb, opaque, TIMER_DBG)
+
 /**
  * timer_new:
  * @type: the clock type to use
@@ -456,12 +475,16 @@ static inline QEMUTimer *timer_new_tl(QEMUTimerList *timer_list,
  *
  * Returns: a pointer to the timer
  */
-static inline QEMUTimer *timer_new(QEMUClockType type, int scale,
-                                   QEMUTimerCB *cb, void *opaque)
+static inline QEMUTimer *timer_new_dbg(QEMUClockType type, int scale,
+                                       QEMUTimerCB *cb, void *opaque,
+                                       const char *dbg)
 {
-    return timer_new_tl(main_loop_tlg.tl[type], scale, cb, opaque);
+    return timer_new_tl_dbg(main_loop_tlg.tl[type], scale, cb, opaque, dbg);
 }
 
+#define timer_new(type, scale, cb, opaque) \
+    timer_new_dbg(type, scale, cb, opaque, TIMER_DBG)
+
 /**
  * timer_new_ns:
  * @clock: the clock to associate with the timer
@@ -473,12 +496,15 @@ static inline QEMUTimer *timer_new(QEMUClockType type, int scale,
  *
  * Returns: a pointer to the newly created timer
  */
-static inline QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb,
-                                      void *opaque)
+static inline QEMUTimer *timer_new_ns_dbg(QEMUClockType type, QEMUTimerCB *cb,
+                                          void *opaque, const char *dbg)
 {
-    return timer_new(type, SCALE_NS, cb, opaque);
+    return timer_new_dbg(type, SCALE_NS, cb, opaque, dbg);
 }
 
+#define timer_new_ns(type, cb, opaque) \
+    timer_new_ns_dbg(type, cb, opaque, TIMER_DBG)
+
 /**
  * timer_new_us:
  * @clock: the clock to associate with the timer
@@ -491,11 +517,14 @@ static inline QEMUTimer *timer_new_ns(QEMUClockType type, QEMUTimerCB *cb,
  * Returns: a pointer to the newly created timer
  */
 static inline QEMUTimer *timer_new_us(QEMUClockType type, QEMUTimerCB *cb,
-                                      void *opaque)
+                                      void *opaque, const char *dbg)
 {
-    return timer_new(type, SCALE_US, cb, opaque);
+    return timer_new_dbg(type, SCALE_US, cb, opaque, dbg);
 }
 
+#define timer_new_us(type, cb, opaque) \
+    timer_new_us_dbg(type, cb, opaque, TIMER_DBG)
+
 /**
  * timer_new_ms:
  * @clock: the clock to associate with the timer
@@ -507,11 +536,13 @@ static inline QEMUTimer *timer_new_us(QEMUClockType type, QEMUTimerCB *cb,
  *
  * Returns: a pointer to the newly created timer
  */
-static inline QEMUTimer *timer_new_ms(QEMUClockType type, QEMUTimerCB *cb,
-                                      void *opaque)
+static inline QEMUTimer *timer_new_ms_dbg(QEMUClockType type, QEMUTimerCB *cb,
+                                          void *opaque, const char *dbg)
 {
-    return timer_new(type, SCALE_MS, cb, opaque);
+    return timer_new_dbg(type, SCALE_MS, cb, opaque, dbg);
 }
+#define timer_new_ms(type, cb, opaque) \
+    timer_new_ms_dbg(type, cb, opaque, TIMER_DBG)
 
 /**
  * timer_free:
diff --git a/qemu-timer.c b/qemu-timer.c
index e15ce47..0e358ac 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -321,15 +321,17 @@ int qemu_poll_ns(GPollFD *fds, guint nfds, int64_t timeout)
 }
 
 
-void timer_init(QEMUTimer *ts,
-                QEMUTimerList *timer_list, int scale,
-                QEMUTimerCB *cb, void *opaque)
+void timer_init_dbg(QEMUTimer *ts,
+                    QEMUTimerList *timer_list, int scale,
+                    QEMUTimerCB *cb, void *opaque,
+                    const char *dbg)
 {
     ts->timer_list = timer_list;
     ts->cb = cb;
     ts->opaque = opaque;
     ts->scale = scale;
     ts->expire_time = -1;
+    ts->dbg = dbg;
 }
 
 void timer_free(QEMUTimer *ts)
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCHv1 2/4] Timers: add command line option -timer-debug-log
  2013-10-25 22:30 [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 1/4] Timers: add debugging macros wrapping timer functions and debug structures Alex Bligh
@ 2013-10-25 22:30 ` Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 3/4] Timers: Instrument timer_mod Alex Bligh
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 10+ messages in thread
From: Alex Bligh @ 2013-10-25 22:30 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Anthony Liguori, Alex Bligh, Jan Kiszka, liu ping fan,
	Stefan Hajnoczi, Paolo Bonzini, MORITA Kazutaka, rth

Add a command line option -timer-debug-log which takes the name
of a file to which periodic timer debugging information will be
written.

Signed-off-by: Alex Bligh <alex@alex.org.uk>
---
 include/qemu/timer.h |    1 +
 qemu-options.hx      |   11 +++++++++++
 qemu-timer.c         |    1 +
 vl.c                 |    3 +++
 4 files changed, 16 insertions(+)

diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index d3ab5b0..1f7c5e4 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -75,6 +75,7 @@ struct QEMUTimer {
 };
 
 extern QEMUTimerListGroup main_loop_tlg;
+extern const char *timer_debug_log;
 
 /*
  * QEMUClockType
diff --git a/qemu-options.hx b/qemu-options.hx
index 5dc8b75..605c1b9 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -3116,6 +3116,17 @@ STEXI
 prepend a timestamp to each log message.(default:on)
 ETEXI
 
+DEF("timer-debug-log", HAS_ARG, QEMU_OPTION_timer_debug_log,
+    "-timer-debug-log FILE\n"
+    "                write timer debug log to FILE (default: don't write)",
+    QEMU_ARCH_ALL)
+STEXI
+@item -timer-debug-log @var{file}
+@findex -timer-debug-log
+Write timer debug output periodically to file @var{file}. By default,
+no timer debug logging is written.
+ETEXI
+
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
 @end table
diff --git a/qemu-timer.c b/qemu-timer.c
index 0e358ac..84a8932 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -57,6 +57,7 @@ typedef struct QEMUClock {
 
 QEMUTimerListGroup main_loop_tlg;
 QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
+const char *timer_debug_log;
 
 /* A QEMUTimerList is a list of timers attached to a clock. More
  * than one QEMUTimerList can be attached to each clock, for instance
diff --git a/vl.c b/vl.c
index b42ac67..4564207 100644
--- a/vl.c
+++ b/vl.c
@@ -3794,6 +3794,9 @@ int main(int argc, char **argv, char **envp)
                 }
                 configure_msg(opts);
                 break;
+            case QEMU_OPTION_timer_debug_log:
+                timer_debug_log = optarg;
+                break;
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCHv1 3/4] Timers: Instrument timer_mod
  2013-10-25 22:30 [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 1/4] Timers: add debugging macros wrapping timer functions and debug structures Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 2/4] Timers: add command line option -timer-debug-log Alex Bligh
@ 2013-10-25 22:30 ` Alex Bligh
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 4/4] Timers: produce timer-debug-log file Alex Bligh
  2013-10-25 23:00 ` [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Paolo Bonzini
  4 siblings, 0 replies; 10+ messages in thread
From: Alex Bligh @ 2013-10-25 22:30 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Anthony Liguori, Alex Bligh, Jan Kiszka, liu ping fan,
	Stefan Hajnoczi, Paolo Bonzini, MORITA Kazutaka, rth

Add instrumentation for timer_mod to allow measurement of the
average time delta to expiry plus the number of short delta
periods. This is only run when logging to a file because
getting the clock value may add appreciable expense.

Signed-off-by: Alex Bligh <alex@alex.org.uk>
---
 qemu-timer.c |   17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/qemu-timer.c b/qemu-timer.c
index 84a8932..16eaa1f 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -376,6 +376,23 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
     ts->next = *pt;
     *pt = ts;
 
+    if (timer_debug_log) {
+        int64_t delta;
+
+        delta = ts->expire_time -
+            qemu_clock_get_ns(ts->timer_list->clock->type);
+        if (delta <= 0) {
+            delta = 0;
+        }
+
+        ts->tot_deltas += delta;
+        ts->num_deltas++;
+
+        if (delta < SCALE_US) {
+            ts->num_short++;
+        }
+    }
+
     return pt == &timer_list->active_timers;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [Qemu-devel] [PATCHv1 4/4] Timers: produce timer-debug-log file
  2013-10-25 22:30 [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Alex Bligh
                   ` (2 preceding siblings ...)
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 3/4] Timers: Instrument timer_mod Alex Bligh
@ 2013-10-25 22:30 ` Alex Bligh
  2013-10-25 23:00 ` [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Paolo Bonzini
  4 siblings, 0 replies; 10+ messages in thread
From: Alex Bligh @ 2013-10-25 22:30 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Anthony Liguori, Alex Bligh, Jan Kiszka, liu ping fan,
	Stefan Hajnoczi, Paolo Bonzini, MORITA Kazutaka, rth

Write a timer-debug-log file if enabled containing data about the
currently existing timers.

Signed-off-by: Alex Bligh <alex@alex.org.uk>
---
 qemu-timer.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/qemu-timer.c b/qemu-timer.c
index 16eaa1f..cbce7ba 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -58,6 +58,7 @@ typedef struct QEMUClock {
 QEMUTimerListGroup main_loop_tlg;
 QEMUClock qemu_clocks[QEMU_CLOCK_MAX];
 const char *timer_debug_log;
+static int64_t timer_last_debug;
 
 /* A QEMUTimerList is a list of timers attached to a clock. More
  * than one QEMUTimerList can be attached to each clock, for instance
@@ -396,6 +397,93 @@ static bool timer_mod_ns_locked(QEMUTimerList *timer_list,
     return pt == &timer_list->active_timers;
 }
 
+static void timer_debug(void)
+{
+    GString *debug_text;
+    GString *tmpfile;
+    QEMUClockType type;
+    FILE *f;
+    uint64_t now;
+
+    if (!timer_debug_log) {
+        return;
+    }
+
+    /* In order not to avoid influencing the output, we don't use a timer
+     * here, but use this disappointingly manual method.
+     */
+    now = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+    if ((now - timer_last_debug) < 1000 * SCALE_MS) {
+        return;
+    }
+    timer_last_debug = now;
+
+    debug_text = g_string_new("");
+    tmpfile = g_string_new(timer_debug_log);
+    g_string_append(tmpfile, ".tmp");
+
+    for (type = 0; type < QEMU_CLOCK_MAX; type++) {
+        QEMUTimerList *timer_list;
+        QEMUClock *clock = qemu_clock_ptr(type);
+
+        /* Iteration through timerlists means we need the BQL held to
+         * call this safely.
+         */
+        QLIST_FOREACH(timer_list, &clock->timerlists, list) {
+            QEMUTimer *ts;
+
+            g_string_append_printf(debug_text, "\nTimer list at %p clock %d:\n",
+                                   timer_list, (int) type);
+            g_string_append_printf(debug_text, "%18s %14s %14s %14s %s\n",
+                                   "Address",
+                                   "Expiries",
+                                   "AvgLength",
+                                   "NumShort",
+                                   "Source");
+            qemu_mutex_lock(&timer_list->active_timers_lock);
+            ts = timer_list->active_timers;
+            for (ts = timer_list->active_timers; ts; ts = ts->next) {
+                int64_t avg = -1;
+                if (ts->num_deltas) {
+                    avg = (ts->tot_deltas + (ts->num_deltas/2)) /
+                        ts->num_deltas;
+                }
+                const char *src = "unknown";
+                if (ts->dbg) {
+                    const char *slash;
+                    src = ts->dbg;
+                    slash = strrchr(src, '/');
+                    if (!slash) {
+                        slash = strrchr(src, '\\');
+                    }
+                    if (slash) {
+                        src = slash+1;
+                    }
+                }
+
+                g_string_append_printf(debug_text, "%18p %14" PRId64 " %14"
+                                       PRId64 " %14" PRId64" %s\n",
+                                       ts,
+                                       ts->num_deltas,
+                                       avg,
+                                       ts->num_short,
+                                       src);
+            }
+            qemu_mutex_unlock(&timer_list->active_timers_lock);
+        }
+    }
+
+    f = fopen(tmpfile->str, "w");
+    if (f) {
+        fprintf(f, "%s", debug_text->str);
+        fclose(f);
+        rename(tmpfile->str, timer_debug_log);
+    }
+
+    g_string_free(tmpfile, true);
+    g_string_free(debug_text, true);
+}
+
 static void timerlist_rearm(QEMUTimerList *timer_list)
 {
     /* Interrupt execution to force deadline recalculation.  */
@@ -621,6 +709,10 @@ bool qemu_clock_run_all_timers(void)
     bool progress = false;
     QEMUClockType type;
 
+    if (timer_debug_log) {
+        timer_debug();
+    }
+
     for (type = 0; type < QEMU_CLOCK_MAX; type++) {
         progress |= qemu_clock_run_timers(type);
     }
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log
  2013-10-25 22:30 [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Alex Bligh
                   ` (3 preceding siblings ...)
  2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 4/4] Timers: produce timer-debug-log file Alex Bligh
@ 2013-10-25 23:00 ` Paolo Bonzini
  2013-10-26  5:52   ` Alex Bligh
  4 siblings, 1 reply; 10+ messages in thread
From: Paolo Bonzini @ 2013-10-25 23:00 UTC (permalink / raw)
  To: Alex Bligh
  Cc: Kevin Wolf, Anthony Liguori, Jan Kiszka, qemu-devel, liu ping fan,
	Stefan Hajnoczi, MORITA Kazutaka, rth

Il 25/10/2013 23:30, Alex Bligh ha scritto:
> This patch set adds facilities for debugging timers using the additional
> command line option -timer-debug-log=FILE. If this option is selected,
> a debugging file will be written showing information about the current
> state of timers in the system, which the author feels will be useful for
> debugging in the field.
> 
> Note that the option is a command line option rather than a configure
> time option. This is because users in the field having issues are unlikely
> to have a compile time option enabled.
> 
> It would be useful to get this feature in prior to 1.7 as it has little
> impact other than making a major change to a subsystem more debuggable.
> This patch has been lightly test.
> 
> Impact of changes whether or not -timer-debug-log is specified:
> 
> 1. QEMUTimer is expanded to hold additional debugging information. Some
>    of this is unused when the command line option is unspecified.
> 
> 2. The file and line number of the caller that allocated the timer are
>    recorded. This is useful for debugging in gdb.
> 
> It is felt these are minimal in nature.
> 
> Additional impact of changes only when -timer-debug-log is specified:
> 
> 1. On every timer modification, the current clock time for that timer
>    is read, and the additional debug information filled in.
> 
> 2. Every second (roughly) a file is written (atomically) containing the
>    timer debug information.
> 
> The debug information includes information on the number of timer
> expiries since the timer was created, the average expiry time (in
> nanoseconds), and the number of short expiries, being the number of
> times the timer was asked to expire in less than one microsecond
> (these usually but not always indicate a bug).
> 
> The file format is designed to be useful both to a mailing list and
> to a user armed with gdb. An example of the output follows:
> 
> Timer list at 0x7f4d6cf0d6e0 clock 0:
>            Address       Expiries      AvgLength       NumShort Source
> 
> Timer list at 0x7f4d6cf0cbc0 clock 0:
>            Address       Expiries      AvgLength       NumShort Source
> 
> Timer list at 0x7f4d6cf0d750 clock 1:
>            Address       Expiries      AvgLength       NumShort Source
> 
> Timer list at 0x7f4d6cf0cc30 clock 1:
>            Address       Expiries      AvgLength       NumShort Source
>     0x7f4d6cf51550              1       27462700              0 i8254.c:333
> 
> Timer list at 0x7f4d6cf0d7c0 clock 2:
>            Address       Expiries      AvgLength       NumShort Source
> 
> Timer list at 0x7f4d6cf0cca0 clock 2:
>            Address       Expiries      AvgLength       NumShort Source
>     0x7f4d6cf6eed0              1      999997000              0 mc146818rtc.c:858
> 
> Note that the somewhat strange choice to output to a file has been taken
> because the tracing infrastructure is unlikely to be enabled in a distro
> environment.

This is a bug in the distro, if it is Linux.  There is no reason not to
enable the stap trace format when running on Linux (Fedora does for
other packages than QEMU, too---most notably glib and glibc).

If it is useful, adding debugging information to timer_new_ns (please
make file and line two separate arguments, though) can definitely be
done unconditionally and added to the traces.  I think adding a
tracepoint in timerlist_run_timers would provide very similar
information to that in your file.

Paolo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log
  2013-10-25 23:00 ` [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Paolo Bonzini
@ 2013-10-26  5:52   ` Alex Bligh
  2013-10-26  7:18     ` Paolo Bonzini
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Bligh @ 2013-10-26  5:52 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi, Jan Kiszka,
	qemu-devel, liu ping fan, Alex Bligh, MORITA Kazutaka, rth


On 26 Oct 2013, at 00:00, Paolo Bonzini wrote:

> his is a bug in the distro, if it is Linux.  There is no reason not to
> enable the stap trace format when running on Linux (Fedora does for
> other packages than QEMU, too---most notably glib and glibc).
> 
> If it is useful, adding debugging information to timer_new_ns (please
> make file and line two separate arguments, though) can definitely be
> done unconditionally and added to the traces.  I think adding a
> tracepoint in timerlist_run_timers would provide very similar
> information to that in your file.

I read the tracepoint information. Doesn't that require the end
user to have far more skills (and far more stuff installed) to
get things like "average expiry delta"? Especially as that's
not something we'd normally calculate as we don't get the clock
value when setting a timer normally.

-- 
Alex Bligh

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log
  2013-10-26  5:52   ` Alex Bligh
@ 2013-10-26  7:18     ` Paolo Bonzini
  2013-10-26  8:24       ` Alex Bligh
  0 siblings, 1 reply; 10+ messages in thread
From: Paolo Bonzini @ 2013-10-26  7:18 UTC (permalink / raw)
  To: Alex Bligh
  Cc: Kevin Wolf, Anthony Liguori, Jan Kiszka, qemu-devel, liu ping fan,
	Stefan Hajnoczi, MORITA Kazutaka, rth

Il 26/10/2013 06:52, Alex Bligh ha scritto:
> 
> On 26 Oct 2013, at 00:00, Paolo Bonzini wrote:
> 
>> his is a bug in the distro, if it is Linux.  There is no reason not to
>> enable the stap trace format when running on Linux (Fedora does for
>> other packages than QEMU, too---most notably glib and glibc).
>>
>> If it is useful, adding debugging information to timer_new_ns (please
>> make file and line two separate arguments, though) can definitely be
>> done unconditionally and added to the traces.  I think adding a
>> tracepoint in timerlist_run_timers would provide very similar
>> information to that in your file.
> 
> I read the tracepoint information. Doesn't that require the end
> user to have far more skills (and far more stuff installed) to
> get things like "average expiry delta"? Especially as that's
> not something we'd normally calculate as we don't get the clock
> value when setting a timer normally.

The simple trace backend includes a nanosecond value that is the same as
rt_clock, so you can correlate the last timer_mod with the next
iteration in timerlist_run_timers (I would put the tracepoint inside the
loop, just before the callback is done).  Similarly, in systemtap you
can just use the builtin gettimeofday_ns() function

All clocks are basically in nanoseconds (the only difference between
vm_clock and rt_clock is that the former stops when the VM is stopped),
so you can get the average expiry delta from there.

Of course it requires some postprocessing or a systemtap script, but we
can put that into scripts/ or give it to the user.  See
https://sourceware.org/ml/systemtap/2011-q3/txt00003.txt for an example,
I suppose the "expiry time" computation would look like this:

global modtime, expirytot, firedcnt

probe qemu.system.x86_64.timer_mod {
   loc = sprintf("%s:%d", timer_file, timer_line)
   modtime[pid(), loc] = gettimeofday_ns()
}
probe qemu.system.x86_64.timer_run {
   loc = sprintf("%s:%d", timer_file, timer_line)
   expirytot[pid(), loc] += gettimeofday_ns() - modtime[pid(), loc]
   firedcnt[pid(), loc]++
}

probe end
{
  printf("\n%8s %28s %8s %8s\n", "pid", "loc", "avg expiry", "cnt")
  foreach([p+, loc] in firedcnt) {
    printf("%8d %28s %8d %8d\n", p, loc,
        expirytot[p, loc] / firedcnt[p, loc],
        firedcnt[p, loc])
  }
}

which I wrote based on the example at
http://cygwin.com/ml/systemtap/2011-q3/msg00316.html

I understand your usecase, but it's not really feasible to add a logging
option for each tracing need; it's much better to add new tracepoints
and distribute sample systemtap scripts.  And please "lobby" your distro
for enabling systemtap support and distributing the .stp file!

Paolo

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log
  2013-10-26  7:18     ` Paolo Bonzini
@ 2013-10-26  8:24       ` Alex Bligh
  2013-10-26 17:11         ` Paolo Bonzini
  0 siblings, 1 reply; 10+ messages in thread
From: Alex Bligh @ 2013-10-26  8:24 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Kevin Wolf, Anthony Liguori, Stefan Hajnoczi, Jan Kiszka,
	qemu-devel, liu ping fan, Alex Bligh, MORITA Kazutaka, rth

Paolo,

On 26 Oct 2013, at 08:18, Paolo Bonzini wrote:

> The simple trace backend includes a nanosecond value that is the same as
> rt_clock, so you can correlate the last timer_mod with the next
> iteration in timerlist_run_timers (I would put the tracepoint inside the
> loop, just before the callback is done).  Similarly, in systemtap you
> can just use the builtin gettimeofday_ns() function
> 
> All clocks are basically in nanoseconds (the only difference between
> vm_clock and rt_clock is that the former stops when the VM is stopped),
> so you can get the average expiry delta from there.
> 
> Of course it requires some postprocessing or a systemtap script, but we
> can put that into scripts/ or give it to the user.  See
> https://sourceware.org/ml/systemtap/2011-q3/txt00003.txt for an example,
> I suppose the "expiry time" computation would look like this:

OK I need to look at the tracepoint stuff a bit more it seems :-)

If we can do this without a patch (save to put some tracepoints in),
that's obviously better than doing it with a patch. I don't like
the file particularly either.

> global modtime, expirytot, firedcnt
> 
> probe qemu.system.x86_64.timer_mod {
>   loc = sprintf("%s:%d", timer_file, timer_line)

How do timer_file and timer_line get filled in? If those still
need to be put in through code changes, how about taking
patch 1 of the series (that fills in timer->dbg with this
information), save for the unnecessary additions to the structure,
plus whatever is necessary to put the tracepoints in?

Alex

>   modtime[pid(), loc] = gettimeofday_ns()
> }
> probe qemu.system.x86_64.timer_run {
>   loc = sprintf("%s:%d", timer_file, timer_line)
>   expirytot[pid(), loc] += gettimeofday_ns() - modtime[pid(), loc]
>   firedcnt[pid(), loc]++
> }
> 
> probe end
> {
>  printf("\n%8s %28s %8s %8s\n", "pid", "loc", "avg expiry", "cnt")
>  foreach([p+, loc] in firedcnt) {
>    printf("%8d %28s %8d %8d\n", p, loc,
>        expirytot[p, loc] / firedcnt[p, loc],
>        firedcnt[p, loc])
>  }
> }

-- 
Alex Bligh

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log
  2013-10-26  8:24       ` Alex Bligh
@ 2013-10-26 17:11         ` Paolo Bonzini
  0 siblings, 0 replies; 10+ messages in thread
From: Paolo Bonzini @ 2013-10-26 17:11 UTC (permalink / raw)
  To: Alex Bligh
  Cc: Kevin Wolf, Anthony Liguori, Jan Kiszka, qemu-devel, liu ping fan,
	Stefan Hajnoczi, MORITA Kazutaka, rth

Il 26/10/2013 10:24, Alex Bligh ha scritto:
> How do timer_file and timer_line get filled in? If those still
> need to be put in through code changes, how about taking
> patch 1 of the series (that fills in timer->dbg with this
> information), save for the unnecessary additions to the structure,
> plus whatever is necessary to put the tracepoints in?

Sure!

Paolo

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2013-10-26 17:11 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-10-25 22:30 [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Alex Bligh
2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 1/4] Timers: add debugging macros wrapping timer functions and debug structures Alex Bligh
2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 2/4] Timers: add command line option -timer-debug-log Alex Bligh
2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 3/4] Timers: Instrument timer_mod Alex Bligh
2013-10-25 22:30 ` [Qemu-devel] [PATCHv1 4/4] Timers: produce timer-debug-log file Alex Bligh
2013-10-25 23:00 ` [Qemu-devel] [PATCHv1 0/4] Timers: add timer debugging through -timer-debug-log Paolo Bonzini
2013-10-26  5:52   ` Alex Bligh
2013-10-26  7:18     ` Paolo Bonzini
2013-10-26  8:24       ` Alex Bligh
2013-10-26 17:11         ` Paolo Bonzini

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).