home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0010 - 0019 / ibm0010-0019 / ibm0010.tar / ibm0010 / CLIPB52.ZIP / YELLICK.ZIP / PROFILER.PRG < prev   
Encoding:
Text File  |  1990-06-05  |  6.4 KB  |  219 lines

  1. *===============================================================*
  2. *
  3. *  Profiler.Prg:  A General-Purpose Profiler Shell
  4. *
  5. *        Author:  Craig Yellick, Alto Microcomputer, Inc.
  6. *                 7107 Ohms Lane, Minneapolis, Minnesota 55435
  7. *                 Voice (612) 835-1080; CIS 76247,541
  8. *
  9. *       Version:  2.0  *  5-June-90  *  DevCon
  10. *
  11. *          Note:  Uses Clipper 5.0-specific syntax, will not
  12. *                 operate as-is under Summer '87.  However,
  13. *                 the code could be modified if needed.
  14. *
  15. *---------------------------------------------------------------*
  16. *
  17. *  No copyrights, no restrictions, no nothin'.
  18. *
  19. *---------------------------------------------------------------*
  20. *
  21. *  What is a profiler?  A profiler is a programmer utility that
  22. *  collects information about an application while it is
  23. *  running.  This is different from utilities that analyze an
  24. *  application's source code, linker "maps" or other static
  25. *  information.  A profiler "watches" your application as it
  26. *  runs, recording information that will be useful to you for
  27. *  debugging or optimizing.  Profilers can be programmed to
  28. *  record memory usage, overlay management statistics, timing
  29. *  and speed, disk access or whatever information you need.
  30. *
  31. *  In this program I present a general purpose profiler shell
  32. *  that you can use as is, or better yet, modify to fit your
  33. *  particular needs.  This example profiler makes use of
  34. *  the MEMORY(0) function to give you a very crude estimate
  35. *  of the amount of memory available.
  36. *
  37. *  I strongly urge you to add support for other kinds of
  38. *  run-time information.  For example, I use a memory-usage
  39. *  based profiler to help track down functions that fragment
  40. *  memory or allocate large chunks of memory and don't let go.
  41. *  I use a variation to track execution speed, looking for
  42. *  likely candidates for optimization.  Still another variation
  43. *  logs the end-user's progress as they operate the
  44. *  application, giving me insight into how the application is
  45. *  really being used (or abused!) by my customers.
  46. *
  47. *---------------------------------------------------------------*
  48. *
  49. *  Overview:  This particular profiler is designed to create
  50. *  and update a text file containing useful information
  51. *  collected while your application is running.
  52. *
  53. *  It supports two ways to collect information:
  54. *
  55. *     1)  Via calls to PROFILE() in your source code.
  56. *
  57. *     2)  Via a hot-key invoked while your application
  58. *         is in a wait-state.  Insert the following line
  59. *         early in your application source code:
  60. *
  61. *         set key <n> to PrfKey  // <n> = inkey() value
  62. *
  63. *===============================================================*
  64.  
  65. function PrfKey
  66. *
  67. *  Target function for calling Profiler via SET KEY TO.
  68. *
  69. parameters procName, procLine, readVar
  70.  
  71. return Profile("*HOTKEY", procName, procLine, readVar)
  72.  
  73. * end func PrfKey
  74. *---------------------------------------------------------------*
  75.  
  76. function Profile
  77. *
  78. *  The main profiler function.
  79. *
  80. *  The COMMENT parameter may be specified in a direct call to
  81. *  PROFILE() in source code or from a call via hot-key.  Unless
  82. *  the call is via a hot-key, the PROCNAME, PROCLINE and
  83. *  READVAR parameters will not be automatically included.
  84. *  However, if desired, direct calls to PROFILE() may
  85. *  include the PROCNAME(), READVAR() and PROCLINE() functions,
  86. *  or other data of the same type that you find useful.
  87. *
  88. *  Examples of Direct Calls:
  89. *
  90. *    Profile("Start of main loop")
  91. *    Profile("Iteration: " +str(i))
  92. *    Profile("Exiting loop", procname(), procline(), readvar())
  93. *    Profile("Exiting loop", VENDOR->Name, VENDOR->(recno()))
  94. *
  95. *  See PRODEMO.PRG for an example of how to make calling
  96. *  the PROFILE() function easier and cleaner with a
  97. *  preprocessor #DEFINE command.
  98. *
  99. *  For debugging purposes, PROFILE() returns one of the
  100. *  following exit status codes.
  101. *
  102. *       0  No errors
  103. *       1  Could not open
  104. *       2  Could not create
  105. *       3  Could not write
  106. *
  107.  
  108. parameter comment, procName, procLine, readVar
  109.  
  110.  
  111. ***  If first call, flag that we've been here
  112. *
  113. static prf_init := .t.
  114. if prf_init
  115.  
  116.   ***  Open existing or create new output file.
  117.   *
  118.   *   (NOTE:  Un-comment the lines if you
  119.   *    want the profiler to APPEND to existing
  120.   *    files rather than always OVER-WRITING.
  121.   *
  122.   public prf_handle
  123.   * if .not. file("PROFILER.TXT")
  124.     prf_handle= fcreate("PROFILER.TXT", 0)
  125.     if ferror() <> 0
  126.       return 2
  127.     endif
  128.   * else
  129.   *  prf_handle= fopen("PROFILER.TXT", 2)
  130.   *  if ferror() <> 0
  131.   *    return 1
  132.   *  endif
  133.   * endif
  134.  
  135.  
  136.   ***  One cursory check for an error, we'll
  137.   *    assume if one write worked, they all will.
  138.   *
  139.   if .not. PrfOut("", .t.)
  140.     return 3
  141.   endif
  142.  
  143.  
  144.   ***  Put a descriptive label in the output file,
  145.   *    showing what it is and the date and time started.
  146.   *
  147.   PrfOut("--- SAMPLE PROFILER ---  " +dtoc(date()) +"  " +time(), .t.)
  148.   PrfOut("", .t.)
  149.  
  150.   ***  Output a full set of column headings
  151.   *
  152.   *                        Insert more column headings, here!
  153.   *                      \/
  154.   PrfOut("Time     Mem-0   Proc-Name  Line# Read-Var    Comment", .t.)
  155.   PrfOut("-------- ------  ---------- ----- ----------  -------", .t.)
  156.  
  157. endif  // our first time through this function
  158.  
  159. prf_init= .f.
  160.  
  161. ***  Fix up any missing parameters
  162. *
  163. if type("comment") = "U"
  164.   comment= ""
  165. endif
  166. if type("procName") = "U"
  167.   procName= ""
  168. endif
  169. if type("procLine") = "U"
  170.   procLine= 0
  171. endif
  172. if type("readVar") = "U"
  173.   readVar= ""
  174. endif
  175.  
  176.  
  177. ***  Finally, we're ready to output a line.
  178. *
  179. PrfOut(time())
  180. PrfOut(str(memory(0),   7))
  181. *
  182. *  Insert more calls to PrfOut() to track
  183. *  things you are interested in.
  184. *
  185. PrfOut("  " +left(procName +space(10), 10))
  186. PrfOut(str(procLine,6))
  187. PrfOut(" " +left(readVar +space(10), 10))
  188. PrfOut("  " +comment, .t.)
  189.  
  190. return 0
  191.  
  192. * end func Profile
  193. *---------------------------------------------------------------*
  194.  
  195. function PrfOut
  196. *
  197. *  Output a line of text to the profiler file.
  198. *  Optionally appends a CR+LF to end of line.
  199. *  Returns error status.
  200. *
  201. *  Note:  Assumes PRF_HANDLE is public, as defined
  202. *         in PROFILE().
  203. *
  204. parameter s, crlf
  205.  
  206. if pcount() < 2
  207.   crlf= .f.
  208. endif
  209.  
  210. fseek(prf_handle, 0, 2)  // Move to EOF
  211.  
  212. fwrite(prf_handle, s +iif(crlf, chr(13) +chr(10), ""))
  213.  
  214. return (ferror() = 0)
  215.  
  216. * end func PrfOut
  217. *===============================================================*
  218. * eof Profiler.Prg
  219.