static async Task Main(string[] args) { RuntimeHelper.PrintConfiguration(); int numTasks = int.Parse(args[0]); TimeSpan sleepDelay = TimeSpan.FromSeconds(double.Parse(args[1])); long maxHits = long.Parse(args[2]); // NB: This sets the "start time" of the first scoreboard message. var scoreboard = new Scoreboard(); // Warning: This fires off a ton of tasks and they will start doing work // while we are still constructing other tasks. This is non-deterministic // and in theory produces "thundering herds". Isn't benchmarking // parallel code fun? // // However, we are not as concerned with wall-clock time as we are about // measuring total memory usage and CPU time. // // But you probably don't want to run this test with a sleepDelay // too low and completely saturate your CPU cores, and thus starve // this creation loop. You should verify that the first scoreboard message // shows a reasonable "elapsed" time. // for (var i = 0; i < numTasks; i++) { // Note: We used to add this to a list, but that is not necessary. // Note: We assign to a variable just to supress a compiler warning // that we aren't using await here. #if USE_TASK_RUN_LAMBDA // Warning: Task.Run() with a lambda closure adds mem/cpu overhead // (+10% CPU, +20% memory on a short 10 second test) var task = Task.Run(() => WorkTask(scoreboard, sleepDelay)); #else var task = WorkTask(scoreboard, sleepDelay); #endif } await scoreboard.PollScores(maxHits); }
public async Task PollScores(long maxHits) { while (true) { DateTime currentTime = DateTime.UtcNow; TimeSpan elapsed = currentTime - lastDumpTime; long totalHits = Interlocked.Read(ref hitCount); Console.WriteLine($"elapsed={elapsed} totalHits={totalHits}"); RuntimeHelper.PrintMemoryInfo(); lastDumpTime = currentTime; if (totalHits >= maxHits) { Environment.Exit(0); } // Sleep for 1/10 of a second to keep precision reasonable await Task.Delay(TimeSpan.FromSeconds(0.1)); } }