1    /*
     2     * Copyright (c) 2013-2016, Texas Instruments Incorporated
     3     * All rights reserved.
     4     *
     5     * Redistribution and use in source and binary forms, with or without
     6     * modification, are permitted provided that the following conditions
     7     * are met:
     8     *
     9     * *  Redistributions of source code must retain the above copyright
    10     *    notice, this list of conditions and the following disclaimer.
    11     *
    12     * *  Redistributions in binary form must reproduce the above copyright
    13     *    notice, this list of conditions and the following disclaimer in the
    14     *    documentation and/or other materials provided with the distribution.
    15     *
    16     * *  Neither the name of Texas Instruments Incorporated nor the names of
    17     *    its contributors may be used to endorse or promote products derived
    18     *    from this software without specific prior written permission.
    19     *
    20     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    21     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
    22     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    23     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
    24     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
    25     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
    26     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
    27     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    28     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
    29     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
    30     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31     */
    32    /*
    33     *  ======== Load.xdc ========
    34     */
    35    
    36    package ti.sysbios.utils;
    37    
    38    import xdc.rov.ViewInfo;
    39    
    40    import ti.sysbios.knl.Queue;
    41    import ti.sysbios.knl.Task;
    42    import ti.sysbios.knl.Swi;
    43    import ti.sysbios.interfaces.IHwi;
    44    
    45    import xdc.rov.ViewInfo;
    46    import xdc.runtime.Diags;
    47    import xdc.runtime.Log;
    48    import xdc.runtime.Error;
    49    
    50    /*!
    51     *  ======== Load ========
    52     *  The Load module reports execution times and load information for threads
    53     *  in a system.
    54     *
    55     *  SYS/BIOS manages four distinct levels of execution threads: hardware
    56     *  interrupt service routines, software interrupt routines, tasks, and
    57     *  background idle functions. This module reports execution time and load on a
    58     *  per-task basis, and also provides information globally for hardware
    59     *  interrupt service routines, software interrupt routines and idle functions
    60     *  (in the form of the idle task). It can also report an estimate of the
    61     *  global CPU load.
    62     *
    63     *  Execution time is reported in units of
    64     *  {@link xdc.runtime.Timestamp Timestamp} counts, and load is reported
    65     *  in percentages.
    66     *
    67     *  By default, load data is gathered for Task threads.
    68     *  {@link #hwiEnabled hwiEnabled}, {@link #swiEnabled swiEnabled}
    69     *  and {@link #taskEnabled taskEnabled} can be used to select which
    70     *  type(s) of threads are monitored. These statistics are automatically
    71     *  recorded to the load module's logger instance. Users can also choose
    72     *  to call {@link #getTaskLoad}, {@link #getGlobalSwiLoad},
    73     *  {@link #getGlobalHwiLoad} and {@link #getCPULoad} at any time to obtain the
    74     *  statistics at runtime.
    75     *
    76     *  The module relies on {@link #update} to be called to compute load and
    77     *  execution times from the time when {@link #update} was last called. This
    78     *  is automatically done for every period specified by
    79     *  {@link #windowInMs windowInMs} in an {@link ti.sysbios.knl.Idle Idle}
    80     *  function when {@link #updateInIdle updateInIdle} is
    81     *  set to true. The time between two calls to {@link #update} is called the
    82     *  benchmark time window.
    83     *
    84     *  By passing in a function pointer of type
    85     *  Void(*{@link #postUpdate})(Void) through the
    86     *  {@link #postUpdate postUpdate} config parameter, one can specify a
    87     *  {@link #postUpdate postUpdate} function that is
    88     *  automatically called by {@link #update} immediately after the statistics
    89     *  have been computed at the end of a benchmark time window.  Setting this
    90     *  function allows the user to optionally post-process the thread statistics
    91     *  once and only once per benchmark window.
    92     *
    93     *  Advanced users could optionally omit calling {@link #update} in the idle
    94     *  loop by setting {@link #updateInIdle updateInIdle} to false. They can
    95     *  then call {@link #update} somewhere else (e.g. in a periodic higher
    96     *  priority Task) instead to ensure statistics are computed even when the
    97     *  system is never idle.
    98     *
    99     *  @a(CPU Load Calculation Methods)
   100     *
   101     *  The CPU load is computed in three different ways,
   102     *  depending on what threads are monitored, and whether or not Power
   103     *  management is used to idle the CPU when no threads are running.
   104     *
   105     *  @p(html)
   106     *  <B>Task Load Disabled and No Power Management</B>
   107     *  @p
   108     *
   109     *  The first method of calculating CPU load is used when
   110     *  Task load logging is disabled, ie, {@link #taskEnabled}
   111     *  is false, and Power management is not used. The CPU load is computed as
   112     *  the percentage of time in the benchmark window which was NOT spent in the
   113     *  idle loop. More specifically, the load is computed as follows:
   114     *
   115     *  global CPU load = 100 * (1 - (min. time for a trip around idle loop *
   116     *      # times in idle loop)/(benchmark time window) )
   117     *
   118     *  Any work done in the idle loop is included in the CPU load - in other
   119     *  words, any time spent in the loop beyond the shortest trip around the idle
   120     *  loop is counted as non-idle time.
   121     *
   122     *  This method works fairly well if the timestamp frequency is
   123     *  sufficiently high (for example, if it's equal to the CPU frequency).
   124     *  For the MSP430, however, with the CPU running at 8MHz, when the 32KHz
   125     *  ACLK is used for the timestamp counter, the CPU load is only a very
   126     *  rough approximation, due to the courseness of the timestamp.  The CPU load
   127     *  accuracy can also be affected by caching and user idle functions.
   128     *
   129     *  @p(html)
   130     *  <B>Task Load Enabled and No Power Management</B>
   131     *  @p
   132     *
   133     *  The second method of calculating CPU load is used when Task load logging
   134     *  is enabled ({@link #taskEnabled} = true) and Power management is not used.
   135     *  In this case the CPU load is calculted as
   136     *
   137     *      global CPU load = 100 - (Idle task load)
   138     *
   139     *  This prevents any discrepancy between the calculated CPU load had we
   140     *  used the first method, and 100 - the Idle task load.  If Swi and
   141     *  Hwi load logging are not enabled, however, time spent in a Swi
   142     *  or Hwi will be charged to the task in which it ran.  This will
   143     *  affect the accuracy of the CPU (and Task) load, but the trade off
   144     *  is more overhead to do the Hwi and Swi load logging.
   145     *
   146     *  @p(html)
   147     *  <B>Power Management Enabled</B>
   148     *  @p
   149     *
   150     *  This method applies to targets that have a SYS/BIOS Power
   151     *  module, for example, MSP430.  It does not apply to targets
   152     *  where Power management is part of TI-RTOS (e.g., CC3200).
   153     *
   154     *  The third method of calculating CPU load is used when Power
   155     *  management is enabled.  In this case, the idle loop has a
   156     *  function brought in by the Power module that idles the CPU.
   157     *  The timestamp timer must continue to run during idle, in order
   158     *  to measure idle and non-idle time, however.  This method of
   159     *  calculating CPU load plugs a Hwi hook function which is run
   160     *  at the beginning of every Hwi. An idle function will call
   161     *  Timestamp_get32() to mark the beginning of idle time, and
   162     *  when the first Hwi causes the CPU to come out of idle, the
   163     *  Hwi hook function will call Timestamp_get32() to mark the end
   164     *  of idle time.  The idle function accumulates the idle time
   165     *  and total time elapsed, and the CPU load is calculated as:
   166     *
   167     *    global CPU load = 100 * (1 - idle time / time elapsed)
   168     *
   169     *  With this method of CPU load calculation, all idle functions are
   170     *  included in the CPU load.  When Power is enabled, Task, Swi, and
   171     *  Hwi load logging can be enabled, but you may find that the
   172     *  CPU load does not equal (100 - idle task load), since the CPU load
   173     *  is calculated as the percentage of time that the processor is not
   174     *  powered down, while the idle task load includes powered down time
   175     *  plus time executing idle functions.
   176     *
   177     *  @p(html)
   178     *  <B>Power Management Enabled outside of SYS/BIOS</B>
   179     *  @p
   180     *
   181     *  Some targets have Power management support outside of SYS/BIOS.  For
   182     *  example, CC3200 and CC26XX devices have Power management in TI-RTOS.
   183     *  In these cases, the best way to get CPU load is to make sure that
   184     *  {@link #taskEnabled} is set to true.  Then the CPU load will be
   185     *  calculated as 100 - the idle task load.  However, for BIOS in ROM builds,
   186     *  this method will not work, as Task hooks are not allowed.  So to
   187     *  use Load for any devices that support BIOS in ROM builds, make
   188     *  sure the ROM build is disabled.
   189     *
   190     *  @a(Examples)
   191     *  Configuration example: The following statements configure the Load module
   192     *  to obtain output in the CCS output window. This is useful for early
   193     *  development without RTA tools support in SYS/BIOS:
   194     *
   195     *  @p(code)
   196     *  var System = xdc.useModule('xdc.runtime.System');
   197     *  var SysStd = xdc.useModule('xdc.runtime.SysStd');
   198     *  System.SupportProxy = SysStd;
   199     *
   200     *  var Load = xdc.useModule('ti.sysbios.utils.Load');
   201     *  var LoggerSys = xdc.useModule('xdc.runtime.LoggerSys');
   202     *  var Defaults = xdc.useModule('xdc.runtime.Defaults');
   203     *  var Diags = xdc.useModule('xdc.runtime.Diags');
   204     *
   205     *  // Turn on statistics log messages for Load module
   206     *  Load.common$.diags_USER4 = Diags.ALWAYS_ON;
   207     *  // Define a program-wide logger to be the System Logger
   208     *  Defaults.common$.logger = LoggerSys.create();
   209     *  @p
   210     *
   211     *  Notes on above example:
   212     *  @p(blist)
   213     *  - When using the {@link xdc.runtime.LoggerSys System Logger},
   214     *  {@link xdc.runtime.System#printf System_printf} calls are made to produce
   215     *  the output in the output window. These calls are highly intrusive
   216     *  and are only suited for early development.
   217     *
   218     *  - Also make sure your task stack sizes are large enough when using the
   219     *  {@link xdc.runtime.LoggerSys System Logger} - particularly the idle task
   220     *  stack size since logging is done in the idle task by default.
   221     *  @p
   222     *
   223     *  @a(Caveats)
   224     *  @p(nlist)
   225     *  - For the module to return accurate load values, the {@link #update}
   226     *  function must be run at least once before the Timestamp count gets to
   227     *  wrap around. This means on a platform with a 32-bit
   228     *  {@link xdc.runtime.Timestamp Timestamp} frequency that runs at 200 MHz,
   229     *  the function must be called at least once every 21 sec. With faster
   230     *  {@link xdc.runtime.Timestamp Timestamp} frequencies it would have to be
   231     *  called even more frequently.
   232     *
   233     *  - If the {@link #updateInIdle updateInIdle} option is enabled, the
   234     *  module will call {@link #update} periodically according to
   235     *  {@link #windowInMs windowInMs}. The latter must be set to a time
   236     *  interval that is below
   237     *  (2^32) * 1000 / ({@link xdc.runtime.Timestamp Timestamp} Frequency)
   238     *  milliseconds
   239     *
   240     *  - If the {@link #updateInIdle updateInIdle} option is disabled, the user is
   241     *  then responsible for calling {@link #update} more often than the above
   242     *  time interval.
   243     *
   244     *  - Load values might not add up to 100%. Because the module minimizes
   245     *  its interrupt latency and avoids locking up the system to compute all
   246     *  thread loads at once, each thread's execution time is evaluated separately
   247     *  over its own time window, which could be slightly different to that of
   248     *  another thread.
   249     *
   250     *  - When disabling monitoring of a thread type of higher priority, the
   251     *  time spent in that thread type will be counted towards time spent in
   252     *  threads of lower priority. E.g. if {@link #hwiEnabled hwiEnabled} and
   253     *  {@link #swiEnabled swiEnabled} are both false, then time spent in Hwi's and
   254     *  Swi's will be counted towards the Tasks in which the interrupts happened.
   255     *  Thus, for better accuracy, it is best to leave monitoring on for threads of
   256     *  a higher priority relative to the thread type of interest.
   257     *
   258     *  - When Task load logging is not enabled and Power management is not used,
   259     *  the implementation of {@link #getCPULoad()} self-calibrates the shortest
   260     *  path through the idle loop. It does this by keeping track of the shortest
   261     *  time between invocations of an idle function automatically inserted by the
   262     *  Load module, and assumes that to be the time it takes for one iteration
   263     *  through the idle loop. Because of this, the CPU load value is only an
   264     *  estimate since the idle loop might occasionally take longer to run
   265     *  (e.g. due to caching effects, stalls). The reported CPU load tends to be
   266     *  slightly higher than reality, especially when the load is low.
   267     *
   268     *  - If {@link #taskEnabled taskEnabled} is set to true,
   269     *  task name support will be automatically turned on so that the Load module
   270     *  can print out the task names in its log output.
   271     *
   272     *  - Currently does not support {@link xdc.runtime.Timestamp Timestamp}
   273     *  frequencies over 4 GHz.
   274     *  @p
   275     *
   276     *  @p(html)
   277     *  <h3> Calling Context </h3>
   278     *  <table border="1" cellpadding="3">
   279     *    <colgroup span="1"></colgroup> <colgroup span="5" align="center">
   280     *    </colgroup>
   281     *
   282     *    <tr><th> Function                 </th><th>  Hwi   </th><th>  Swi   </th>
   283     *    <th>  Task  </th><th>  Main  </th><th>  Startup  </th></tr>
   284     *    <!--                                                          -->
   285     *    <tr><td> {@link #getCPULoad}      </td><td>   Y    </td><td>   Y    </td>
   286     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   287     *    <tr><td> {@link #getGlobalHwiLoad}</td><td>   Y    </td><td>   Y    </td>
   288     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   289     *    <tr><td> {@link #getGlobalSwiLoad}</td><td>   Y    </td><td>   Y    </td>
   290     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   291     *    <tr><td> {@link #getTaskLoad}     </td><td>   Y    </td><td>   Y    </td>
   292     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   293     *    <tr><td> {@link #reset}           </td><td>   Y*   </td><td>   Y*   </td>
   294     *    <td>   Y    </td><td>   Y    </td><td>   N    </td></tr>
   295     *    <tr><td> {@link #update}          </td><td>   Y*   </td><td>   Y*   </td>
   296     *    <td>   Y    </td><td>   N    </td><td>   N    </td></tr>
   297     *    <tr><td colspan="6"> Definitions: <br />
   298     *       <ul>
   299     *         <li> <b>Hwi</b>: API is callable from a Hwi thread. </li>
   300     *         <li> <b>Swi</b>: API is callable from a Swi thread. </li>
   301     *         <li> <b>Task</b>: API is callable from a Task thread. </li>
   302     *         <li> <b>Main</b>: API is callable during any of these phases: </li>
   303     *           <ul>
   304     *             <li> In your module startup after this module is started
   305     *    (e.g. Load_Module_startupDone() returns TRUE). </li>
   306     *             <li> During xdc.runtime.Startup.lastFxns. </li>
   307     *             <li> During main().</li>
   308     *             <li> During BIOS.startupFxns.</li>
   309     *           </ul>
   310     *         <li> <b>Startup</b>: API is callable during any of these phases:</li>
   311     *           <ul>
   312     *             <li> During xdc.runtime.Startup.firstFxns.</li>
   313     *             <li> In your module startup before this module is started
   314     *    (e.g. Load_Module_startupDone() returns FALSE).</li>
   315     *           </ul>
   316     *       <li> <b>*</b>: Indicates only when {@link #taskEnabled taskEnabled}
   317     *    is set to false. </li>
   318     *       </ul>
   319     *    </td></tr>
   320     *  </table>
   321     *  @p
   322     */
   323    
   324    @Template("./Load.xdt")
   325    @DirectCall
   326    module Load
   327    {
   328        /*!
   329         *  ======== ModuleView ========
   330         *  @_nodoc
   331         */
   332        metaonly struct ModuleView {
   333            String cpuLoad;     /* total cpu load, in percent */
   334            String swiLoad;     /* cpu load due to Swi's, in percent */
   335            String hwiLoad;     /* cpu load due to Hwi's, in percent */
   336            String idleError;   /* estimated measurement error in one pass of idle
   337                                 * loop, in percent
   338                                 */
   339        }
   340    
   341        /*!
   342         *  ======== rovViewInfo ========
   343         *  @_nodoc
   344         */
   345        @Facet
   346        metaonly config ViewInfo.Instance rovViewInfo =
   347            ViewInfo.create({
   348                viewMap: [
   349                [
   350                    'Module',
   351                    {
   352                        type: ViewInfo.MODULE,
   353                        viewInitFxn: 'viewInitModule',
   354                        structName: 'ModuleView'
   355                    }
   356                ],
   357                ]
   358            });
   359    
   360    
   361        /* -------- Module Types -------- */
   362    
   363        /*!
   364         *  ======== FuncPtr ========
   365         *  Callback function type
   366         */
   367        typedef Void (*FuncPtr)();
   368    
   369        /*!
   370         *  ======== Stat ========
   371         *  Load statistics info
   372         */
   373        struct Stat {
   374            UInt32 threadTime;
   375            UInt32 totalTime;
   376        };
   377    
   378    
   379        /* -------- Module Configuration Parameters -------- */
   380    
   381        /*!
   382         *  ======== LS_cpuLoad ========
   383         *  This event logs the global CPU load as a percentage
   384         *
   385         *  This event is logged whenever the Diags.USER4 level is enabled
   386         *  and the load is measured.
   387         *
   388         */
   389        config Log.Event LS_cpuLoad = {
   390            mask: Diags.USER4,
   391            msg: "LS_cpuLoad: %d%%"
   392        };
   393    
   394        /*!
   395         *  ======== LS_hwiLoad ========
   396         *  This event logs the Hwi load
   397         *
   398         *  This event is logged whenever the Diags.USER4 level is enabled
   399         *  {@link #hwiEnabled} is true, and the load is measured.
   400         *
   401         *  This event logs the Hwi load, with the form:
   402         *  <load time>,<measurement time>
   403         *
   404         *  Percentage load = <load time> / <measurement time> x 100%
   405         */
   406        config Log.Event LS_hwiLoad = {
   407            mask: Diags.USER4,
   408            msg: "LS_hwiLoad: %d,%d"
   409        };
   410    
   411        /*!
   412         *  ======== LS_swiLoad ========
   413         *  This event logs the Swi load
   414         *
   415         *  This event is logged whenever the Diags.USER4 level is enabled
   416         *  {@link #swiEnabled} is true, and the load is measured.
   417         *
   418         *  This event logs the Swi load, with the form:
   419         *  <load time>,<measurement time>
   420         *
   421         *  Percentage load = <load time> / <measurement time> x 100%
   422         */
   423        config Log.Event LS_swiLoad = {
   424            mask: Diags.USER4,
   425            msg: "LS_swiLoad: %d,%d"
   426        };
   427    
   428        /*!
   429         *  ======== LS_taskLoad ========
   430         *  This event logs Task thread loads
   431         *
   432         *  This event is logged whenever the Diags.USER4 level is enabled,
   433         *  {@link #taskEnabled} is true, and the load is measured.
   434         *
   435         *  This event logs Task thread loads, with the form:
   436         *  <Task handle>,<load time>,<measurement time>,<Task function pointer>
   437         *
   438         *  Percentage load = <load time> / <measurement time> x 100%
   439         */
   440        config Log.Event LS_taskLoad = {
   441            mask: Diags.USER4,
   442            msg: "LS_taskLoad: 0x%x,%d,%d,0x%x"
   443        };
   444    
   445        /*!
   446         *  ======== postUpdate ========
   447         *  User function called after each load update
   448         *
   449         *  If non-NULL, postUpdate is run immediately after each update.
   450         */
   451        config FuncPtr postUpdate = null;
   452    
   453        /*!
   454         *  ======== updateInIdle ========
   455         *  Automatically call {@link #update} in Idle loop
   456         *
   457         *  If this parameter is set to `true`, an {@link ti.sysbios.knl.Idle Idle}
   458         *  function, which computes and updates the CPU load, is added to the
   459         *  {@link ti.sysbios.knl.Idle#run Idle loop}.
   460         */
   461        config Bool updateInIdle = true;
   462    
   463        /*!
   464         *  ======== enableCPULoadCalc ========
   465         *  Automatically update the Load module's CPU load value in
   466         *  {@link #update}.
   467         *
   468         *  If this parameter is set to `true`, Load_update() will calculate
   469         *  the CPU load for the elapsed time.  In some cases, the user may
   470         *  prefer to use the statistics gathered by the Load module and do
   471         *  the CPU load calculation themself.  Set this parameter to false,
   472         *  to disable the Load module's CPU load calculations.  This can
   473         *  improve performance of the Load_update() call.
   474         */
   475        metaonly config Bool enableCPULoadCalc = true;
   476    
   477        /*!
   478         *  ======== minIdle ========
   479         *  Specifies the minimum time used to compute idle time
   480         *
   481         *  During CPU load measurement, the minimum time observed executing
   482         *  the idle loop together with the count of the number of times the idle
   483         *  loop runs id used to compute the total idle time.  However, since the
   484         *  _actual_ time spent in the idle loop will almost always be greater
   485         *  then the observed minimum, the idle time is almost always under
   486         *  estimated.
   487         *
   488         *  This configuration parameter can be used to compensate for this
   489         *  underestimate by placing a lower bound on the minimum time used in
   490         *  the CPU measurements.  The minimum idle time used to compute CPU
   491         *  load is guarenteed to be greater than or equal to `minIdle`.
   492         */
   493        metaonly config UInt32 minIdle = 0;
   494    
   495        /*!
   496         *  ======== windowInMs ========
   497         *  Load averaging period
   498         *
   499         *  When {@link #updateInIdle} is enabled, this period determines the
   500         *  minimum elapsed time between updates of the load statistics in the
   501         *  idle loop.
   502         */
   503        config UInt windowInMs = 500;
   504    
   505        /*!
   506         *  ======== hwiEnabled ========
   507         *  Enables Hwi time monitoring
   508         *
   509         *  When this parameter is set to `true`, {@link ti.sysbios.hal.Hwi Hwi}
   510         *  processing time is accumulated between successive calls of
   511         *  {@link #update} and, as part of Load_update, an
   512         *  {@link #LS_hwiLoad event} with this cumulative time is logged.  This
   513         *  time, together with the total elapsed time, is used to estimate the
   514         *  CPU load due to any Hwi instances run between these updates.
   515         */
   516        config Bool hwiEnabled = false;
   517    
   518        /*!
   519         *  ======== swiEnabled ========
   520         *  Enables Swi time monitoring
   521         *
   522         *  When this parameter is set to `true`, Swi processing time is
   523         *  accumulated between successive calls of {@link #update} and, as
   524         *  part of Load_update, an {@link #LS_swiLoad event} with this
   525         *  cumulative time is logged.  This time together with the total
   526         *  elapsed time is used to estimate the CPU load due to any Swi
   527         *  instances run between these updates.
   528         */
   529        config Bool swiEnabled = false;
   530    
   531        /*!
   532         *  ======== taskEnabled ========
   533         *  Enables Task time monitoring
   534         *
   535         *  When this parameter is set to `true`, each Task's processing time is
   536         *  accumulated between successive calls of {@link #update} and, as
   537         *  part of Load_update, an {@link #LS_taskLoad event} with this
   538         *  cumulative time is logged for each task.  This time together with the
   539         *  total elapsed time is used to estimate the CPU load due to each Task
   540         *  run between these updates.
   541         */
   542        config Bool taskEnabled = true;
   543    
   544        /* -------- Module Functions -------- */
   545    
   546        /*!
   547         *  ======== getTaskLoad ========
   548         *  Return the load and time spent in a specific task
   549         *
   550         *  This function returns the load and time spent in a specific task
   551         *  along with the duration over which the measurement was done. Numbers
   552         *  are reported in  {@link xdc.runtime.Timestamp Timestamp} counts.
   553         *
   554         *  Task handle must be valid and have been registered with Load.
   555         *
   556         *  @param(task) Handle of the Task which time we are interested in.
   557         *  @param(stat) Load and time statistics info
   558         *  @b(returns) TRUE if success, FALSE if failure
   559         *
   560         */
   561        Bool getTaskLoad(Task.Handle task, Stat *stat);
   562    
   563        /*!
   564         *  ======== update ========
   565         *  Record thread statistics and reset all counters
   566         *
   567         *  If {@link #taskEnabled taskEnabled} is set to true, this function can
   568         *  only be called in task context.
   569         */
   570        Void update();
   571    
   572        /*!
   573         *  @_nodoc
   574         *  ======== updateCPULoad ========
   575         *  Record CPU load only.  This function is used only when Power idling
   576         *  is enabled.
   577         *
   578         *  If Power idling is available for the device and enabled, a different
   579         *  method of CPU load calculation must be used. Since the idle loop will
   580         *  not be executing while the CPU is idle, we cannot measure the idle
   581         *  time by multiplying the number of times the idle loop ran, by the
   582         *  minumum time through one iteration of the idle loop.  Instead, we
   583         *  use a {@link ti.sysbios.knl.hal.Hwi} hook function for measuring
   584         *  idle time. The hook function is run at the beginning of each Hwi,
   585         *  and the first Hwi to cause the CPU to come out of idle, will mark
   586         *  the end of idle time.
   587         *
   588         */
   589        @DirectCall
   590        Void updateCPULoad();
   591    
   592        /*!
   593         *  @_nodoc
   594         *  ======== updateLoads ========
   595         *  Record CPU load and thread loads if Task, Swi, or Hwi load logging
   596         *  is enabled. This function is called by Load_update() if Power
   597         *  management is not used.
   598         */
   599        @DirectCall
   600        Void updateLoads();
   601    
   602        /*!
   603         *  @_nodoc
   604         *  ======== updateContextsAndPost ========
   605         *  This function is called by Load_update() when Load.enableCPULoadCalc
   606         *  is false.
   607         *  Updates the current thread's time and hook contexts for all threads.
   608         *  Call the postUpdate() function.  It is up to the application to
   609         *  calculate the loads.
   610         */
   611        @DirectCall
   612        Void updateContextsAndPost();
   613    
   614        /*!
   615         *  @_nodoc
   616         *  ======== updateCurrentThreadTime ========
   617         *  Update the total time for the currently running thread.  This function
   618         *  will be called if Task, Swi, or Hwi Load logging is enabled.
   619         */
   620        @DirectCall
   621        Void updateCurrentThreadTime();
   622    
   623        /*!
   624         *  @_nodoc
   625         *  ======== updateThreadContexts ========
   626         *  Update hook contexts for all threads.  This function
   627         *  will be called if Task, Swi, or Hwi Load logging is enabled.
   628         */
   629        @DirectCall
   630        Void updateThreadContexts();
   631    
   632        /*!
   633         *  ======== reset ========
   634         *  Reset all internal load counters
   635         *
   636         *  If {@link #taskEnabled taskEnabled} is set to true, this function can
   637         *  only be called in task context.
   638         */
   639        Void reset();
   640    
   641        /*!
   642         *  ======== getGlobalSwiLoad ========
   643         *  Return the load and time spent in Swi's
   644         *
   645         *  This function returns the load and time spent in Swi's along with
   646         *  the time duration over which the measurement was done. Numbers are
   647         *  reported in  {@link xdc.runtime.Timestamp Timestamp} counts.
   648         *
   649         *  @param(stat) Load and time statistics info
   650         *  @b(returns) TRUE if success, FALSE if failure
   651         *
   652         */
   653        Bool getGlobalSwiLoad(Stat *stat);
   654    
   655        /*!
   656         *  ======== getGlobalHwiLoad ========
   657         *  Return the load and time spent in hwi's
   658         *
   659         *  This function computes the load and time spent in Hwi's along
   660         *  with the time duration over which the measurement was done. Numbers
   661         *  are reported in  {@link xdc.runtime.Timestamp Timestamp} counts.
   662         *
   663         *  @param(stat) Load and time statistics info
   664         *
   665         *  @b(returns) TRUE if success, FALSE if failure
   666         */
   667        Bool getGlobalHwiLoad(Stat *stat);
   668    
   669        /*!
   670         *  ======== getCPULoad ========
   671         *  Return an estimate of the global CPU load
   672         *
   673         *  This function returns an estimate of CPU load (% utilization of the
   674         *  CPU), with the idle time determined based on number of trips through
   675         *  the idle loop multiplied by the shortest amount of time through the
   676         *  loop.
   677         *
   678         *  This function requires the idle loop to be run during a benchmark time
   679         *  window.
   680         *
   681         *  Note: Time spent in kernel while switching to a Hwi/Swi/Task is
   682         *        considered non-idle time.
   683         *
   684         *  @b(returns) CPU load in %
   685         *
   686         */
   687        UInt32 getCPULoad();
   688    
   689        /*!
   690         *  ======== calculateLoad ========
   691         *  Compute total CPU load from a Load_Stat structure
   692         *
   693         *  This function computes percent load from the
   694         *  values in a Load_Stat structure.
   695         *
   696         *  @a(returns) Load value of a Load_Stat structure in %.
   697         */
   698        UInt32 calculateLoad(Stat *stat);
   699    
   700        /*!
   701         *  ======== setMinIdle ========
   702         *  Set lower bound on idle loop time used to compute CPU load
   703         *
   704         *  @see #minIdle
   705         */
   706        UInt32 setMinIdle(UInt32 newMinIdleTime);
   707    
   708        /*! @_nodoc
   709         *  ======== addTask ========
   710         *  Add a task to the list for benchmarking
   711         *
   712         *  If {@link #taskEnabled} is set to true, this function can only be
   713         *  called in task context.
   714         *
   715         *  @param(task) Handle of the Task to be added to the list.
   716         *  @param(env) Handle of context structure to be used by the Task
   717         */
   718        Void addTask(Task.Handle task, HookContext *env);
   719    
   720        /*! @_nodoc
   721         *  ======== removeTask ========
   722         *  Remove a task from the list for benchmarking
   723         *
   724         *  If {@link #taskEnabled} is set to true, this funciton can only be
   725         *  called in task context.
   726         *
   727         *  @param(taskHandle) Handle of the Task to be removed from the list.
   728         */
   729        Bool removeTask(Task.Handle task);
   730    
   731        /*!
   732         *  @_nodoc
   733         *  ======== idleFxn ========
   734         *  Idle function used to periodically update the Task time values
   735         */
   736        Void idleFxn();
   737    
   738        /*!
   739         *  @_nodoc
   740         *  ======== idleFxnPwr ========
   741         *  Idle function used when Power idling is enabled.
   742         */
   743        @DirectCall
   744        Void idleFxnPwr();
   745    
   746        /*!
   747         *  @_nodoc
   748         *  ======== Load_startup ========
   749         *  Initialize thread load update times.
   750         */
   751        Void startup();
   752    
   753        /* -------- Hook Functions -------- */
   754    
   755        /*!
   756         *  @_nodoc
   757         *  ======== taskCreateHook ========
   758         *  Create hook function used to initialize all task's hook context
   759         *  to NULL during creation time. Also adds the task's hook context
   760         *  when {@link #autoAddTasks} is set to true.
   761         *
   762         *  @param(task) Handle of the Task to initialize.
   763         *  @param(eb) Error block.
   764         */
   765        Void taskCreateHook(Task.Handle task, Error.Block *eb);
   766    
   767        /*!
   768         *  @_nodoc
   769         *  ======== taskDeleteHook ========
   770         *  Delete hook function used to remove the task's hook context
   771         *  when {@link #autoAddTasks} is set to true.
   772         *
   773         *  @param(task) Handle of the Task to delete.
   774         */
   775        Void taskDeleteHook(Task.Handle task);
   776    
   777        /*!
   778         *  @_nodoc
   779         *  ======== taskSwitchHook ========
   780         *  Switch hook function used to perform benchmarks
   781         *
   782         *  @param(curTask) Handle of currently executing Task.
   783         *  @param(nextTask) Handle of the next Task to run
   784         */
   785        Void taskSwitchHook(Task.Handle curTask, Task.Handle nextTask);
   786    
   787        /*!
   788         *  @_nodoc
   789         *  ======== swiBeginHook ========
   790         *  Swi begin hook function used to perform benchmarks
   791         *
   792         *  @param(swi) Handle of Swi to begin execution.
   793         */
   794        Void swiBeginHook(Swi.Handle swi);
   795    
   796        /*!
   797         *  @_nodoc
   798         *  ======== swiEndHook ========
   799         *  Swi end hook function used to perform benchmarks
   800         *
   801         *  @param(swi) Handle of Swi to end execution.
   802         */
   803        Void swiEndHook(Swi.Handle swi);
   804    
   805        /*!
   806         *  @_nodoc
   807         *  ======== hwiBeginHook ========
   808         *  Hwi begin hook function used to perform benchmarks
   809         *
   810         *  @param hwi Handle of Hwi to begin execution.
   811         */
   812        Void hwiBeginHook(IHwi.Handle hwi);
   813    
   814        /*!
   815         *  @_nodoc
   816         *  ======== hwiEndHook ========
   817         *  Hwi end hook function used to perform benchmarks
   818         *
   819         *  @param hwi Handle of Hwi to end execution.
   820         */
   821        Void hwiEndHook(IHwi.Handle hwi);
   822    
   823        /*!
   824         *  @_nodoc
   825         *  ======== taskRegHook ========
   826         *  Registration function for the module's hook
   827         *
   828         *  Moved out of the internal section for ROM purposes. This function
   829         *  is not referenced directly, so it must be a "public" function so
   830         *  that the linker does not drop it when creating a ROM image.
   831         *
   832         *  @param(id) The id of the hook for use in load.
   833         */
   834        Void taskRegHook(Int id);
   835    
   836    internal:   /* not for client use */
   837    
   838        /* -------- Internal Module Types -------- */
   839    
   840        /*!
   841         *  @_nodoc
   842         *  Hook Context
   843         */
   844        struct HookContext {
   845            Queue.Elem qElem;        /*! Queue element */
   846            UInt32 totalTimeElapsed; /*! Total amount of time elapsed */
   847            UInt32 totalTime;        /*! time spent in thread */
   848            UInt32 nextTotalTime;    /*! working counter of time spent in thread */
   849            UInt32 timeOfLastUpdate; /*! time when update was last called */
   850            Ptr threadHandle;        /*! handle to thread whose context this is */
   851        };
   852    
   853        /* -------- Internal Module Parameters -------- */
   854    
   855        /*! @_nodoc
   856         *  Automatically add all tasks
   857         */
   858        config Bool autoAddTasks = true;
   859    
   860        /*! @_nodoc
   861         *  Is power management enabled?
   862         */
   863        metaonly config Bool powerEnabled;
   864    
   865        /* -------- Internal Module Functions -------- */
   866    
   867        /*!
   868         *  @_nodoc
   869         *  ======== logLoads ========
   870         *  Logs load values for all monitored threads.
   871         *  Statistics messages from the kernel must be enabled
   872         *  (via Load.common$.diags_USER4) in order to see the output.
   873         *
   874         *  If {@link #taskEnabled} is set to TRUE, this function can only be
   875         *  called in task context.
   876         */
   877        Void logLoads();
   878    
   879        /*!
   880         *  @_nodoc
   881         *  ======== logCPULoad ========
   882         *  Log CPU load only.
   883         */
   884        Void logCPULoad();
   885    
   886        struct Module_State {
   887            Queue.Object taskList;   /* List to hold registered task instances */
   888    
   889            Int taskHId;             /* Task Hook Context Id for this module */
   890    
   891            UInt32 taskStartTime[];  /* The start time of the current task */
   892            UInt32 timeElapsed;      /* Working count of time elapsed */
   893            Task.Handle runningTask[]; /* Currently running task */
   894            Bool firstSwitchDone;    /* Flag for first task switch */
   895    
   896            UInt32 swiStartTime;     /* Start time of the current Swi */
   897            HookContext swiEnv;      /* Singleton hook context for swi's */
   898            HookContext taskEnv[];   /* Hook contexts for static tasks */
   899            UInt32 swiCnt;           /* number of Swi's currently executing */
   900    
   901            UInt32 hwiStartTime;     /* Start time of the current Hwi */
   902            HookContext hwiEnv;      /* Singleton hook context for hwi's */
   903            UInt32 hwiCnt;           /* number of Hwi's currently executing */
   904    
   905            UInt32 timeSlotCnt;      /* count of number of time windows printed */
   906    
   907            UInt32 minLoop;          /* shortest time thru the idle loop */
   908            UInt32 minIdle;          /* minLoop is never set below this value */
   909            UInt32 t0;               /* start time of previous call to idle fxn */
   910            UInt32 idleCnt;          /* number of times through idle loop */
   911            UInt32 cpuLoad;          /* CPU load in previous time window */
   912    
   913            UInt32 taskEnvLen;       /* Length of static taskEnv array */
   914            UInt32 taskNum;          /* Number of initialized static tasks */
   915    
   916            /* Fields for CPU load calculation with Power idling */
   917            Bool   powerEnabled;
   918            UInt32 idleStartTime;
   919            UInt32 busyStartTime;
   920            UInt32 busyTime;
   921        };
   922    }