perfsup.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*++
  2. Copyright (c) 2015 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. perfsup.c
  5. Abstract:
  6. This module implements the helper routines for all performance benchmark
  7. tests.
  8. Author:
  9. Chris Stevens 5-May-2015
  10. Environment:
  11. User
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <errno.h>
  17. #include <signal.h>
  18. #include <string.h>
  19. #include <unistd.h>
  20. #include <sys/resource.h>
  21. #include "perftest.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. void
  32. PtAlarmSignalHandler (
  33. int Signal
  34. );
  35. //
  36. // -------------------------------------------------------------------- Globals
  37. //
  38. //
  39. // Store a value indicating whether ot not a test is running.
  40. //
  41. int PtTestRunning;
  42. //
  43. // Store the original alarm signal handler action.
  44. //
  45. struct sigaction PtAlarmOriginalAction;
  46. //
  47. // Store a value indicating whether or not the resource usage is in use.
  48. //
  49. int PtResourceUsageBusy;
  50. //
  51. // Store the starting resource usage.
  52. //
  53. PT_TEST_RESOURCE_USAGE PtStartResourceUsage;
  54. //
  55. // ------------------------------------------------------------------ Functions
  56. //
  57. int
  58. PtStartTimedTest (
  59. time_t Duration
  60. )
  61. /*++
  62. Routine Description:
  63. This routine starts a timed performance test. It will collect initial
  64. resource usage and then set an alarm to stop the test after the given
  65. duration. Only one test can run at a time for each process.
  66. Arguments:
  67. Duration - Supplies the desired duration of the test, in seconds.
  68. Return Value:
  69. 0 on success.
  70. -1 on error, and the errno variable will contain more information.
  71. --*/
  72. {
  73. struct sigaction NewAction;
  74. unsigned int PreviousAlarm;
  75. int Status;
  76. //
  77. // Only one test can be running at a given time within one process.
  78. //
  79. if (PtTestRunning != 0) {
  80. errno = EBUSY;
  81. return -1;
  82. }
  83. //
  84. // Set the alarm to modify the test running variable after the duration.
  85. //
  86. memset(&NewAction, 0, sizeof(struct sigaction));
  87. NewAction.sa_handler = PtAlarmSignalHandler;
  88. Status = sigaction(SIGALRM, &NewAction, &PtAlarmOriginalAction);
  89. if (Status != 0) {
  90. return Status;
  91. }
  92. //
  93. // Start collecting the resource usage before the alarm is set.
  94. //
  95. Status = PtCollectResourceUsageStart();
  96. if (Status != 0) {
  97. goto StartTimedTestEnd;
  98. }
  99. //
  100. // Set the alarm to stop the test after the given number of seconds.
  101. //
  102. PtTestRunning = 1;
  103. Status = 0;
  104. errno = 0;
  105. PreviousAlarm = alarm((unsigned int)Duration);
  106. if (PreviousAlarm != 0) {
  107. errno = EBUSY;
  108. Status = -1;
  109. } else if (errno != 0) {
  110. Status = -1;
  111. }
  112. StartTimedTestEnd:
  113. //
  114. // Set the original alarm action back if the test failed to start.
  115. //
  116. if (Status != 0) {
  117. PtTestRunning = 0;
  118. sigaction(SIGALRM, &PtAlarmOriginalAction, NULL);
  119. }
  120. return Status;
  121. }
  122. int
  123. PtFinishTimedTest (
  124. PPT_TEST_RESULT Result
  125. )
  126. /*++
  127. Routine Description:
  128. This routine finalizes a running test that has stopped. It will collect the
  129. final usage statistics and set them in the given result. It makes sure that
  130. the alarm is disabled and stops the test.
  131. Arguments:
  132. Result - Supplies a pointer to the test result that will receive the test's
  133. resource usage, including child resources.
  134. Return Value:
  135. 0 on success.
  136. -1 on error, and the errno variable will contain more information.
  137. --*/
  138. {
  139. int Status;
  140. //
  141. // Stop collecting the resource usage.
  142. //
  143. Status = PtCollectResourceUsageStop(Result);
  144. //
  145. // Always disable the timer and restore the original action.
  146. //
  147. alarm(0);
  148. sigaction(SIGALRM, &PtAlarmOriginalAction, NULL);
  149. PtTestRunning = 0;
  150. return Status;
  151. }
  152. int
  153. PtIsTimedTestRunning (
  154. void
  155. )
  156. /*++
  157. Routine Description:
  158. This routine determines whether or not a timed test is running.
  159. Arguments:
  160. None.
  161. Return Value:
  162. 1 if a test is currently running, or 0 otherwise.
  163. --*/
  164. {
  165. return PtTestRunning;
  166. }
  167. int
  168. PtCollectResourceUsageStart (
  169. void
  170. )
  171. /*++
  172. Routine Description:
  173. This routine starts collecting resource usage by taking a snapshot of the
  174. current process's usage and the usage of any children it has waited on.
  175. Arguments:
  176. None.
  177. Return Value:
  178. 0 on success.
  179. -1 on error, and the errno variable will contain more information.
  180. --*/
  181. {
  182. struct rusage ChildrenUsage;
  183. struct rusage SelfUsage;
  184. int Status;
  185. if (PtResourceUsageBusy != 0) {
  186. errno = EBUSY;
  187. return -1;
  188. }
  189. //
  190. // Get the real time first to make sure the user and system times are
  191. // always less than the real time.
  192. //
  193. Status = gettimeofday(&(PtStartResourceUsage.RealTime), NULL);
  194. if (Status != 0) {
  195. return Status;
  196. }
  197. Status = getrusage(RUSAGE_CHILDREN, &ChildrenUsage);
  198. if (Status != 0) {
  199. return Status;
  200. }
  201. Status = getrusage(RUSAGE_SELF, &SelfUsage);
  202. if (Status != 0) {
  203. return Status;
  204. }
  205. timeradd(&(SelfUsage.ru_utime),
  206. &(ChildrenUsage.ru_utime),
  207. &(PtStartResourceUsage.UserTime));
  208. timeradd(&(SelfUsage.ru_stime),
  209. &(ChildrenUsage.ru_stime),
  210. &(PtStartResourceUsage.SystemTime));
  211. PtResourceUsageBusy = 1;
  212. return 0;
  213. }
  214. int
  215. PtCollectResourceUsageStop (
  216. PPT_TEST_RESULT Result
  217. )
  218. /*++
  219. Routine Description:
  220. This routine stops collecting resource usage data for the current test and
  221. fills result with the test's resource usage stats.
  222. Arguments:
  223. Result - Supplies a pointer to the test result that will receive the test's
  224. resource usage, including child resources.
  225. Return Value:
  226. 0 on success.
  227. -1 on error, and the errno variable will contain more information.
  228. --*/
  229. {
  230. struct rusage ChildrenUsage;
  231. struct rusage EndUsage;
  232. struct timeval RealTime;
  233. struct rusage SelfUsage;
  234. int Status;
  235. if (PtResourceUsageBusy == 0) {
  236. errno = EINVAL;
  237. return -1;
  238. }
  239. PtResourceUsageBusy = 0;
  240. //
  241. // Measure the tests resource usage and store it in the result.
  242. //
  243. Status = getrusage(RUSAGE_SELF, &SelfUsage);
  244. if (Status != 0) {
  245. return Status;
  246. }
  247. Status = getrusage(RUSAGE_CHILDREN, &ChildrenUsage);
  248. if (Status != 0) {
  249. return Status;
  250. }
  251. //
  252. // Get the real time after collecting the usage times, so that the user and
  253. // system times are always a percentage of the real time.
  254. //
  255. Status = gettimeofday(&RealTime, NULL);
  256. if (Status != 0) {
  257. return Status;
  258. }
  259. timeradd(&(SelfUsage.ru_utime),
  260. &(ChildrenUsage.ru_utime),
  261. &(EndUsage.ru_utime));
  262. timeradd(&(SelfUsage.ru_stime),
  263. &(ChildrenUsage.ru_stime),
  264. &(EndUsage.ru_stime));
  265. timersub(&(EndUsage.ru_utime),
  266. &(PtStartResourceUsage.UserTime),
  267. &(Result->ResourceUsage.UserTime));
  268. timersub(&(EndUsage.ru_stime),
  269. &(PtStartResourceUsage.SystemTime),
  270. &(Result->ResourceUsage.SystemTime));
  271. timersub(&RealTime,
  272. &(PtStartResourceUsage.RealTime),
  273. &(Result->ResourceUsage.RealTime));
  274. Result->ResourceUsageValid = 1;
  275. return 0;
  276. }
  277. //
  278. // --------------------------------------------------------- Internal Functions
  279. //
  280. void
  281. PtAlarmSignalHandler (
  282. int Signal
  283. )
  284. /*++
  285. Routine Description:
  286. This routine is called when a signal fires. If it is the alarm signal, then
  287. it will mark the performance test timer as expired.
  288. Arguments:
  289. Signal - Supplies the signal that fired.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. if (Signal == SIGALRM) {
  295. PtTestRunning = 0;
  296. }
  297. return;
  298. }