spyLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:22k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* spyLib.c - spy CPU activity library */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 03n,16oct01,jn   use symFindSymbol for symbol lookup (SPR #7453)
  8. 03m,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  9. 03l,18sep97,kkk  fixed typo in spyClkInt() (SPR# 8886), updated copyright.
  10. 03k,22oct95,jdi  doc: removed references to dbxtool/dbxTask (SPR 4378).
  11. 03j,12jun95,p_m  updated man pages.
  12. 03i,27may95,p_m  implemented decoupling of the result display to allow
  13.  host browser spy to run silently.
  14.  Moved spyHelp to usrLib.c.
  15. 03h,01nov94,kdl  merge cleanup - fixed spyStackSize definition.
  16. 03g,02dec93,tpr  increased spy stack size for Am29K.
  17. 03g,02may94,ms   increased stacksize for the simulator.
  18. 03f,13feb93,kdl  changed cplusLib.h to private/cplusLibP.h (SPR #1917).
  19. 03e,20jan93,jdi  documentation cleanup for 5.1.
  20. 03d,31oct92,jcf  increased spy stack size for 68k.
  21. 03c,31oct92,ccc  increased spy stack size for I960.
  22. 03b,04aug92,ajm  fixed define of nameToPrint to be char *
  23. 03a,01aug92,srh  added C++ demangling idiom to spyReport
  24. 02z,30jul92,smb  changed format for printf to avoid zero padding.
  25. 02y,04jul92,jcf  scalable/ANSI/cleanup effort.
  26. 02x,26may92,rrr  the tree shuffle
  27. 02w,22apr92,jwt  converted CPU==SPARC to CPU_FAMILY==SPARC; copyright.
  28. 02v,23mar92,jmm  changed spyClkStart and spyReport to check for null ptrs
  29.                  SPR #1384
  30. 02u,19nov91,rrr  shut up some ansi warnings.
  31. 02t,15oct91,ajm  modified spy stack size for MIPS too
  32. 02s,15oct91,jwt  02q merge never did initialize auxClkTickPerSecond to 60.
  33. 02r,04oct91,rrr  passed through the ansification filter
  34.                   -changed functions to ansi style
  35.   -changed VOID to void
  36.   -changed copyright notice
  37. 02q,23may91,jwt  modified spy stack size, init auxClkTickPerSecond for SPARC.
  38. 02p,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  39.  doc review by shl.
  40. 02o,24mar91,jdi  documentation cleanup.
  41. 02n,10aug90,dnw  added forward declaration of spyTaskIdListSort().
  42. 02m,28jun90,shl  cleared sysKernelTicks and sysKernelIncTicks in sysSpyStart().
  43. 02l,21jun90,shl  added task names and priorities to spy report,
  44.  display of tasks now ordered by priority.
  45.  added spyTaskIdListSort().
  46.          set auxClkRate back to its original value after spyStop().
  47.  replaced sysAuxClkDisconnect() by sysAuxClkDisable().
  48. 02k,14apr90,jcf  remove tcbx dependencies
  49.  added kernel state time.
  50.  changed name of spyTask to tSpyTask.
  51. 02j,19mar90,jdi  documentation cleanup.
  52. 02i,20aug88,gae  documentation.
  53. 02h,22jun88,dnw  name tweaks.
  54.  clean-up.
  55. 02g,07jun88,gae  added call to sysClkEnable ().
  56. 02f,06jun88,dnw  changed taskSpawn/taskCreate args.
  57. 02e,04jun88,gae  changed spyStart() to spyClkStart().
  58.  added spyClkStop().
  59. 02c,30may88,dnw  changed to v4 names.
  60. 02b,24mar88,gae  fixed spyReport() formatting, % calculations, prints
  61.    out tasks that have no ticks & newly created tasks.
  62.  fixed bugs allowing multiple spy's & extra delete hooks.
  63. 02a,07mar88,gae  made it work with generic kernel -- does not use
  64.    static array for tasks.
  65.  Renamed module and all routines to "spy".
  66.  Added spy{Create,Delete}Task() to correctly handle
  67.    variable number of tasks between reports.
  68. 01i,04nov87,ecs  documentation.
  69. 01h,02apr87,ecs  eased lint's mind in taReport.
  70. 01g,23mar87,jlf  documentation.
  71. 01f,20feb87,jlf  made taStart check the parameter returned by
  72.    sysAuxClkConnect, to determine whether the board has
  73.    an aux clock on it.
  74. 01e,21dec86,dnw  changed to not get include files from default directories.
  75. 01d,19nov86,llk  Added spyTask.
  76. 01c,06nov86,jlf  Changed to use new CPU-independent routines, sysAuxClk...
  77. 01b,24oct85,dnw  changed taSpy to explicity spawn periodRun since default
  78.    parameters supplied by period, weren't adequate.
  79. 01a,22oct85,jlf  written.
  80. */
  81. /*
  82. DESCRIPTION
  83. This library provides a facility to monitor tasks' use of the CPU.
  84. The primary interface routine, spy(), periodically calls spyReport() to
  85. display the amount of CPU time utilized by each task, the amount of time
  86. spent at interrupt level, the amount of time spent in the kernel, and the
  87. amount of idle time.  It also displays the total usage since the start of
  88. spy() (or the last call to spyClkStart()), and the change in usage since
  89. the last spyReport().
  90. CPU usage can also be monitored manually by calling spyClkStart() and
  91. spyReport(), instead of spy().  In this case, spyReport() provides a one-time
  92. report of the same information provided by spy().
  93. Data is gathered by an interrupt-level routine that is connected by
  94. spyClkStart() to the auxiliary clock.  Currently, this facility cannot be
  95. used with CPUs that have no auxiliary clock.  Interrupts that are at a
  96. higher level than the auxiliary clock's interrupt level cannot be
  97. monitored.
  98. All user interface routine except spyLibInit() are available through usrLib.
  99. EXAMPLE
  100. The following call:
  101. .CS
  102.     -> spy 10, 200
  103. .CE
  104. will generate a report in the following format every 10 seconds,
  105. gathering data at the rate of 200 times per second.
  106. .CS
  107. .ne 5
  108. &NAME          ENTRY       TID   PRI  total % (ticks)  delta % (ticks)
  109. &--------     --------    -----  ---  ---------------  ---------------
  110. &tExcTask     _excTask    fbb58    0    0% (       0)    0% (       0)
  111. &tLogTask     _logTask    fa6e0    0    0% (       0)    0% (       0)
  112. &tShell       _shell      e28a8    1    0% (       4)    0% (       0)
  113. &tRlogind     _rlogind    f08dc    2    0% (       0)    0% (       0)
  114. &tRlogOutTask _rlogOutTa  e93e0    2    2% (     173)    2% (      46)
  115. &tRlogInTask  _rlogInTas  e7f10    2    0% (       0)    0% (       0)
  116. &tSpyTask     _spyTask    ffe9c    5    1% (     116)    1% (      28)
  117. &tNetTask     _netTask    f3e2c   50    0% (       4)    0% (       1)
  118. &tPortmapd    _portmapd   ef240  100    0% (       0)    0% (       0)
  119. &KERNEL                                 1% (     105)    0% (      10)
  120. &INTERRUPT                              0% (       0)    0% (       0)
  121. &IDLE                                  95% (    7990)   95% (    1998)
  122. &TOTAL                                 99% (    8337)   98% (    2083)
  123. .CE
  124. The "total" column reflects CPU activity since the initial call to spy()
  125. or the last call to spyClkStart().  The "delta" column reflects activity
  126. since the previous report.  A call to spyReport() will produce a single
  127. report; however, the initial auxiliary clock interrupts and data collection
  128. must first be started using spyClkStart().
  129. Data collection/clock interrupts and periodic reporting are stopped by
  130. calling:
  131. .CS
  132.     -> spyStop
  133. .CE
  134. INCLUDE FILES: spyLib.h
  135. SEE ALSO: usrLib
  136. */
  137. #include "vxWorks.h"
  138. #include "sysSymTbl.h"
  139. #include "sysLib.h"
  140. #include "taskHookLib.h"
  141. #include "logLib.h"
  142. #include "stdio.h"
  143. #include "intLib.h"
  144. #include "spyLib.h"
  145. #include "private/cplusLibP.h"
  146. #include "private/windLibP.h"
  147. #define MAX_SPY_TASKS 200 /* max tasks that can be spy'd */
  148. /* spyTask parameters */
  149. int spyTaskId = ERROR; /* ERROR = spy task not active */
  150. int spyTaskOptions = VX_UNBREAKABLE;
  151. int spyTaskPriority = 5;
  152. #if ((CPU_FAMILY==SPARC) || (CPU_FAMILY==MIPS) || (CPU_FAMILY==I960) || 
  153.  (CPU_FAMILY== AM29XXX)  ||  (CPU_FAMILY== SIMSPARCSUNOS) || 
  154.  (CPU_FAMILY==SIMHPPA))
  155. int spyTaskStackSize = 10000;
  156. #else
  157. int spyTaskStackSize = 6000;
  158. #endif /* CPU_FAMILY==SPARC || CPU_FAMILY==MIPS || CPU_FAMILY==I960 ... */
  159. /* global variables */
  160. /* 
  161.  * The variables below must remain declared in the order they are declared 
  162.  * here since they are read by host tools using gopher.
  163.  */
  164. UINT spyTotalTicks; /* all ticks since start */
  165. UINT spyIncTicks; /* all ticks since last report */
  166. UINT spyInterruptTicks; /* int ticks since start */
  167. UINT spyInterruptIncTicks; /* int ticks since last report */
  168. UINT spyKernelTicks; /* int ticks since start */
  169. UINT spyKernelIncTicks; /* int ticks since last report */
  170. UINT spyIdleTicks; /* idle ticks since start */
  171. UINT spyIdleIncTicks; /* idle ticks since last report*/
  172. /* local variables */
  173. LOCAL BOOL spyClkRunning; /* TRUE = spyClkStart'ed */
  174. LOCAL BOOL spyInitialized; /* TRUE = hooks installed */
  175. LOCAL int  spyCreateCount; /* num tasks created since report */
  176. LOCAL int  spyDeleteCount; /* num tasks deleted since report */
  177. #if CPU_FAMILY==SPARC
  178. LOCAL int  auxClkTicksPerSecond = 60;
  179. #else /* CPU_FAMILY==SPARC */
  180. LOCAL int  auxClkTicksPerSecond;
  181. #endif /* CPU_FAMILY==SPARC */
  182. /* display formats */
  183. LOCAL char *spyFmt1 = "%-12.12s %-10.10s %8x  %3d   %3d%% (%8d)  %3d%% (%8d)n";
  184. LOCAL char *spyFmt2 = "%-12.12s %-10.10s %8s  %3s   %3d%% (%8d)  %3d%% (%8d)n";
  185. /* forward static functions */
  186. static void spyCreateHook (WIND_TCB *pTcb);
  187. static void spyDeleteHook (WIND_TCB *pTcb);
  188. static void spyClkInt (void);
  189. static void spyTaskIdListSort (int idList [ ], int nTasks);
  190. /*******************************************************************************
  191. *
  192. * spyLibInit - initialize task cpu utilization tool package
  193. *
  194. * This routine initializes the task cpu utilization tool package.  
  195. * If the configuration macro INCLUDE_SPY is defined, it is called by the root 
  196. * task, usrRoot(), in usrConfig.c.
  197. *
  198. * RETURNS: N/A
  199. *
  200. * SEE ALSO: usrLib
  201. */
  202. void spyLibInit (void)
  203.     {
  204.     _func_spy = (FUNCPTR) spyCommon;
  205.     _func_spyStop = (FUNCPTR) spyStopCommon;
  206.     _func_spyClkStart  = (FUNCPTR) spyClkStartCommon;
  207.     _func_spyClkStop  = (FUNCPTR) spyClkStopCommon;
  208.     _func_spyTask  = (FUNCPTR) spyComTask;
  209.     _func_spyReport = (FUNCPTR) spyReportCommon;
  210.     }
  211. /*******************************************************************************
  212. *
  213. * spyCreateHook - initialize task tick counters
  214. *
  215. * This routine is installed as a task create hook so that the task tick
  216. * counters can be initialized and spyReport() can indicate when new tasks
  217. * appear between reports.
  218. *
  219. * RETURNS: N/A
  220. */
  221. LOCAL void spyCreateHook
  222.     (
  223.     WIND_TCB *pTcb      /* WIND_TCB of new task */
  224.     )
  225.     {
  226.     pTcb->taskTicks    = 0;
  227.     pTcb->taskIncTicks = 0;
  228.     spyCreateCount++;
  229.     }
  230. /*******************************************************************************
  231. *
  232. * spyDeleteHook - notify spyLib of task deletion
  233. *
  234. * This routine is installed as a task delete hook so that spyReport()
  235. * can indicate when tasks disappear between reports.
  236. *
  237. * RETURNS: N/A
  238. *
  239. * ARGSUSED
  240. */
  241. LOCAL void spyDeleteHook
  242.     (
  243.     WIND_TCB *pTcb      /* WIND_TCB of new task */
  244.     )
  245.     {
  246.     spyDeleteCount++;
  247.     }
  248. /*******************************************************************************
  249. *
  250. * spyClkInt - spyLib interrupt service routine
  251. *
  252. * This routine is called at each tick of the auxiliary clock.  When at
  253. * interrupt level the interrupt tick count is incremented.  If there is no
  254. * active task then the idle tick count is incremented, otherwise increment
  255. * the active task's tick counter.
  256. *
  257. * RETURNS: N/A
  258. */
  259. LOCAL void spyClkInt (void)
  260.     {
  261.     if (intCount () > 1) /* we interrupted an interrupt */
  262. spyInterruptIncTicks++;
  263.     else if (kernelIsIdle) /* we interrupted idle state */
  264. spyIdleIncTicks++;
  265.     else if (kernelState) /* we interrupted the kernel */
  266. spyKernelIncTicks++;
  267.     else
  268. {
  269. if (taskIsReady ((int) taskIdCurrent))
  270.     taskIdCurrent->taskIncTicks++;
  271. else
  272.     logMsg ("spyClkInt: taskIdCurrent not ready.n",0,0,0,0,0,0);
  273. }
  274.     spyIncTicks++;
  275.     }
  276. /*******************************************************************************
  277. *
  278. * spyClkStartCommon - start collecting task activity data
  279. *
  280. * This routine begins data collection by enabling the auxiliary clock
  281. * interrupts at a frequency of <intsPerSec> interrupts per second.  If
  282. * <intsPerSec> is omitted or zero, the frequency will be 100.  Data from
  283. * previous collections is cleared.
  284. *
  285. * RETURNS:
  286. * OK, or ERROR if the CPU has no auxiliary clock, or if task create and
  287. * delete hooks cannot be installed.
  288. *
  289. * SEE ALSO: sysAuxClkConnect()
  290. *
  291. * NOMANUAL
  292. */
  293. STATUS spyClkStartCommon
  294.     (
  295.     int intsPerSec, /* timer interrupt freq, 0 = default of 100 */
  296.     FUNCPTR printRtn /* routine to display result */
  297.     )
  298.     {
  299.     FAST int ix;
  300.     FAST int nTasks;
  301.     FAST WIND_TCB *pTcb;
  302.     int idList [MAX_SPY_TASKS];
  303.     if (spyClkRunning)
  304. return (ERROR); /* We're already going */
  305.     if ((_func_taskCreateHookAdd != NULL) && (_func_taskDeleteHookAdd != NULL))
  306. {
  307. if (!spyInitialized &&
  308.     ((* _func_taskCreateHookAdd) ((FUNCPTR)spyCreateHook) == ERROR ||
  309.      (* _func_taskDeleteHookAdd) ((FUNCPTR)spyDeleteHook) == ERROR))
  310.     {
  311.     if (printRtn != NULL)
  312. (* printRtn) ("Unable to add create/delete hooks.n");
  313.     return (ERROR);
  314.     }
  315. }
  316.     spyInitialized = TRUE;
  317.     if (intsPerSec == 0)
  318. intsPerSec = 100;
  319.     spyDeleteCount  = 0;
  320.     spyCreateCount  = 0;
  321.     spyTotalTicks = spyIdleTicks  = spyKernelTicks    = spyInterruptTicks    =0;
  322.     spyIncTicks = spyIdleIncTicks = spyKernelIncTicks = spyInterruptIncTicks =0;
  323.     /* initialize tick counters of tasks already running */
  324.     nTasks = taskIdListGet (idList, NELEMENTS (idList));
  325.     for (ix = 0; ix < nTasks; ++ix)
  326. {
  327. pTcb = taskTcb (idList [ix]);
  328. /*
  329.  * Need to make sure pTcb is a valid pointer
  330.  */
  331. if (pTcb == NULL)
  332.     continue;
  333. pTcb->taskIncTicks = pTcb->taskTicks = 0;
  334. }
  335.     if (sysAuxClkConnect ((FUNCPTR)spyClkInt, 0) != OK)
  336. {
  337. if (printRtn != NULL)
  338.     (* printRtn) ("No auxiliary clock on CPU.n");
  339. return (ERROR);
  340. }
  341.     auxClkTicksPerSecond = sysAuxClkRateGet ();
  342.     sysAuxClkRateSet (intsPerSec);
  343.     sysAuxClkEnable ();
  344.     spyClkRunning = TRUE;
  345.     return (OK);
  346.     }
  347. /*******************************************************************************
  348. *
  349. * spyClkStopCommon - stop collecting task activity data
  350. *
  351. * This routine disables the auxiliary clock interrupts.
  352. * Data collected remains valid until the next spyClkStart() call.
  353. *
  354. * RETURNS: N/A
  355. *
  356. * SEE ALSO: spyClkStart()
  357. *
  358. * NOMANUAL
  359. */
  360. void spyClkStopCommon (void)
  361.     {
  362.     sysAuxClkRateSet (auxClkTicksPerSecond);
  363.     sysAuxClkDisable ();
  364.     spyClkRunning  = FALSE;
  365.     }
  366. /*******************************************************************************
  367. *
  368. * spyReportCommon - display task activity data
  369. *
  370. * This routine reports on data gathered at interrupt level for the amount of
  371. * CPU time utilized by each task, the amount of time spent at interrupt level,
  372. * the amount of time spent in the kernel, and the amount of idle time.  Time
  373. * is displayed in ticks and as a percentage, and the data is shown since both
  374. * the last call to spyClkStart() and the last spyReport().  If no interrupts
  375. * have occurred since the last spyReport(), nothing is displayed.
  376. *
  377. * RETURNS: N/A
  378. *
  379. * SEE ALSO: spyClkStart()
  380. *
  381. * NOMANUAL
  382. */
  383. void spyReportCommon 
  384.     (
  385.     FUNCPTR printRtn /* routine to display result */
  386.     )
  387.     {
  388.     FAST WIND_TCB *pTcb;
  389.     FAST int     ix;
  390.     SYMBOL_ID      symId;
  391.     FUNCPTR     symbolAddress = 0;
  392.     char     *name;       /* pointer to symbol table copy of string */
  393.     int     taskPriority;
  394.     char    demangled [MAX_SYS_SYM_LEN + 1];
  395.     char    *nameToPrint;
  396.     int     idList [MAX_SPY_TASKS]; /* task specific statistics */
  397.     int     taskIncTicks [MAX_SPY_TASKS];
  398.     int     taskTotalTicks [MAX_SPY_TASKS];
  399.     FAST int     nTasks;
  400.     int     tmpIncTicks; /* incremental snap shot */
  401.     int     tmpIdleIncTicks;
  402.     int     tmpKernelIncTicks;
  403.     int     tmpInterruptIncTicks;
  404.     int     totalPerCent;
  405.     int     incPerCent;
  406.     int     sumTotalPerCent = 0;
  407.     int     sumIncPerCent   = 0;
  408.     /* if there have been no ticks, there is nothing to report */
  409.     if (spyIncTicks == 0)
  410. return;
  411.     /* snap shot and clear task statistics */
  412.     nTasks = taskIdListGet (idList, NELEMENTS (idList));
  413.     spyTaskIdListSort (idList, nTasks);
  414.     for (ix = 0; ix < nTasks; ++ix)
  415. {
  416. pTcb = taskTcb (idList [ix]);
  417. /*
  418.  * Need to make sure pTcb is a valid pointer
  419.  */
  420. if (pTcb == NULL)
  421.     continue;
  422. /* order is important: save and clear incremental, then update total */
  423. taskIncTicks [ix]    = pTcb->taskIncTicks;
  424. pTcb->taskIncTicks  = 0;
  425. pTcb->taskTicks    += taskIncTicks [ix];
  426. taskTotalTicks [ix]  = pTcb->taskTicks;
  427. }
  428.     /* save and clear incremental counts and accumulate totals */
  429.     tmpIncTicks          = spyIncTicks;
  430.     tmpIdleIncTicks      = spyIdleIncTicks;
  431.     tmpKernelIncTicks    = spyKernelIncTicks;
  432.     tmpInterruptIncTicks = spyInterruptIncTicks;
  433.     spyIncTicks = spyIdleIncTicks = spyKernelIncTicks = spyInterruptIncTicks =0;
  434.     spyTotalTicks       += tmpIncTicks;
  435.     spyInterruptTicks   += tmpInterruptIncTicks;
  436.     spyKernelTicks      += tmpKernelIncTicks;
  437.     spyIdleTicks        += tmpIdleIncTicks;
  438.     if (printRtn == NULL) /* for host browser don't display result */
  439. return;
  440.     /* print info */
  441.     (* printRtn) ("n");
  442.     (* printRtn) (
  443.     "NAME          ENTRY         TID   PRI   total %% (ticks)  delta %% (ticks)n");
  444.     (* printRtn) (
  445.     "--------     --------      -----  ---   ---------------  ---------------n");
  446.     for (ix = 0; ix < nTasks; ++ix)
  447. {
  448. /* find name in symbol table */
  449. pTcb = taskTcb (idList [ix]);
  450. /*
  451.  * Need to make sure pTcb is a valid pointer
  452.  */
  453. if (pTcb == NULL)
  454.     continue;
  455.         /* 
  456.  * Only check one symLib function pointer (for performance's sake). All
  457.  * symLib functions are provided by the same library, by convention.    
  458.  */
  459. if ((_func_symFindSymbol !=(FUNCPTR) NULL) &&
  460.     (sysSymTbl != NULL))
  461.     {
  462.     if ((* _func_symFindSymbol) (sysSymTbl,  NULL, 
  463.  (void *)pTcb->entry, 
  464.  SYM_MASK_NONE, SYM_MASK_NONE, 
  465.  &symId) == OK)
  466.         {
  467. (* _func_symNameGet) (symId, &name);
  468. (* _func_symValueGet) (symId, (void **) &symbolAddress); 
  469. }
  470.     }
  471. if (symbolAddress != pTcb->entry)
  472.     name = "";          /* no matching symbol */
  473.     
  474.         taskPriorityGet (idList [ix], &taskPriority);
  475. /* print line for this task */
  476. totalPerCent     = (taskTotalTicks [ix] * 100) / spyTotalTicks;
  477. incPerCent       = (taskIncTicks [ix] * 100) / tmpIncTicks;
  478. sumTotalPerCent += totalPerCent;
  479. sumIncPerCent   += incPerCent;
  480. nameToPrint = cplusDemangle (name, demangled, sizeof (demangled));
  481. (* printRtn) (spyFmt1, pTcb->name, nameToPrint, idList [ix], 
  482.       taskPriority, totalPerCent, taskTotalTicks [ix],
  483.       incPerCent, taskIncTicks [ix]);
  484. }
  485.     totalPerCent     = (spyKernelTicks * 100) / spyTotalTicks;
  486.     incPerCent       = (tmpKernelIncTicks * 100) / tmpIncTicks;
  487.     sumTotalPerCent += totalPerCent;
  488.     sumIncPerCent   += incPerCent;
  489.     (* printRtn) (spyFmt2, "KERNEL", "", "", "", totalPerCent, spyKernelTicks,
  490.       incPerCent, tmpKernelIncTicks);
  491.     totalPerCent     = (spyInterruptTicks * 100) / spyTotalTicks;
  492.     incPerCent       = (tmpInterruptIncTicks * 100) / tmpIncTicks;
  493.     sumTotalPerCent += totalPerCent;
  494.     sumIncPerCent   += incPerCent;
  495.     (* printRtn) (spyFmt2, "INTERRUPT", "", "", "", totalPerCent, spyInterruptTicks,
  496.       incPerCent, tmpInterruptIncTicks);
  497.     totalPerCent     = (spyIdleTicks * 100) / spyTotalTicks;
  498.     incPerCent       = (tmpIdleIncTicks * 100) / tmpIncTicks;
  499.     sumTotalPerCent += totalPerCent;
  500.     sumIncPerCent   += incPerCent;
  501.     (* printRtn) (spyFmt2, "IDLE", "", "", "", totalPerCent, spyIdleTicks,
  502.  incPerCent, tmpIdleIncTicks);
  503.     (* printRtn) (spyFmt2, "TOTAL", "", "", "", sumTotalPerCent, spyTotalTicks,
  504.   sumIncPerCent, tmpIncTicks);
  505.     (* printRtn) ("n");
  506.     if (spyCreateCount > 0)
  507. {
  508. (* printRtn) ("%d task%s created.n", spyCreateCount,
  509. spyCreateCount == 1 ? " was" : "s were");
  510. spyCreateCount = 0;
  511. }
  512.     if (spyDeleteCount > 0)
  513. {
  514. (* printRtn) ("%d task%s deleted.n", spyDeleteCount,
  515. spyDeleteCount == 1 ? " was" : "s were");
  516. spyDeleteCount = 0;
  517. }
  518.     }
  519. /*******************************************************************************
  520. *
  521. * spyComTask - run periodic task activity reports
  522. *
  523. * This routine is spawned as a task by spy() to provide periodic task
  524. * activity reports.  It prints a report, delays for the specified number of
  525. * seconds, and repeats.
  526. *
  527. * RETURNS: N/A
  528. *
  529. * SEE ALSO: spy()
  530. *
  531. * NOMANUAL
  532. */
  533. void spyComTask
  534.     (
  535.     int freq, /* reporting frequency, in seconds */
  536.     FUNCPTR printRtn /* routine to display results */
  537.     )
  538.     {
  539.     int delay = freq * sysClkRateGet ();
  540.     while (TRUE)
  541. {
  542. spyReportCommon (printRtn);
  543. taskDelay (delay);
  544. }
  545.     }
  546. /*******************************************************************************
  547. *
  548. * spyStopCommon - stop spying and reporting
  549. *
  550. * This routine calls spyClkStop().  Any periodic reporting by spyTask()
  551. * is terminated.
  552. *
  553. * RETURNS: N/A
  554. *
  555. * SEE ALSO: spyClkStop(), spyTask()
  556. *
  557. * NOMANUAL
  558. */
  559. void spyStopCommon (void)
  560.     {
  561.     spyClkStopCommon ();
  562.     if (spyTaskId != ERROR)
  563. {
  564. taskDelete (spyTaskId);
  565. spyTaskId = ERROR;
  566. }
  567.     }
  568. /*******************************************************************************
  569. *
  570. * spyCommon - begin periodic task activity reports
  571. *
  572. * This routine collects task activity data and periodically runs spyReport().
  573. * Data is gathered <ticksPerSec> times per second, and a report is made every
  574. * <freq> seconds.  If <freq> is zero, it defaults to 5 seconds.  If
  575. * <ticksPerSec> is omitted or zero, it defaults to 100.
  576. *
  577. * This routine spawns spyTask() to do the actual reporting.
  578. *
  579. * It is not necessary to call spyClkStart() before running spy().
  580. *
  581. * RETURNS: N/A
  582. *
  583. * SEE ALSO: spyClkStart(), spyTask()
  584. *
  585. * NOMANUAL
  586. */
  587. void spyCommon
  588.     (
  589.     int freq, /* reporting freq in sec, 0 = default of 5 */
  590.     int ticksPerSec, /* interrupt clock freq, 0 = default of 100 */
  591.     FUNCPTR printRtn /* routine to use to display results */
  592.     )
  593.     {
  594.     if (freq == 0)
  595. freq = 5; /* default frequency is 5 secs */
  596.     if (spyClkStartCommon (ticksPerSec, printRtn) == OK)
  597. {
  598. spyTaskId = taskSpawn ("tSpyTask", spyTaskPriority,
  599.        spyTaskOptions, spyTaskStackSize,
  600.        (FUNCPTR)spyComTask, freq, (int) printRtn, 
  601.        0, 0, 0, 0, 0, 0, 0, 0);
  602. if ((spyTaskId == ERROR)&& (printRtn != NULL))
  603.     (* printRtn) ("Unable to spawn spyTask.n");
  604. }
  605.     }
  606. /*******************************************************************************
  607. *
  608. * spyTaskIdListSort - sort the ID list by priority
  609. *
  610. * This routine sorts the task ID list <idList> by task priority.
  611. *
  612. * RETURNS: N/A
  613. */
  614. LOCAL void spyTaskIdListSort
  615.     (
  616.     int idList[],
  617.     int nTasks
  618.     )
  619.     {
  620.     FAST int temp;
  621.     int prevPri;
  622.     int curPri;
  623.     FAST int *pCurId;
  624.     BOOL change = TRUE;
  625.     FAST int *pEndId = &idList [nTasks];
  626.     if (nTasks == 0)
  627.         return;
  628.     while (change)
  629.         {
  630.         change = FALSE;
  631.         taskPriorityGet (idList[0], &prevPri);
  632.         for (pCurId = &idList[1]; pCurId < pEndId; ++pCurId, prevPri = curPri)
  633.             {
  634.             taskPriorityGet (*pCurId, &curPri);
  635.             if (prevPri > curPri)
  636.                 {
  637.                 temp = *pCurId;
  638.                 *pCurId = *(pCurId - 1);
  639.                 *(pCurId - 1) = temp;
  640.                 change = TRUE;
  641.                 }
  642.             }
  643.         }
  644.     }