PageRenderTime 44ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/base/Applications/Tests/MemStress/MemStress.cs

#
C# | 384 lines | 225 code | 68 blank | 91 comment | 34 complexity | d674f8524e80726fb6b28806197283dd MD5 | raw file
  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Microsoft Research Singularity
  4. //
  5. // Copyright (c) Microsoft Corporation. All rights reserved.
  6. //
  7. // Note: Perform short (bvt) and long running stress of OutOfMemory
  8. // behavior of the system.
  9. //
  10. //
  11. // Tests to support:
  12. //
  13. // - Overcommit of heap memory within a SIP
  14. //
  15. // Create lots of managed array objects until the OS can no
  16. // longer satisfy the request and terminates the SIP.
  17. //
  18. //
  19. // - Overcommit of stack memory within a SIP
  20. //
  21. // Implement a recursive function that results in stack overflow
  22. // and termination of the SIP.
  23. //
  24. // - Overcommit of heap memory within the kernel
  25. //
  26. // Since we can't directly allocate kernel heap memory,
  27. // we do this by creating lots of kernel objects that occupy
  28. // the heap (such as new threads)
  29. //
  30. // - Overcommit kernel heap memory from within the kernel in multiple
  31. // threads to find races in any resource reservation strategies that
  32. // may be timing dependent.
  33. //
  34. using System;
  35. using System.Threading;
  36. using Microsoft.Contracts;
  37. using Microsoft.SingSharp.Reflection;
  38. using Microsoft.Singularity.UnitTest;
  39. using Microsoft.Singularity.V1.Services;
  40. using Microsoft.Singularity.Channels;
  41. using Microsoft.Singularity.Directory;
  42. using Microsoft.Singularity.Applications;
  43. using Microsoft.Singularity.Io;
  44. using Microsoft.Singularity.Configuration;
  45. [assembly: Transform(typeof(ApplicationResourceTransform))]
  46. namespace Microsoft.Singularity.Applications
  47. {
  48. [ConsoleCategory(DefaultAction=true)]
  49. internal class Parameters {
  50. [InputEndpoint("data")]
  51. public readonly TRef<UnicodePipeContract.Exp:READY> Stdin;
  52. [OutputEndpoint("data")]
  53. public readonly TRef<UnicodePipeContract.Imp:READY> Stdout;
  54. [Endpoint]
  55. public readonly TRef<DirectoryServiceContract.Imp:Start> nsRef;
  56. [BoolParameter( "sip_so", Default=false, HelpMessage="Create Stack Overflow in SIP")]
  57. internal bool sipSo;
  58. [BoolParameter( "sip_oom", Default=false, HelpMessage="Create Out Of Memory in SIP")]
  59. internal bool sipOom;
  60. [BoolParameter( "kernel_oom", Default=false, HelpMessage="Create Kernel Out Of Memory")]
  61. internal bool kernelOom;
  62. [BoolParameter( "kernel_oom_stress", Default=false, HelpMessage="Create Kernel Out Of Memory Stress")]
  63. internal bool kernelOomStress;
  64. //
  65. // The noProcess parameter runs the test without creating a sub-process.
  66. //
  67. // Since success for this test is running out of memory and having the SIP
  68. // die, there is no way to return a success status to a top level test script.
  69. // The script thinks that the SIP failure due to OOM is a failure of the test.
  70. //
  71. // So by default, the tests are run in a sub-process which we can then monitor
  72. // and return a proper result to the top level test script.
  73. //
  74. // This parameter allows the same executable to be used for both parts
  75. // of the test.
  76. //
  77. [BoolParameter( "noprocess", Default=false, HelpMessage="Run directly without a sub-process")]
  78. internal bool noProcess;
  79. reflective internal Parameters();
  80. internal int AppMain() {
  81. return MemStress.AppMain(this);
  82. }
  83. }
  84. public class MemStress
  85. {
  86. internal static int AppMain(Parameters! config)
  87. {
  88. #if PAGING
  89. if (true) {
  90. Console.WriteLine("MemStress does not work on PAGING builds");
  91. return -1;
  92. }
  93. #endif
  94. DumpMemInfo();
  95. SipMemoryStresser sipms = new SipMemoryStresser();
  96. if (!config.noProcess) {
  97. if (config.sipSo) {
  98. sipms.RunTestAsProcess(config, "-sip_so");
  99. }
  100. else if (config.sipOom) {
  101. sipms.RunTestAsProcess(config, "-sip_oom");
  102. }
  103. else if (config.kernelOom) {
  104. sipms.RunTestAsProcess(config, "-kernel_oom");
  105. }
  106. else if (config.kernelOomStress) {
  107. sipms.RunTestAsProcess(config, "-kernel_oom_stress");
  108. }
  109. else {
  110. Console.WriteLine("Usage: MemStress [-sip_oom] [-sip_so] [-kernel_oom] [-kernel_oom_stress]");
  111. Console.WriteLine("Must pick one option");
  112. }
  113. }
  114. else {
  115. if (config.sipSo) {
  116. sipms.RunSOTest();
  117. }
  118. else if (config.sipOom) {
  119. sipms.RunOOMTest();
  120. }
  121. else if (config.kernelOom) {
  122. sipms.KernelOOMTest();
  123. }
  124. else if (config.kernelOomStress) {
  125. sipms.KernelOOMStress();
  126. }
  127. else {
  128. Console.WriteLine("Usage: MemStress [-sip_oom] [-sip_so] [-kernel_oom] [-kernel_oom_stress]");
  129. Console.WriteLine("Must pick one option");
  130. }
  131. }
  132. return 0;
  133. }
  134. public static void DumpMemInfo()
  135. {
  136. int result;
  137. ulong totalMemoryFree = 0;
  138. ulong totalMemoryInUse = 0;
  139. ulong kernelHeapInUse = 0;
  140. ulong kernelStackInUse = 0;
  141. ulong totalSIPHeapInUse = 0;
  142. ulong totalSIPStackInUse = 0;
  143. ulong kernelStackReservation = 0;
  144. ulong kernelHeapReservation = 0;
  145. result = MemoryInfoService.MemoryUsageInfo(
  146. out totalMemoryFree,
  147. out totalMemoryInUse,
  148. out kernelHeapInUse,
  149. out kernelStackInUse,
  150. out totalSIPHeapInUse,
  151. out totalSIPStackInUse,
  152. out kernelStackReservation,
  153. out kernelHeapReservation
  154. );
  155. // TODO: Use standard ErrorCode's
  156. if (result != 0) {
  157. Console.WriteLine("Error {0} retrieving MemoryUsageInfo");
  158. }
  159. else {
  160. Console.WriteLine("TotalMemoryFree 0x{0:x8}, TotalMemoryInUse {1:x8}", totalMemoryFree, totalMemoryInUse);
  161. Console.WriteLine("KernelHeapInUse {0:x8}, KernelStackInUse {1:x8}", kernelHeapInUse, kernelStackInUse);
  162. Console.WriteLine("TotalSIPHeapInUse {0:x8}, TotalSIPStackInUse {1:x8}", totalSIPHeapInUse, totalSIPStackInUse);
  163. Console.WriteLine("KernelStackReservation {0:x8}, KernelHeapReservation {1:x8}", kernelStackReservation, kernelHeapReservation);
  164. Console.WriteLine("");
  165. }
  166. }
  167. }
  168. public class SipMemoryStresser
  169. {
  170. //
  171. // Run out of memory test, eventually terminates the SIP due
  172. // to fail fast.
  173. //
  174. internal void RunTestAsProcess(Parameters! config, string test) {
  175. Process p = null;
  176. //
  177. // Create a subprocess run of "memstress -testparameter"
  178. //
  179. string[] args = new string[3];
  180. args[0] = "memstress";
  181. args[1] = test;
  182. args[2] = "-noprocess";
  183. Console.WriteLine("Creating subprocess memstress {0} -noprocess", test);
  184. try {
  185. p = ProcessLauncher.CreateSubProcess(config, args);
  186. }
  187. catch (Exception e) {
  188. Console.WriteLine("Exception from CreateSubProcess: " + e.Message);
  189. return;
  190. }
  191. if (p == null) {
  192. Console.WriteLine("Error creating process");
  193. return;
  194. }
  195. Console.WriteLine("Process returned with ExitCode={0}", p.ExitCode);
  196. }
  197. public void RunOOMTest() {
  198. object[] TopLevel;
  199. object[] tmp;
  200. TopLevel = new Object[1];
  201. //
  202. // Currrently the test handles the OOM exception showing
  203. // that this works. Additional testing should create multiple
  204. // threads and have OOM failures at random places in the runtime
  205. // without try/except handlers so we can test the case when
  206. // the exception bubbles up to the top of the stack.
  207. //
  208. try {
  209. for (int count = 65535;; count *= 2) {
  210. tmp = new object[count];
  211. tmp[0] = TopLevel;
  212. TopLevel = tmp;
  213. for (int i = 1; i < count; i++) {
  214. TopLevel[i] = new object[count];
  215. }
  216. MemStress.DumpMemInfo();
  217. }
  218. }
  219. catch (OutOfMemoryException e) {
  220. e=e;
  221. //Thread.CurrentProcess.Stop(1);
  222. return;
  223. }
  224. }
  225. // Run stack overflow test, terminates the SIP
  226. public void RunSOTest() {
  227. // Test the fail fast path directly
  228. //Microsoft.Singularity.V1.Services.StackService.StackOverflow();
  229. RunSOTest();
  230. }
  231. //
  232. // Invoke a kernel heap out of memory condition by creating
  233. // lots of kernel objects
  234. //
  235. public void KernelOOMTest() {
  236. IdleThread[] threads;
  237. int threadCount = 1000;
  238. while (true) {
  239. System.Console.WriteLine("Creating {0} threads", threadCount);
  240. threads = new IdleThread[threadCount];
  241. if (threads == null) {
  242. System.Console.WriteLine("Error allocating Thread[]");
  243. return;
  244. }
  245. for (int i = 0; i < threadCount; i++) {
  246. threads[i] = new IdleThread(i);
  247. if (threads[i] == null) {
  248. System.Console.WriteLine("Error creating thread");
  249. return;
  250. }
  251. }
  252. // Start them running
  253. for (int i = 0; i < threadCount; i++) {
  254. ((!)threads[i]).RunThread();
  255. }
  256. }
  257. }
  258. //
  259. // Use multiple threads to stress the system and induce
  260. // kernel heap OOM to test the ability for the system
  261. // to remain running.
  262. //
  263. public void KernelOOMStress() {
  264. Console.WriteLine("Not implemented yet");
  265. return;
  266. }
  267. }
  268. // Generic class that creates the thread
  269. public class ThreadRunner
  270. {
  271. private Thread thread;
  272. public ThreadRunner() {
  273. }
  274. public Thread Thread {
  275. get {
  276. return thread;
  277. }
  278. }
  279. // Creates thread, returns with it running
  280. public Thread RunThread() {
  281. thread = new Thread(new ThreadStart(ThreadMain));
  282. thread.Start();
  283. return thread;
  284. }
  285. public virtual void ThreadMain() {
  286. // This exits the thread
  287. return;
  288. }
  289. }
  290. //
  291. // Implementation classes represent different thread creation
  292. // parameters, and actions
  293. //
  294. //
  295. // This creates an idle thread that just waits.
  296. //
  297. // The goal is to create lots of kernel objects and use up
  298. // memory, not jam the system with many threads until
  299. // it stalls.
  300. //
  301. public class IdleThread : ThreadRunner
  302. {
  303. private long argValue;
  304. public IdleThread(long arg) : base() {
  305. argValue = arg;
  306. }
  307. public override void ThreadMain() {
  308. // Wait for ever
  309. while (true) {
  310. Thread.Sleep(60*60*1000);
  311. }
  312. // This exits the thread
  313. return;
  314. }
  315. }
  316. }