]> sourceware.org Git - systemtap.git/commitdiff
hrtimer probes: support on-the-fly [dis]arming
authorJonathan Lebon <jlebon@redhat.com>
Mon, 2 Jun 2014 21:22:52 +0000 (17:22 -0400)
committerJonathan Lebon <jlebon@redhat.com>
Mon, 11 Aug 2014 19:40:00 +0000 (15:40 -0400)
This patch adds support for on-the-fly arming/disarming of hrtimer
probes. Although it is only supported for non-usermode, there were a few
changes required in dyninst/timer.c so that the same interface is
exposed for both usermode and kernel mode.

runtime/dyninst/timer.c

   - Decouple timer creation from timer starting by factoring out
     _stp_hrtimer_start() from _stp_hrtimer_create().
   - Make _stp_hrtimer_cancel() actually just cancel the timer, and not
     completely delete it.
   - Add new _stp_hrtimer_delete() to delete the timer.

runtime/linux/timer.c

   - Similarly, factor out _stp_hrtimer_start() from
     _stp_hrtimer_create().
   - Add new _stp_hrtimer_delete(), which also does a cancel.

tapset-timers.cxx

   - Declare hrtimer_derived_probe as a probe that supports on-the-fly
     operations.
   - In emit_module_init(): unconditionally create the timer, but if in
     STP_ON_THE_FLY mode, only bother to start it if its condition is
     met.
   - In emit_module_refresh(): check for which timers to start/cancel.

runtime/dyninst/timer.c
runtime/linux/timer.c
tapset-timers.cxx

index 417e228da446e6be3923effab774e4a790524887..d7d3b9c1fa22688021ca54e1ffd08e944090dab2 100644 (file)
@@ -35,20 +35,8 @@ static void _stp_hrtimer_init(void)
 
 
 static int
-_stp_hrtimer_create(struct stap_hrtimer_probe *shp, void (*function)(sigval_t))
+_stp_hrtimer_start(struct stap_hrtimer_probe *shp)
 {
-       int rc;
-
-       /* Create the timer. */
-       shp->sigev.sigev_notify = SIGEV_THREAD;
-       shp->sigev.sigev_value.sival_ptr = shp;
-       shp->sigev.sigev_notify_function = function;
-       shp->sigev.sigev_notify_attributes = NULL;
-       rc = timer_create(CLOCK_MONOTONIC, &shp->sigev, &shp->timer_id);
-       if (rc) {
-               return rc;
-       }
-
        /* Specify a timer with the correct initial value (possibly
         * randomized a bit).
         *
@@ -72,8 +60,21 @@ _stp_hrtimer_create(struct stap_hrtimer_probe *shp, void (*function)(sigval_t))
                shp->its.it_value.tv_sec = i / NSEC_PER_SEC;
                shp->its.it_value.tv_nsec = i % NSEC_PER_SEC;
        }
-       rc = timer_settime(shp->timer_id, 0, &shp->its, NULL);
-       return rc;
+       return timer_settime(shp->timer_id, 0, &shp->its, NULL);
+}
+
+
+static int
+_stp_hrtimer_create(struct stap_hrtimer_probe *shp, void (*function)(sigval_t))
+{
+       int rc;
+
+       /* Create the timer. */
+       shp->sigev.sigev_notify = SIGEV_THREAD;
+       shp->sigev.sigev_value.sival_ptr = shp;
+       shp->sigev.sigev_notify_function = function;
+       shp->sigev.sigev_notify_attributes = NULL;
+       return timer_create(CLOCK_MONOTONIC, &shp->sigev, &shp->timer_id);
 }
 
 
@@ -98,6 +99,13 @@ static void _stp_hrtimer_update(struct stap_hrtimer_probe *shp)
 
 
 static void _stp_hrtimer_cancel(struct stap_hrtimer_probe *shp)
+{
+       shp->its.it_value.tv_sec = 0;
+       shp->its.it_value.tv_nsec = 0;
+       timer_settime(shp->timer_id, 0, &shp->its, NULL);
+}
+
+static void _stp_hrtimer_delete(struct stap_hrtimer_probe *shp)
 {
        (void) timer_delete(shp->timer_id);
 }
