profile.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. profile.c
  9. Abstract:
  10. This module implements the system profiler application.
  11. Author:
  12. Chris Stevens 18-Jan-2015
  13. Environment:
  14. User Mode
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/lib/minocaos.h>
  20. #include <minoca/kernel/sp.h>
  21. #include <minoca/lib/mlibc.h>
  22. #include <assert.h>
  23. #include <errno.h>
  24. #include <getopt.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <unistd.h>
  29. //
  30. // --------------------------------------------------------------------- Macros
  31. //
  32. #define PRINT_ERROR(...) fprintf(stderr, "\nprofile: " __VA_ARGS__)
  33. //
  34. // ---------------------------------------------------------------- Definitions
  35. //
  36. #define PROFILE_VERSION_MAJOR 1
  37. #define PROFILE_VERSION_MINOR 0
  38. #define PROFILE_USAGE \
  39. "usage: profile [-d <type>] [-e <type>]\n\n" \
  40. "The profile utility enables, disables or gets system profiling state.\n\n"\
  41. "Options:\n" \
  42. " -d, --disable <type> -- Disable a system profiler. Valid values are \n" \
  43. " stack, memory, thread, and all.\n" \
  44. " -e, --enable <type> -- Enable a system profiler. Valid values are \n" \
  45. " stack, memory, thread, all.\n" \
  46. " --help -- Display this help text.\n" \
  47. " --version -- Display the application version and exit.\n\n"
  48. #define PROFILE_OPTIONS_STRING "e:d:Vh"
  49. #define PROFILE_TYPE_COUNT 4
  50. //
  51. // ------------------------------------------------------ Data Type Definitions
  52. //
  53. /*++
  54. Structure Description:
  55. This structure defines the information for a given profile type option.
  56. Members:
  57. Name - Stores the command line name for the profile type option.
  58. TypeFlags - Stores bitmask of type flags for the system profilers that
  59. correspond to the name. See PROFILER_TYPE_FLAG_* for definitions.
  60. --*/
  61. typedef struct _PROFILE_TYPE_DATA {
  62. PSTR Name;
  63. ULONG TypeFlags;
  64. } PROFILE_TYPE_DATA, *PPROFILE_TYPE_DATA;
  65. //
  66. // ----------------------------------------------- Internal Function Prototypes
  67. //
  68. //
  69. // -------------------------------------------------------------------- Globals
  70. //
  71. struct option ProfileLongOptions[] = {
  72. {"disable", required_argument, 0, 'd'},
  73. {"enable", required_argument, 0, 'e'},
  74. {"help", no_argument, 0, 'h'},
  75. {"version", no_argument, 0, 'V'},
  76. {NULL, 0, 0, 0},
  77. };
  78. PROFILE_TYPE_DATA ProfileTypeData[PROFILE_TYPE_COUNT] = {
  79. {
  80. "all",
  81. PROFILER_TYPE_FLAG_STACK_SAMPLING |
  82. PROFILER_TYPE_FLAG_MEMORY_STATISTICS |
  83. PROFILER_TYPE_FLAG_THREAD_STATISTICS
  84. },
  85. {
  86. "stack",
  87. PROFILER_TYPE_FLAG_STACK_SAMPLING
  88. },
  89. {
  90. "memory",
  91. PROFILER_TYPE_FLAG_MEMORY_STATISTICS
  92. },
  93. {
  94. "thread",
  95. PROFILER_TYPE_FLAG_THREAD_STATISTICS
  96. },
  97. };
  98. //
  99. // ------------------------------------------------------------------ Functions
  100. //
  101. int
  102. main (
  103. int ArgumentCount,
  104. char **Arguments
  105. )
  106. /*++
  107. Routine Description:
  108. This routine implements the kernel test program.
  109. Arguments:
  110. ArgumentCount - Supplies the number of elements in the arguments array.
  111. Arguments - Supplies an array of strings. The array count is bounded by the
  112. previous parameter, and the strings are null-terminated.
  113. Return Value:
  114. 0 on success.
  115. Non-zero on failure.
  116. --*/
  117. {
  118. ULONG DisableFlags;
  119. ULONG EnableFlags;
  120. ULONG Index;
  121. INT Option;
  122. INT ReturnValue;
  123. UINTN Size;
  124. SP_GET_SET_STATE_INFORMATION StateInformation;
  125. KSTATUS Status;
  126. DisableFlags = 0;
  127. EnableFlags = 0;
  128. ReturnValue = 0;
  129. //
  130. // Process the control arguments.
  131. //
  132. while (TRUE) {
  133. Option = getopt_long(ArgumentCount,
  134. Arguments,
  135. PROFILE_OPTIONS_STRING,
  136. ProfileLongOptions,
  137. NULL);
  138. if (Option == -1) {
  139. break;
  140. }
  141. if ((Option == '?') || (Option == ':')) {
  142. ReturnValue = 1;
  143. goto MainEnd;
  144. }
  145. switch (Option) {
  146. case 'd':
  147. for (Index = 0; Index < PROFILE_TYPE_COUNT; Index += 1) {
  148. if (strcasecmp(optarg, ProfileTypeData[Index].Name) == 0) {
  149. DisableFlags = ProfileTypeData[Index].TypeFlags;
  150. break;
  151. }
  152. }
  153. if (Index == PROFILE_TYPE_COUNT) {
  154. PRINT_ERROR("Invalid profiling type: %s\n", optarg);
  155. ReturnValue = 1;
  156. goto MainEnd;
  157. }
  158. break;
  159. case 'e':
  160. for (Index = 0; Index < PROFILE_TYPE_COUNT; Index += 1) {
  161. if (strcasecmp(optarg, ProfileTypeData[Index].Name) == 0) {
  162. EnableFlags = ProfileTypeData[Index].TypeFlags;
  163. break;
  164. }
  165. }
  166. if (Index == PROFILE_TYPE_COUNT) {
  167. PRINT_ERROR("Invalid profiling type: %s\n", optarg);
  168. ReturnValue = 1;
  169. goto MainEnd;
  170. }
  171. break;
  172. case 'V':
  173. printf("profile version %d.%02d\n",
  174. PROFILE_VERSION_MAJOR,
  175. PROFILE_VERSION_MINOR);
  176. ReturnValue = 1;
  177. goto MainEnd;
  178. case 'h':
  179. printf(PROFILE_USAGE);
  180. return 1;
  181. default:
  182. assert(FALSE);
  183. ReturnValue = 1;
  184. goto MainEnd;
  185. }
  186. }
  187. //
  188. // If there is nothing to enable or disable, then just get and print the
  189. // status.
  190. //
  191. if ((EnableFlags == 0) && (DisableFlags == 0)) {
  192. Size = sizeof(SP_GET_SET_STATE_INFORMATION);
  193. RtlZeroMemory(&StateInformation, Size);
  194. Status = OsGetSetSystemInformation(SystemInformationSp,
  195. SpInformationGetSetState,
  196. &StateInformation,
  197. &Size,
  198. FALSE);
  199. if (!KSUCCESS(Status)) {
  200. ReturnValue = ClConvertKstatusToErrorNumber(Status);
  201. PRINT_ERROR("Failed to get profiling information: %s.\n",
  202. strerror(ReturnValue));
  203. goto MainEnd;
  204. }
  205. if (Size < sizeof(SP_GET_SET_STATE_INFORMATION)) {
  206. Status = STATUS_DATA_LENGTH_MISMATCH;
  207. ReturnValue = ClConvertKstatusToErrorNumber(Status);
  208. PRINT_ERROR("Failed to get profiling information: %s.\n",
  209. strerror(ReturnValue));
  210. goto MainEnd;
  211. }
  212. for (Index = 1; Index < PROFILE_TYPE_COUNT; Index += 1) {
  213. if ((StateInformation.ProfilerTypeFlags &
  214. ProfileTypeData[Index].TypeFlags) != 0) {
  215. printf("%s - enabled\n", ProfileTypeData[Index].Name);
  216. } else {
  217. printf("%s - disabled\n", ProfileTypeData[Index].Name);
  218. }
  219. }
  220. //
  221. // Disable and enable the profiler types specified, unless they are equal.
  222. //
  223. } else if (DisableFlags != EnableFlags) {
  224. //
  225. // Don't disable anything that is about to be enabled.
  226. //
  227. DisableFlags &= ~EnableFlags;
  228. if (DisableFlags != 0) {
  229. Size = sizeof(SP_GET_SET_STATE_INFORMATION);
  230. StateInformation.Operation = SpGetSetStateOperationDisable;
  231. StateInformation.ProfilerTypeFlags = DisableFlags;
  232. Status = OsGetSetSystemInformation(SystemInformationSp,
  233. SpInformationGetSetState,
  234. &StateInformation,
  235. &Size,
  236. TRUE);
  237. if (!KSUCCESS(Status)) {
  238. ReturnValue = ClConvertKstatusToErrorNumber(Status);
  239. PRINT_ERROR("Failed to disable profiling information: %s.\n",
  240. strerror(ReturnValue));
  241. goto MainEnd;
  242. }
  243. }
  244. if (EnableFlags != 0) {
  245. Size = sizeof(SP_GET_SET_STATE_INFORMATION);
  246. StateInformation.Operation = SpGetSetStateOperationEnable;
  247. StateInformation.ProfilerTypeFlags = EnableFlags;
  248. Status = OsGetSetSystemInformation(SystemInformationSp,
  249. SpInformationGetSetState,
  250. &StateInformation,
  251. &Size,
  252. TRUE);
  253. if (!KSUCCESS(Status)) {
  254. ReturnValue = ClConvertKstatusToErrorNumber(Status);
  255. PRINT_ERROR("Failed to enable profiling information: %s.\n",
  256. strerror(ReturnValue));
  257. goto MainEnd;
  258. }
  259. }
  260. //
  261. // Tell the user that no action was taken.
  262. //
  263. } else {
  264. printf("Attempt to enable and disable the same profiling types "
  265. "ignored.\n");
  266. }
  267. MainEnd:
  268. return ReturnValue;
  269. }