public PerfStat this[string key] { get { PerfStat counter; if (_stats.TryGetValue(key, out counter) == false) { counter = new PerfStat(key); _stats[key] = counter; } return counter; } }
static int Main(string[] args) { Console.Error.WriteLine(); Console.Error.WriteLine(string.Format("{0} - Command Line Profiler", Name)); Console.Error.WriteLine("Mark Gillard, 2016 | [email protected] | marzersoft.com"); Console.Error.WriteLine(); string exe = "", exeArgs = "", desc = ""; bool csv = false; //parse arguments { ArgData value = null, key = null; for (int i = 0; i < args.Length; i++) { key = value ?? new ArgData(args[i]); value = i < args.Length - 1 ? new ArgData(args[i + 1]) : null; if (!key.IsFlag || key.Handled) continue; //single-token flags if (key.Handled = (key.Value == "?")) { Console.Error.WriteLine(Help); return 0; } else if (key.Handled = (key.Value == "csv")) csv = true; //key-value pairs else if (value != null && !value.IsFlag) { if (key.Handled = value.Handled = (key.Value == "exe")) exe = value.Value; else if (key.Handled = value.Handled = (key.Value == "args")) exeArgs = value.Value; else if (key.Handled = value.Handled = (key.Value == "desc")) desc = value.Value.Replace(',',' ').Replace('\t',' ').Trim(); } } } //check exe if (exe.Length == 0) { Console.Error.WriteLine("No executable specified"); Console.Error.WriteLine(); Console.Error.WriteLine(Usage); return 1; } if (!Path.HasExtension(exe)) exe += ".exe"; if (!File.Exists(exe)) { Console.Error.WriteLine("Specified executable {0} could not be found", exe); Console.Error.WriteLine(); Console.Error.WriteLine(Usage); return 2; } //set up performance counter PerformanceCounter cpuCounter = new PerformanceCounter( "Processor", "% Processor Time", "_Total", true ); double totalRam = (new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory / (1024ul * 1024ul)); PerformanceCounter ramCounter = new PerformanceCounter("Memory", "Available MBytes", true); //execute command if (!csv) { Console.Out.WriteLine("Executing {0}", desc.Length == 0 ? "process" : "\"" + desc + "\""); Console.Out.WriteLine("({0} {1})", exe, exeArgs); Console.Out.WriteLine("----"); } Timer timer = new Timer(); double executionTime = 0.0; Process proc = null; try { proc = Process.Start(new ProcessStartInfo() { CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true, WindowStyle = ProcessWindowStyle.Hidden, FileName = Path.GetFullPath(exe), Arguments = exeArgs }); } catch (Exception e) { Console.Error.WriteLine("{0} thrown while launching executable ({1})", e.GetType().Name, e.Message); return 3; } proc.Exited += (sender, e) => { executionTime = timer.Stopwatch; }; //spawn process monitoring thread Thread monitor; List<PerfNode> perfNodes = new List<PerfNode>(); (monitor = new Thread(() => { proc.Refresh(); while (!proc.HasExited) { perfNodes.Add(new PerfNode(proc, ramCounter, cpuCounter)); Thread.Sleep(125); proc.Refresh(); } }) { Priority = ThreadPriority.AboveNormal }).Start(); //spawn io redirection threads Thread stderr = null, stdout = null; (stdout = new Thread(() => { if (csv) //redirect stdout to stderr to avoid polluting csv output Console.Error.Write(proc.StandardOutput.ReadToEnd()); else Console.Out.Write(proc.StandardOutput.ReadToEnd()); proc.WaitForExit(); }) { Priority = ThreadPriority.BelowNormal }).Start(); (stderr = new Thread(() => { Console.Error.Write(proc.StandardError.ReadToEnd()); proc.WaitForExit(); }) { Priority = ThreadPriority.BelowNormal }).Start(); //wait for threads to finish stdout.Join(); stderr.Join(); monitor.Join(); //report execution stats if (csv) { Console.Out.Write("{0}", desc.Length == 0 ? Path.GetFileName(exe) : desc); Console.Out.Write(",\t{0}", executionTime); Console.Out.Write(",\t{0}", totalRam); } else { Console.Out.WriteLine("----"); Console.Out.WriteLine("Child process finished."); Console.Out.WriteLine("Time taken: {0} s", executionTime); Console.Out.WriteLine("Samples recorded: {0}", perfNodes.Count); Console.Out.WriteLine("Total System Memory: {0} Mb", totalRam); } //report individual metrics PerfStat processRam = new PerfStat("Process Memory Usage"); PerfStat systemRam = new PerfStat("System Memory Usage"); PerfStat systemCpu = new PerfStat("System CPU Percentage"); foreach (PerfNode node in perfNodes) { processRam.Add(node.PrivateMemory); systemRam.Add(totalRam - node.SystemMemory); systemCpu.Add(node.CpuPercentage); } if (csv) { Console.Out.Write(",\t{0}", processRam.ToCSV("0.00", 1.0 / (1024.0 * 1024.0))); Console.Out.Write(",\t{0}", systemRam.ToCSV("0.00", 1.0)); Console.Out.Write(",\t{0}", systemCpu.ToCSV("0.00")); } else { Console.Out.WriteLine(processRam.ToString(" Mb", "0.00", 1.0 / (1024.0 * 1024.0), totalRam)); Console.Out.WriteLine(systemRam.ToString(" Mb", "0.00", 1.0, totalRam)); Console.Out.WriteLine(systemCpu.ToString(" %", "0.00")); Console.Out.WriteLine(""); } return 0; }