LCOV - code coverage report
Current view: top level - mnt/wasteland/wcohen/systemtap_write/systemtap - tapset-timers.cxx (source / functions) Hit Total Coverage
Test: stap.info Lines: 260 291 89.3 %
Date: 2013-03-08 Functions: 28 42 66.7 %
Branches: 303 670 45.2 %

           Branch data     Line data    Source code
       1                 :            : // tapset for timers
       2                 :            : // Copyright (C) 2005-2011 Red Hat Inc.
       3                 :            : // Copyright (C) 2005-2007 Intel Corporation.
       4                 :            : //
       5                 :            : // This file is part of systemtap, and is free software.  You can
       6                 :            : // redistribute it and/or modify it under the terms of the GNU General
       7                 :            : // Public License (GPL); either version 2, or (at your option) any
       8                 :            : // later version.
       9                 :            : 
      10                 :            : 
      11                 :            : #include "session.h"
      12                 :            : #include "tapsets.h"
      13                 :            : #include "translate.h"
      14                 :            : #include "util.h"
      15                 :            : 
      16                 :            : #include <cstring>
      17                 :            : #include <string>
      18                 :            : 
      19                 :            : 
      20                 :            : using namespace std;
      21                 :            : using namespace __gnu_cxx;
      22                 :            : 
      23                 :            : 
      24         [ +  - ]:       2414 : static const string TOK_TIMER("timer");
      25                 :            : 
      26                 :            : 
      27                 :            : // ------------------------------------------------------------------------
      28                 :            : // timer derived probes
      29                 :            : // ------------------------------------------------------------------------
      30                 :            : 
      31                 :            : 
      32         [ #  # ]:          0 : struct timer_derived_probe: public derived_probe
      33                 :            : {
      34                 :            :   int64_t interval, randomize;
      35                 :            :   bool time_is_msecs; // NB: hrtimers get ms-based probes on modern kernels instead
      36                 :            :   timer_derived_probe (probe* p, probe_point* l,
      37                 :            :                        int64_t i, int64_t r, bool ms=false);
      38                 :            :   virtual void join_group (systemtap_session& s);
      39                 :            : 
      40                 :            :   // No assertion need be emitted, since this probe is allowed for unprivileged
      41                 :            :   // users.
      42                 :         11 :   void emit_privilege_assertion (translator_output*) {}
      43                 :         22 :   void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
      44                 :            : };
      45                 :            : 
      46                 :            : 
      47         [ #  # ]:          9 : struct timer_derived_probe_group: public generic_dpg<timer_derived_probe>
      48                 :            : {
      49                 :            :   void emit_interval (translator_output* o);
      50                 :            : public:
      51                 :            :   void emit_module_decls (systemtap_session& s);
      52                 :            :   void emit_module_init (systemtap_session& s);
      53                 :            :   void emit_module_exit (systemtap_session& s);
      54                 :            : };
      55                 :            : 
      56                 :            : 
      57                 :         13 : timer_derived_probe::timer_derived_probe (probe* p, probe_point* l,
      58                 :            :                                           int64_t i, int64_t r, bool ms):
      59                 :         13 :   derived_probe (p, l), interval (i), randomize (r), time_is_msecs(ms)
      60                 :            : {
      61 [ +  - ][ -  + ]:         13 :   if (interval <= 0 || interval > 1000000) // make i and r fit into plain ints
      62                 :            :     //TRANSLATORS: 'timer' is the name of a probe point
      63 [ #  # ][ #  # ]:          0 :     throw semantic_error (_("invalid interval for jiffies timer"));
      64                 :            :   // randomize = 0 means no randomization
      65 [ +  - ][ -  + ]:         13 :   if (randomize < 0 || randomize > interval)
      66                 :            :     //TRANSLATORS: 'randomize' is a key word
      67 [ #  # ][ #  # ]:          0 :     throw semantic_error (_("invalid randomize for jiffies timer"));
      68                 :            : 
      69         [ -  + ]:         13 :   if (locations.size() != 1)
      70 [ #  # ][ #  # ]:          0 :     throw semantic_error (_("only expect one probe point"));
      71                 :            :   // so we don't have to loop over them in the other functions
      72                 :         13 : }
      73                 :            : 
      74                 :            : 
      75                 :            : void
      76                 :         13 : timer_derived_probe::join_group (systemtap_session& s)
      77                 :            : {
      78         [ +  + ]:         13 :   if (! s.timer_derived_probes)
      79         [ +  - ]:          9 :     s.timer_derived_probes = new timer_derived_probe_group ();
      80                 :         13 :   s.timer_derived_probes->enroll (this);
      81                 :         13 : }
      82                 :            : 
      83                 :            : 
      84                 :            : void
      85                 :         14 : timer_derived_probe_group::emit_interval (translator_output* o)
      86                 :            : {
      87                 :         14 :   o->line() << "({";
      88                 :         14 :   o->newline(1) << "unsigned i = stp->intrv;";
      89                 :         14 :   o->newline() << "if (stp->rnd != 0)";
      90                 :         14 :   o->newline(1) << "i += _stp_random_pm(stp->rnd);";
      91                 :         14 :   o->newline(-1) << "stp->ms ? msecs_to_jiffies(i) : i;";
      92                 :         14 :   o->newline(-1) << "})";
      93                 :         14 : }
      94                 :            : 
      95                 :            : 
      96                 :            : void
      97                 :          7 : timer_derived_probe_group::emit_module_decls (systemtap_session& s)
      98                 :            : {
      99         [ -  + ]:         14 :   if (probes.empty()) return;
     100                 :            : 
     101                 :          7 :   s.op->newline() << "/* ---- timer probes ---- */";
     102                 :            : 
     103                 :          7 :   s.op->newline() << "static struct stap_timer_probe {";
     104                 :          7 :   s.op->newline(1) << "struct timer_list timer_list;";
     105                 :          7 :   s.op->newline() << "const struct stap_probe * const probe;";
     106                 :          7 :   s.op->newline() << "unsigned intrv, ms, rnd;";
     107                 :          7 :   s.op->newline(-1) << "} stap_timer_probes [" << probes.size() << "] = {";
     108                 :          7 :   s.op->indent(1);
     109         [ +  + ]:         18 :   for (unsigned i=0; i < probes.size(); i++)
     110                 :            :     {
     111                 :         11 :       s.op->newline () << "{";
     112 [ +  - ][ +  - ]:         11 :       s.op->line() << " .probe=" << common_probe_init (probes[i]) << ",";
     113                 :         11 :       s.op->line() << " .intrv=" << probes[i]->interval << ",";
     114                 :         11 :       s.op->line() << " .ms=" << probes[i]->time_is_msecs << ",";
     115                 :         11 :       s.op->line() << " .rnd=" << probes[i]->randomize;
     116                 :         11 :       s.op->line() << " },";
     117                 :            :     }
     118                 :          7 :   s.op->newline(-1) << "};";
     119                 :          7 :   s.op->newline();
     120                 :            : 
     121                 :          7 :   s.op->newline() << "static void enter_timer_probe (unsigned long val) {";
     122                 :          7 :   s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [val];";
     123                 :          7 :   s.op->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
     124                 :          7 :   s.op->newline() << "    (atomic_read (session_state()) == STAP_SESSION_RUNNING))";
     125                 :          7 :   s.op->newline(1) << "mod_timer (& stp->timer_list, jiffies + ";
     126                 :          7 :   emit_interval (s.op);
     127                 :          7 :   s.op->line() << ");";
     128                 :          7 :   s.op->newline(-1) << "{";
     129                 :          7 :   s.op->indent(1);
     130                 :            :   common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
     131 [ +  - ][ +  - ]:          7 :                                  "stp_probe_type_timer");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     132                 :          7 :   s.op->newline() << "(*stp->probe->ph) (c);";
     133                 :          7 :   common_probe_entryfn_epilogue (s, true);
     134                 :          7 :   s.op->newline(-1) << "}";
     135                 :          7 :   s.op->newline(-1) << "}";
     136                 :            : }
     137                 :            : 
     138                 :            : 
     139                 :            : void
     140                 :          7 : timer_derived_probe_group::emit_module_init (systemtap_session& s)
     141                 :            : {
     142         [ -  + ]:         14 :   if (probes.empty()) return;
     143                 :            : 
     144                 :          7 :   s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
     145                 :          7 :   s.op->newline(1) << "struct stap_timer_probe* stp = & stap_timer_probes [i];";
     146                 :          7 :   s.op->newline() << "probe_point = stp->probe->pp;";
     147                 :          7 :   s.op->newline() << "init_timer (& stp->timer_list);";
     148                 :          7 :   s.op->newline() << "stp->timer_list.function = & enter_timer_probe;";
     149                 :          7 :   s.op->newline() << "stp->timer_list.data = i;"; // NB: important!
     150                 :            :   // copy timer renew calculations from above :-(
     151                 :          7 :   s.op->newline() << "stp->timer_list.expires = jiffies + ";
     152                 :          7 :   emit_interval (s.op);
     153                 :          7 :   s.op->line() << ";";
     154                 :          7 :   s.op->newline() << "add_timer (& stp->timer_list);";
     155                 :            :   // note: no partial failure rollback is needed: add_timer cannot fail.
     156                 :          7 :   s.op->newline(-1) << "}"; // for loop
     157                 :            : }
     158                 :            : 
     159                 :            : 
     160                 :            : void
     161                 :         13 : timer_derived_probe_group::emit_module_exit (systemtap_session& s)
     162                 :            : {
     163         [ -  + ]:         26 :   if (probes.empty()) return;
     164                 :            : 
     165                 :         13 :   s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
     166                 :         13 :   s.op->newline(1) << "del_timer_sync (& stap_timer_probes[i].timer_list);";
     167                 :         13 :   s.op->indent(-1);
     168                 :            : }
     169                 :            : 
     170                 :            : 
     171                 :            : 
     172                 :            : // ------------------------------------------------------------------------
     173                 :            : // hrtimer derived probes
     174                 :            : // ------------------------------------------------------------------------
     175                 :            : // This is a new timer interface that provides more flexibility in specifying
     176                 :            : // intervals, and uses the hrtimer APIs when available for greater precision.
     177                 :            : // While hrtimers were added in 2.6.16, the API's weren't exported until
     178                 :            : // 2.6.17, so we must check this kernel version before attempting to use
     179                 :            : // hrtimers.
     180                 :            : //
     181                 :            : // * hrtimer_derived_probe: creates a probe point based on the hrtimer APIs.
     182                 :            : 
     183                 :            : 
     184         [ #  # ]:          0 : struct hrtimer_derived_probe: public derived_probe
     185                 :            : {
     186                 :            :   // set a (generous) maximum of one day in ns
     187                 :            :   static const int64_t max_ns_interval = 1000000000LL * 60LL * 60LL * 24LL;
     188                 :            : 
     189                 :            :   // 100us seems like a reasonable minimum
     190                 :            :   static const int64_t min_ns_interval = 100000LL;
     191                 :            : 
     192                 :            :   int64_t interval, randomize;
     193                 :            : 
     194                 :        155 :   hrtimer_derived_probe (probe* p, probe_point* l, int64_t i, int64_t r,
     195                 :            :                          int64_t scale):
     196                 :        155 :     derived_probe (p, l), interval (i), randomize (r)
     197                 :            :   {
     198 [ +  - ][ -  + ]:        155 :     if ((i < min_ns_interval) || (i > max_ns_interval))
     199                 :          0 :       throw semantic_error(_F("interval value out of range (%s, %s)",
     200                 :            :                           (lex_cast(scale < min_ns_interval ? min_ns_interval/scale : 1).c_str()),
     201 [ #  # ][ #  # ]:          0 :                            lex_cast(max_ns_interval/scale).c_str()));
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     202                 :            : 
     203                 :            :     // randomize = 0 means no randomization
     204 [ +  - ][ -  + ]:        155 :     if ((r < 0) || (r > i))
     205 [ #  # ][ #  # ]:          0 :       throw semantic_error(_("randomization value out of range"));
     206                 :        155 :   }
     207                 :            : 
     208                 :            :   void join_group (systemtap_session& s);
     209                 :            : 
     210                 :            :   // No assertion need be emitted, since these probes are allowed for
     211                 :            :   // unprivileged users.
     212                 :         89 :   void emit_privilege_assertion (translator_output*) {}
     213                 :        246 :   void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
     214                 :            : };
     215                 :            : 
     216                 :            : 
     217         [ #  # ]:        109 : struct hrtimer_derived_probe_group: public generic_dpg<hrtimer_derived_probe>
     218                 :            : {
     219                 :            : public:
     220                 :            :   void emit_module_decls (systemtap_session& s);
     221                 :            :   void emit_module_init (systemtap_session& s);
     222                 :            :   void emit_module_exit (systemtap_session& s);
     223                 :            : };
     224                 :            : 
     225                 :            : 
     226                 :            : void
     227                 :        155 : hrtimer_derived_probe::join_group (systemtap_session& s)
     228                 :            : {
     229         [ +  + ]:        155 :   if (! s.hrtimer_derived_probes)
     230         [ +  - ]:        109 :     s.hrtimer_derived_probes = new hrtimer_derived_probe_group ();
     231                 :        155 :   s.hrtimer_derived_probes->enroll (this);
     232                 :        155 : }
     233                 :            : 
     234                 :            : 
     235                 :            : void
     236                 :         80 : hrtimer_derived_probe_group::emit_module_decls (systemtap_session& s)
     237                 :            : {
     238         [ -  + ]:        160 :   if (probes.empty()) return;
     239                 :            : 
     240                 :         80 :   s.op->newline() << "/* ---- hrtimer probes ---- */";
     241                 :         80 :   s.op->newline() << "#include \"timer.c\"";
     242                 :         80 :   s.op->newline() << "static struct stap_hrtimer_probe stap_hrtimer_probes [" << probes.size() << "] = {";
     243                 :            : 
     244                 :         80 :   s.op->indent(1);
     245         [ +  + ]:        203 :   for (unsigned i=0; i < probes.size(); i++)
     246                 :            :     {
     247                 :        123 :       s.op->newline () << "{";
     248 [ +  - ][ +  - ]:        123 :       s.op->line() << " .probe=" << common_probe_init (probes[i]) << ",";
     249                 :        123 :       s.op->line() << " .intrv=" << probes[i]->interval << "LL,";
     250                 :        123 :       s.op->line() << " .rnd=" << probes[i]->randomize << "LL";
     251                 :        123 :       s.op->line() << " },";
     252                 :            :     }
     253                 :         80 :   s.op->newline(-1) << "};";
     254                 :         80 :   s.op->newline();
     255                 :            : 
     256         [ +  - ]:         80 :   if (!s.runtime_usermode_p())
     257                 :            :     {
     258                 :         80 :       s.op->newline() << "static hrtimer_return_t _stp_hrtimer_notify_function (struct hrtimer *timer) {";
     259                 :            : 
     260                 :         80 :       s.op->newline(1) << "int rc = HRTIMER_NORESTART;";
     261                 :         80 :       s.op->newline() << "struct stap_hrtimer_probe *stp = container_of(timer, struct stap_hrtimer_probe, hrtimer);";
     262                 :            : 
     263                 :            :       // Update the timer with the next trigger time
     264                 :         80 :       s.op->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
     265                 :         80 :       s.op->newline() << "    (atomic_read (session_state()) == STAP_SESSION_RUNNING)) {";
     266                 :         80 :       s.op->newline(1) << "_stp_hrtimer_update(stp);";
     267                 :         80 :       s.op->newline() << "rc = HRTIMER_RESTART;";
     268                 :         80 :       s.op->newline(-1) << "}";
     269                 :            : 
     270                 :         80 :       s.op->newline() << "{";
     271                 :         80 :       s.op->indent(1);
     272                 :            :       common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
     273 [ +  - ][ +  - ]:         80 :                                      "stp_probe_type_hrtimer");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     274                 :         80 :       s.op->newline() << "(*stp->probe->ph) (c);";
     275                 :         80 :       common_probe_entryfn_epilogue (s, true);
     276                 :         80 :       s.op->newline(-1) << "}";
     277                 :         80 :       s.op->newline() << "return rc;";
     278                 :         80 :       s.op->newline(-1) << "}";
     279                 :            :     }
     280                 :            :   else
     281                 :            :     {
     282                 :          0 :       s.op->newline() << "static void _stp_hrtimer_notify_function (sigval_t value)";
     283                 :          0 :       s.op->newline(1) << "{";
     284                 :          0 :       s.op->newline() << "struct stap_hrtimer_probe *stp = value.sival_ptr;";
     285                 :            : 
     286                 :            :       // Update the timer with the next trigger time
     287                 :          0 :       s.op->newline() << "if ((atomic_read (session_state()) == STAP_SESSION_STARTING) ||";
     288                 :          0 :       s.op->newline() << "    (atomic_read (session_state()) == STAP_SESSION_RUNNING)) {";
     289                 :          0 :       s.op->newline(1) << "_stp_hrtimer_update(stp);";
     290                 :          0 :       s.op->newline(-1) << "}";
     291                 :            : 
     292                 :          0 :       s.op->newline() << "{";
     293                 :          0 :       s.op->indent(1);
     294                 :            :       common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "stp->probe",
     295 [ #  # ][ #  # ]:          0 :                                      "stp_probe_type_hrtimer");
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
                 [ #  # ]
     296                 :          0 :       s.op->newline() << "(*stp->probe->ph) (c);";
     297                 :          0 :       common_probe_entryfn_epilogue (s, true);
     298                 :          0 :       s.op->newline(-1) << "}";
     299                 :          0 :       s.op->newline(-1) << "}";
     300                 :            :     }
     301                 :            : }
     302                 :            : 
     303                 :            : 
     304                 :            : void
     305                 :         80 : hrtimer_derived_probe_group::emit_module_init (systemtap_session& s)
     306                 :            : {
     307         [ -  + ]:        160 :   if (probes.empty()) return;
     308                 :            : 
     309                 :         80 :   s.op->newline() << "_stp_hrtimer_init();";
     310                 :         80 :   s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
     311                 :         80 :   s.op->newline(1) << "struct stap_hrtimer_probe* stp = & stap_hrtimer_probes [i];";
     312                 :         80 :   s.op->newline() << "probe_point = stp->probe->pp;";
     313                 :            : 
     314                 :            :   // Note: no partial failure rollback is needed for kernel hrtimer
     315                 :            :   // probes (hrtimer_start only "fails" if the timer was already
     316                 :            :   // active, which cannot be). But, stapdyn timer probes need a
     317                 :            :   // rollback, and it won't hurt the kernel hrtimers.
     318                 :         80 :   s.op->newline() << "rc = _stp_hrtimer_create(stp, _stp_hrtimer_notify_function);";
     319                 :         80 :   s.op->newline() << "if (rc) {";
     320                 :         80 :   s.op->indent(1);
     321                 :         80 :   s.op->newline() << "for (j=i-1; j>=0; j--)"; // partial rollback
     322                 :         80 :   s.op->newline(1) << "_stp_hrtimer_cancel(& stap_hrtimer_probes[j]);";
     323                 :         80 :   s.op->newline(-1) << "break;"; // don't attempt to register any more
     324                 :         80 :   s.op->newline(-1) << "}";
     325                 :         80 :   s.op->newline(-1) << "}"; // for loop
     326                 :            : }
     327                 :            : 
     328                 :            : 
     329                 :            : void
     330                 :         86 : hrtimer_derived_probe_group::emit_module_exit (systemtap_session& s)
     331                 :            : {
     332         [ -  + ]:        172 :   if (probes.empty()) return;
     333                 :            : 
     334                 :         86 :   s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
     335                 :         86 :   s.op->indent(1);
     336                 :         86 :   s.op->newline() << "_stp_hrtimer_cancel(& stap_hrtimer_probes[i]);";
     337                 :         86 :   s.op->indent(-1);
     338                 :            : }
     339                 :            : 
     340                 :            : 
     341                 :            : 
     342                 :            : // ------------------------------------------------------------------------
     343                 :            : // profile derived probes
     344                 :            : // ------------------------------------------------------------------------
     345                 :            : //   On kernels < 2.6.10, this uses the register_profile_notifier API to
     346                 :            : //   generate the timed events for profiling; on kernels >= 2.6.10 this
     347                 :            : //   uses the register_timer_hook API.  The latter doesn't currently allow
     348                 :            : //   simultaneous users, so insertion will fail if the profiler is busy.
     349                 :            : //   (Conflicting users may include OProfile, other SystemTap probes, etc.)
     350                 :            : 
     351                 :            : 
     352         [ #  # ]:          0 : struct profile_derived_probe: public derived_probe
     353                 :            : {
     354                 :            :   profile_derived_probe (systemtap_session &s, probe* p, probe_point* l);
     355                 :            :   void join_group (systemtap_session& s);
     356                 :            : };
     357                 :            : 
     358                 :            : 
     359         [ #  # ]:         20 : struct profile_derived_probe_group: public generic_dpg<profile_derived_probe>
     360                 :            : {
     361                 :            : public:
     362                 :            :   void emit_module_decls (systemtap_session& s);
     363                 :            :   void emit_module_init (systemtap_session& s);
     364                 :            :   void emit_module_exit (systemtap_session& s);
     365                 :            : };
     366                 :            : 
     367                 :            : 
     368                 :         98 : profile_derived_probe::profile_derived_probe (systemtap_session &, probe* p, probe_point* l):
     369                 :         98 :   derived_probe(p, l)
     370                 :            : {
     371                 :         98 : }
     372                 :            : 
     373                 :            : 
     374                 :            : void
     375                 :         98 : profile_derived_probe::join_group (systemtap_session& s)
     376                 :            : {
     377         [ +  + ]:         98 :   if (! s.profile_derived_probes)
     378         [ +  - ]:         20 :     s.profile_derived_probes = new profile_derived_probe_group ();
     379                 :         98 :   s.profile_derived_probes->enroll (this);
     380                 :         98 : }
     381                 :            : 
     382                 :            : 
     383                 :            : // timer.profile probe handlers are hooked up in an entertaining way
     384                 :            : // to the underlying kernel facility.  The fact that 2.6.11+ era
     385                 :            : // "register_timer_hook" API allows only one consumer *system-wide*
     386                 :            : // will give a hint.  We will have a single entry function (and thus
     387                 :            : // trivial registration / unregistration), and it will call all probe
     388                 :            : // handler functions in sequence.
     389                 :            : 
     390                 :            : void
     391                 :         16 : profile_derived_probe_group::emit_module_decls (systemtap_session& s)
     392                 :            : {
     393         [ -  + ]:         32 :   if (probes.empty()) return;
     394                 :            : 
     395                 :            :   // kernels < 2.6.10: use register_profile_notifier API
     396                 :            :   // kernels >= 2.6.10: use register_timer_hook API
     397                 :         16 :   s.op->newline() << "/* ---- profile probes ---- */";
     398                 :            : 
     399                 :            :   // This function calls all the profiling probe handlers in sequence.
     400                 :            :   // The only tricky thing is that the context will be reused amongst
     401                 :            :   // them.  While a simple sequence of calls to the individual probe
     402                 :            :   // handlers is unlikely to go terribly wrong (with c->last_error
     403                 :            :   // being set causing an early return), but for extra assurance, we
     404                 :            :   // open-code the same logic here.
     405                 :            : 
     406                 :         16 :   s.op->newline() << "static void enter_all_profile_probes (struct pt_regs *regs) {";
     407                 :         16 :   s.op->newline(1) << "const struct stap_probe * probe = "
     408 [ +  - ][ +  - ]:         16 :                    << common_probe_init (probes[0]) << ";";
     409                 :            :   common_probe_entryfn_prologue (s, "STAP_SESSION_RUNNING", "probe",
     410 [ +  - ][ +  - ]:         16 :                                  "stp_probe_type_profile_timer");
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
                 [ +  - ]
     411                 :            :   // Timer interrupts save all registers, so if the interrupt happened
     412                 :            :   // in user space we can rely on it being the full user pt_regs.
     413                 :         16 :   s.op->newline() << "if (user_mode(regs)) {";
     414                 :         16 :   s.op->newline(1) << "c->user_mode_p = 1;";
     415                 :         16 :   s.op->newline() << "c->uregs = regs;";
     416                 :         16 :   s.op->newline(-1) << "} else {";
     417                 :         16 :   s.op->newline(1) << "c->kregs = regs;";
     418                 :         16 :   s.op->newline(-1) << "}";
     419                 :            : 
     420         [ +  + ]:        110 :   for (unsigned i=0; i<probes.size(); i++)
     421                 :            :     {
     422         [ +  + ]:         94 :       if (i > 0)
     423                 :            :         {
     424                 :            :           // Some lightweight inter-probe context resetting
     425                 :            :           // XXX: not quite right: MAXERRORS not respected
     426                 :            :           // XXX: STP_TIMING stats are also not correct
     427 [ +  - ][ +  - ]:         78 :           s.op->newline() << "probe = " << common_probe_init (probes[i]) << ";";
     428                 :         78 :           s.op->newline() << "#ifdef STP_NEED_PROBE_NAME";
     429                 :         78 :           s.op->newline() << "c->probe_name = probe->pn;";
     430                 :         78 :           s.op->newline() << "#endif";
     431         [ +  - ]:         78 :            if(!s.suppress_time_limits)
     432                 :            :              {
     433                 :         78 :                s.op->newline() << "c->actionremaining = MAXACTION;";
     434                 :            :              }
     435                 :            :         }
     436                 :         94 :       s.op->newline() << "if (c->last_error == NULL) probe->ph (c);";
     437                 :            :     }
     438                 :         16 :   common_probe_entryfn_epilogue (s, true);
     439                 :         16 :   s.op->newline(-1) << "}";
     440                 :            : 
     441                 :         16 :   s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
     442                 :            : 
     443                 :         16 :   s.op->newline() << "static int enter_profile_probes (struct notifier_block *self,"
     444                 :         16 :                   << " unsigned long val, void *data) {";
     445                 :         16 :   s.op->newline(1) << "(void) self; (void) val;";
     446                 :         16 :   s.op->newline() << "enter_all_profile_probes ((struct pt_regs *) data);";
     447                 :         16 :   s.op->newline() << "return 0;";
     448                 :         16 :   s.op->newline(-1) << "}";
     449                 :         16 :   s.op->newline() << "struct notifier_block stap_profile_notifier = {"
     450                 :         16 :                   << " .notifier_call = & enter_profile_probes };";
     451                 :            : 
     452                 :         16 :   s.op->newline() << "#else";
     453                 :            : 
     454                 :         16 :   s.op->newline() << "static int enter_profile_probes (struct pt_regs *regs) {";
     455                 :         16 :   s.op->newline(1) << "enter_all_profile_probes (regs);";
     456                 :         16 :   s.op->newline() << "return 0;";
     457                 :         16 :   s.op->newline(-1) << "}";
     458                 :            : 
     459                 :         16 :   s.op->newline() << "#endif";
     460                 :            : }
     461                 :            : 
     462                 :            : 
     463                 :            : void
     464                 :         16 : profile_derived_probe_group::emit_module_init (systemtap_session& s)
     465                 :            : {
     466         [ -  + ]:         32 :   if (probes.empty()) return;
     467                 :            : 
     468                 :         16 :   s.op->newline() << "probe_point = \"timer.profile\";"; // NB: hard-coded for convenience
     469                 :         16 :   s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
     470                 :         16 :   s.op->newline() << "rc = register_profile_notifier (& stap_profile_notifier);";
     471                 :         16 :   s.op->newline() << "#else";
     472                 :         16 :   s.op->newline() << "rc = register_timer_hook (& enter_profile_probes);";
     473                 :         16 :   s.op->newline() << "#endif";
     474                 :            : }
     475                 :            : 
     476                 :            : 
     477                 :            : void
     478                 :         33 : profile_derived_probe_group::emit_module_exit (systemtap_session& s)
     479                 :            : {
     480         [ -  + ]:         66 :   if (probes.empty()) return;
     481                 :            : 
     482                 :         33 :   s.op->newline() << "#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)"; // == using_rpn of yore
     483                 :         33 :   s.op->newline() << "unregister_profile_notifier (& stap_profile_notifier);";
     484                 :         33 :   s.op->newline() << "#else";
     485                 :         33 :   s.op->newline() << "unregister_timer_hook (& enter_profile_probes);";
     486                 :         33 :   s.op->newline() << "#endif";
     487                 :            : }
     488                 :            : 
     489                 :            : 
     490                 :            : 
     491                 :            : // ------------------------------------------------------------------------
     492                 :            : // unified probe builder for timer probes
     493                 :            : // ------------------------------------------------------------------------
     494                 :            : 
     495                 :            : 
     496         [ #  # ]:       1218 : struct timer_builder: public derived_probe_builder
     497                 :            : {
     498                 :            :     virtual void build(systemtap_session & sess,
     499                 :            :                        probe * base, probe_point * location,
     500                 :            :                        literal_map_t const & parameters,
     501                 :            :                        vector<derived_probe *> & finished_results);
     502                 :            : 
     503                 :            :     static void register_patterns(systemtap_session& s);
     504                 :            : };
     505                 :            : 
     506                 :            : void
     507                 :        266 : timer_builder::build(systemtap_session & sess,
     508                 :            :     probe * base,
     509                 :            :     probe_point * location,
     510                 :            :     literal_map_t const & parameters,
     511                 :            :     vector<derived_probe *> & finished_results)
     512                 :            : {
     513                 :        266 :   int64_t scale=1, period, rand=0;
     514                 :            : 
     515 [ +  - ][ +  - ]:        266 :   if (has_null_param(parameters, "profile"))
         [ +  - ][ +  + ]
     516                 :            :     {
     517         [ -  + ]:         98 :       if (sess.runtime_usermode_p())
     518 [ #  # ][ #  # ]:          0 :         throw semantic_error (_("profile timer probes not available with the dyninst runtime"));
     519                 :            : 
     520 [ +  - ][ +  - ]:         98 :       sess.unwindsym_modules.insert ("kernel");
                 [ +  - ]
     521                 :            :       finished_results.push_back
     522 [ +  - ][ +  - ]:         98 :         (new profile_derived_probe(sess, base, location));
                 [ +  - ]
     523                 :            :       return;
     524                 :            :     }
     525                 :            : 
     526 [ +  - ][ +  - ]:        168 :   if (!get_param(parameters, "randomize", rand))
         [ +  - ][ +  + ]
     527                 :        150 :     rand = 0;
     528                 :            : 
     529 [ +  - ][ +  - ]:        168 :   if (get_param(parameters, "jiffies", period))
         [ +  - ][ +  + ]
     530                 :            :     {
     531         [ -  + ]:         13 :       if (sess.runtime_usermode_p())
     532 [ #  # ][ #  # ]:          0 :         throw semantic_error (_("jiffies timer probes not available with the dyninst runtime"));
     533                 :            : 
     534                 :            :       // always use basic timers for jiffies
     535                 :            :       finished_results.push_back
     536 [ +  - ][ +  - ]:         13 :         (new timer_derived_probe(base, location, period, rand, false));
                 [ +  - ]
     537                 :            :       return;
     538                 :            :     }
     539 [ +  - ][ +  - ]:        155 :   else if (get_param(parameters, "hz", period))
         [ +  - ][ +  + ]
     540                 :            :     {
     541         [ -  + ]:          2 :       if (period <= 0)
     542 [ #  # ][ #  # ]:          0 :         throw semantic_error (_("frequency must be greater than 0"));
     543                 :          2 :       period = (1000000000 + period - 1)/period;
     544                 :            :     }
     545 [ +  - ][ +  - ]:        399 :   else if (get_param(parameters, "s", period) ||
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  +  
             #  #  #  # ]
     546 [ +  - ][ +  - ]:        246 :            get_param(parameters, "sec", period))
         [ +  + ][ +  - ]
                 [ +  + ]
           [ #  #  #  # ]
     547                 :            :     {
     548                 :         67 :       scale = 1000000000;
     549                 :         67 :       period *= scale;
     550                 :         67 :       rand *= scale;
     551                 :            :     }
     552 [ +  - ][ +  - ]:        192 :   else if (get_param(parameters, "ms", period) ||
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  +  
             #  #  #  # ]
     553 [ +  - ][ +  - ]:        106 :            get_param(parameters, "msec", period))
         [ +  + ][ +  - ]
                 [ +  + ]
           [ #  #  #  # ]
     554                 :            :     {
     555                 :         70 :       scale = 1000000;
     556                 :         70 :       period *= scale;
     557                 :         70 :       rand *= scale;
     558                 :            :     }
     559 [ +  - ][ +  - ]:         44 :   else if (get_param(parameters, "us", period) ||
         [ +  + ][ +  + ]
         [ +  - ][ +  - ]
         [ +  - ][ +  +  
             #  #  #  # ]
     560 [ +  - ][ +  - ]:         28 :            get_param(parameters, "usec", period))
         [ +  + ][ +  - ]
                 [ +  + ]
           [ #  #  #  # ]
     561                 :            :     {
     562                 :          8 :       scale = 1000;
     563                 :          8 :       period *= scale;
     564                 :          8 :       rand *= scale;
     565                 :            :     }
     566 [ +  - ][ +  - ]:         20 :   else if (get_param(parameters, "ns", period) ||
         [ +  + ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ -  +  
             #  #  #  # ]
     567 [ +  - ][ +  - ]:         12 :            get_param(parameters, "nsec", period))
         [ +  + ][ +  - ]
                 [ +  + ]
           [ #  #  #  # ]
     568                 :            :     {
     569                 :            :       // ok
     570                 :            :     }
     571                 :            :   else
     572 [ #  # ][ #  # ]:          0 :     throw semantic_error (_("unrecognized timer variant"));
     573                 :            : 
     574                 :            :   // Redirect wallclock-time based probes to hrtimer code on recent
     575                 :            :   // enough kernels.
     576 [ +  - ][ -  + ]:        155 :   if (strverscmp(sess.kernel_base_release.c_str(), "2.6.17") < 0)
     577                 :            :     {
     578                 :            :       // hrtimers didn't exist, so use the old-school timers
     579                 :          0 :       period = (period + 1000000 - 1)/1000000;
     580                 :          0 :       rand = (rand + 1000000 - 1)/1000000;
     581                 :            : 
     582                 :            :       finished_results.push_back
     583 [ #  # ][ #  # ]:          0 :         (new timer_derived_probe(base, location, period, rand, true));
                 [ #  # ]
     584                 :            :     }
     585                 :            :   else
     586                 :            :     finished_results.push_back
     587 [ +  - ][ +  - ]:        266 :       (new hrtimer_derived_probe(base, location, period, rand, scale));
                 [ +  - ]
     588                 :            : }
     589                 :            : 
     590                 :            : void
     591                 :       1218 : register_tapset_timers(systemtap_session& s)
     592                 :            : {
     593                 :       1218 :   match_node* root = s.pattern_root;
     594                 :       1218 :   derived_probe_builder *builder = new timer_builder();
     595                 :            : 
     596                 :       1218 :   root = root->bind(TOK_TIMER);
     597                 :            : 
     598                 :            :   root->bind_num("s")
     599                 :            :     ->bind_privilege(pr_all)
     600 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     601                 :            :   root->bind_num("s")->bind_num("randomize")
     602                 :            :     ->bind_privilege(pr_all)
     603 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     604                 :            :   root->bind_num("sec")
     605                 :            :     ->bind_privilege(pr_all)
     606 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     607                 :            :   root->bind_num("sec")->bind_num("randomize")
     608                 :            :     ->bind_privilege(pr_all)
     609 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     610                 :            : 
     611                 :            :   root->bind_num("ms")
     612                 :            :     ->bind_privilege(pr_all)
     613 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     614                 :            :   root->bind_num("ms")->bind_num("randomize")
     615                 :            :     ->bind_privilege(pr_all)
     616 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     617                 :            :   root->bind_num("msec")
     618                 :            :     ->bind_privilege(pr_all)
     619 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     620                 :            :   root->bind_num("msec")->bind_num("randomize")
     621                 :            :     ->bind_privilege(pr_all)
     622 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     623                 :            : 
     624                 :            :   root->bind_num("us")
     625                 :            :     ->bind_privilege(pr_all)
     626 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     627                 :            :   root->bind_num("us")->bind_num("randomize")
     628                 :            :     ->bind_privilege(pr_all)
     629 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     630                 :            :   root->bind_num("usec")
     631                 :            :     ->bind_privilege(pr_all)
     632 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     633                 :            :   root->bind_num("usec")->bind_num("randomize")
     634                 :            :     ->bind_privilege(pr_all)
     635 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     636                 :            : 
     637                 :            :   root->bind_num("ns")
     638                 :            :     ->bind_privilege(pr_all)
     639 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     640                 :            :   root->bind_num("ns")->bind_num("randomize")
     641                 :            :     ->bind_privilege(pr_all)
     642 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     643                 :            :   root->bind_num("nsec")
     644                 :            :     ->bind_privilege(pr_all)
     645 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     646                 :            :   root->bind_num("nsec")->bind_num("randomize")
     647                 :            :     ->bind_privilege(pr_all)
     648 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     649                 :            : 
     650                 :            :   root->bind_num("jiffies")
     651                 :            :     ->bind_privilege(pr_all)
     652 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     653                 :            :   root->bind_num("jiffies")->bind_num("randomize")
     654                 :            :     ->bind_privilege(pr_all)
     655 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
         [ +  - ][ +  - ]
     656                 :            : 
     657                 :            :   root->bind_num("hz")
     658                 :            :     ->bind_privilege(pr_all)
     659 [ +  - ][ +  - ]:       1218 :     ->bind(builder);
         [ +  - ][ +  - ]
                 [ +  - ]
     660                 :            : 
     661                 :            :   // Not ok for unprivileged users, because register_timer_hook only
     662                 :            :   // allows a single attached callback.  No resource-sharing -> no
     663                 :            :   // unprivileged access.
     664                 :            :   //
     665                 :            :   // Sigh, but for dyninst users, we want a semantic error that
     666                 :            :   // profile probes aren't supported (which will come from
     667                 :            :   // timer_builder::build()), not a privilege error.  So, we'll fake
     668                 :            :   // it so that profile probes are allowed for all.
     669         [ +  - ]:       1218 :   if (!s.runtime_usermode_p()) {
     670                 :            :     root->bind("profile")
     671 [ +  - ][ +  - ]:       1218 :       ->bind(builder);
         [ +  - ][ +  - ]
     672                 :            :   }
     673                 :            :   else {
     674                 :            :     root->bind("profile")
     675                 :            :       ->bind_privilege(pr_all)
     676 [ #  # ][ #  # ]:          0 :       ->bind(builder);
         [ #  # ][ #  # ]
                 [ #  # ]
     677                 :            :   }
     678 [ +  - ][ +  - ]:       8460 : }
     679                 :            : 
     680                 :            : 
     681                 :            : 
     682                 :            : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */

Generated by: LCOV version 1.9