index afc11e3d2eef608bb20c8106a444b463e61cbba3..5beb5792aab5b5d814118b56a514040158aeda95 100644 (file)
@@ -18,9 +18,10 @@ static unsigned long stap_hrtimer_resolution = 0;
 
 struct stap_hrtimer_probe {
        struct hrtimer hrtimer;
-       const struct stap_probe * const probe;
+       const struct stap_probe * probe;
        int64_t intrv;
        int64_t rnd;
+       unsigned enabled;
 };
 
 // The function signature changed in 2.6.21.
@@ -88,17 +89,24 @@ static inline void _stp_hrtimer_update(struct stap_hrtimer_probe *stp)
 }
 
 
+static int
+_stp_hrtimer_start(struct stap_hrtimer_probe *stp)
+{
+       (void)hrtimer_start(&stp->hrtimer, _stp_hrtimer_get_interval(stp),
+                           HRTIMER_MODE_REL);
+       return 0;
+}
+
 static int
 _stp_hrtimer_create(struct stap_hrtimer_probe *stp,
                    hrtimer_return_t (*function)(struct hrtimer *))
 {
        hrtimer_init(&stp->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        stp->hrtimer.function = function;
-       (void)hrtimer_start(&stp->hrtimer, _stp_hrtimer_get_interval(stp),
-                           HRTIMER_MODE_REL);
        return 0;
 }
 
+// For kernel-mode, there is no difference between cancel/delete.
 
 static void
 _stp_hrtimer_cancel(struct stap_hrtimer_probe *stp)
@@ -106,6 +114,12 @@ _stp_hrtimer_cancel(struct stap_hrtimer_probe *stp)
        hrtimer_cancel(&stp->hrtimer);
 }
 
+static void
+_stp_hrtimer_delete(struct stap_hrtimer_probe *stp)
+{
+       _stp_hrtimer_cancel(stp);
+}
+
 #else  /* kernel version < 2.6.17 */
 
 #error "not implemented"
index bbc8b1fe6cc01fa0a218078448564c10552568f7..436d9c9c0e345466a25aa4ec767a739b9b49e333 100644 (file)
@@ -211,6 +211,7 @@ struct hrtimer_derived_probe: public derived_probe
   // unprivileged users.
   void emit_privilege_assertion (translator_output*) {}
   void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
+  bool on_the_fly_supported () { return true; }
 };
 
 
@@ -219,6 +220,7 @@ struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
 public:
   void emit_module_decls (systemtap_session& s);
   void emit_module_init (systemtap_session& s);
+  void emit_module_refresh (systemtap_session& s);
   void emit_module_exit (systemtap_session& s);
 };
 
@@ -306,23 +308,77 @@ hrtimer_derived_probe_group::emit_module_init (systemtap_session& s)
 {
   if (probes.empty()) return;
 
-  s.op->newline() << "_stp_hrtimer_init();";
-  s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
-  s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
-  s.op->newline() << "probe_point = stp->probe->pp;";
+  s.op->newline( 0) <<  "_stp_hrtimer_init();";
+  s.op->newline( 0) <<  "for (i=0; i<" << probes.size() << "; i++) {";
+  s.op->newline(+1) <<    "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
+  s.op->newline( 0) <<    "probe_point = stp->probe->pp;";
 
   // Note: no partial failure rollback is needed for kernel hrtimer
   // probes (hrtimer_start only "fails" if the timer was already
   // active, which cannot be). But, stapdyn timer probes need a
   // rollback, and it won't hurt the kernel hrtimers.
-  s.op->newline() << "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
-  s.op->newline() << "if (rc) {";
-  s.op->indent(1);
-  s.op->newline() << "for (j=i-1; j>=0; j--)"; // partial rollback
-  s.op->newline(1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
-  s.op->newline(-1) << "break;"; // don't attempt to register any more
+  s.op->newline( 0) <<    "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
+  s.op->newline( 0) <<    "if (rc) {";
+  s.op->newline(+1) <<      "for (j=i-1; j>=0; j--) {"; // partial rollback
+  s.op->newline(+1) <<        "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
+  s.op->newline( 0) <<        "#ifdef STP_ON_THE_FLY";
+  s.op->newline( 0) <<        "stap_hrtimer_probes[j].enabled = 0;";
+  s.op->newline( 0) <<        "#endif";
+  s.op->newline(-1) <<      "}";
+  s.op->newline( 0) <<      "break;"; // don't attempt to register any more
+  s.op->newline(-1) <<    "}";
+
+  // If the probe condition is off, then don't bother starting the timer
+  s.op->newline( 0) <<    "#ifdef STP_ON_THE_FLY";
+  s.op->newline( 0) <<    "if (!stp->probe->cond_enabled) {";
+  s.op->newline(+1) <<      "dbug_otf(\"not starting (hrtimer) pidx %zu\\n\", stp->probe->index);";
+  s.op->newline( 0) <<      "continue;";
+  s.op->newline(-1) <<    "}";
+  s.op->newline( 0) <<    "#endif";
+
+  // Start the timer (with rollback on failure)
+  s.op->newline( 0) <<    "rc = _stp_hrtimer_start(stp);";
+  s.op->newline( 0) <<    "if (rc) {";
+  s.op->newline(+1) <<      "for (j=i-1; j>=0; j--) {"; // partial rollback
+  s.op->newline(+1) <<        "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
+  s.op->newline( 0) <<        "#ifdef STP_ON_THE_FLY";
+  s.op->newline( 0) <<        "stap_hrtimer_probes[j].enabled = 0;";
+  s.op->newline( 0) <<        "#endif";
+  s.op->newline(-1) <<      "}";
+  s.op->newline( 0) <<      "break;"; // don't attempt to register any more
+  s.op->newline(-1) <<    "}";
+
+  // Mark as enabled since we successfully started the timer
+  s.op->newline( 0) <<    "#ifdef STP_ON_THE_FLY";
+  s.op->newline( 0) <<    "stp->enabled = 1;";
+  s.op->newline( 0) <<    "#endif";
+  s.op->newline(-1) <<  "}"; // for loop
+}
+
+
+void
+hrtimer_derived_probe_group::emit_module_refresh (systemtap_session& s)
+{
+  if (probes.empty()) return;
+
+  // Check if we need to enable/disable any timers
+  s.op->newline( 0) << "#ifdef STP_ON_THE_FLY";
+
+  s.op->newline( 0) << "for (i=0; i <" << probes.size() << "; i++) {";
+  s.op->newline(+1) <<   "struct stap_hrtimer_probe* stp = &stap_hrtimer_probes[i];";
+  // timer disabled, but condition says enabled?
+  s.op->newline( 0) <<   "if (!stp->enabled && stp->probe->cond_enabled) {";
+  s.op->newline(+1) <<     "dbug_otf(\"enabling (hrtimer) pidx %zu\\n\", stp->probe->index);";
+  s.op->newline( 0) <<     "_stp_hrtimer_start(stp);";
+  // timer enabled, but condition says disabled?
+  s.op->newline(-1) <<   "} else if (stp->enabled && !stp->probe->cond_enabled) {";
+  s.op->newline(+1) <<     "dbug_otf(\"disabling (hrtimer) pidx %zu\\n\", stp->probe->index);";
+  s.op->newline( 0) <<     "_stp_hrtimer_cancel(stp);";
+  s.op->newline(-1) <<   "}";
+  s.op->newline( 0) <<   "stp->enabled = stp->probe->cond_enabled;";
   s.op->newline(-1) << "}";
-  s.op->newline(-1) << "}"; // for loop
+
+  s.op->newline( 0) << "#endif";
 }
 
 
@@ -333,7 +389,7 @@ hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s)
 
   s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
   s.op->indent(1);
-  s.op->newline() << "_stp_hrtimer_cancel(& stap_hrtimer_probes[i]);";
+  s.op->newline() << "_stp_hrtimer_delete(& stap_hrtimer_probes[i]);";
   s.op->indent(-1);
 }
 
This page took 0.086896 seconds and 5 git commands to generate.