/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // /////////////////////////////////////////////////////////////////////////////// using System; using System.Diagnostics; using System.Text; using Windows; namespace timerun { class timerun { static int Main(string[] args) { try { if (args.Length < 1) { Usage(); return 1; } string program = args[0]; string arguments = String.Join(" ", args, 1, args.Length - 1); IntPtr job_handle = Kernel32.CreateJobObject(); if (job_handle == IntPtr.Zero) { WriteLine("WARNING: Failed to create job object; cannot gather CPU usage info."); } using (Process process = new Process()) { process.StartInfo.UseShellExecute = false; process.StartInfo.Arguments = arguments; process.StartInfo.FileName = program; DateTime timeStarted = DateTime.Now; process.Start(); if (job_handle != IntPtr.Zero) { if (!Kernel32.AssignProcessToJobObject(job_handle, process.Handle)) { WriteLine("WARNING: Failed to assign child process to job."); WriteLine("The process may have already terminated."); } } process.WaitForExit(); DateTime timeEnded = DateTime.Now; TimeSpan elapsed = timeEnded - timeStarted; const string times_format = " {0,-32} : {1}"; if (job_handle != IntPtr.Zero) { try { JOBOBJECT_BASIC_ACCOUNTING_INFORMATION job_info; job_info = Kernel32.QueryJobObjectBasicAccountingInformation(job_handle); TimeSpan total_job_time = job_info.TotalUserTime + job_info.TotalKernelTime; WriteLine( times_format, "CPU time consumed by jobs", total_job_time); WriteLine( times_format, " in user mode", job_info.TotalUserTime); WriteLine( times_format, " in kernel mode", job_info.TotalKernelTime); WriteLine( times_format, "Elapsed time (wall time)", elapsed); WriteLine(""); if (elapsed.TotalMilliseconds > 0) { double elapsed_ms = elapsed.TotalMilliseconds; double total_job_ms = total_job_time.TotalMilliseconds; double throughput_ratio = total_job_ms / elapsed_ms; double throughput_percent = Math.Round(throughput_ratio * 100.0); WriteLine(" Parallel throughput ratio: {0}%", throughput_percent); } else { WriteLine(" Too little time elapsed to compute ratio."); } } catch (Exception ex) { WriteLine("FAILED to query job info!"); ShowException(ex); } } else { WriteLine(" Child process times not available."); } return process.ExitCode; } } catch (Exception ex) { ShowException(ex); return 1; } } static void WriteLine(string line) { Console.WriteLine(Prefix + line); } static void WriteLine(string format, params object[] args) { WriteLine(String.Format(format, args)); } const string Prefix = "TIMERUN: "; static void Usage() { Console.WriteLine("Usage: TIMERUN program args ..."); Console.WriteLine(); Console.WriteLine(" TIMERUN runs a program, then displays CPU usage information for the program"); Console.WriteLine(" and all of its child processes."); } static void ShowException(Exception chain) { for (Exception ex = chain; ex != null; ex = ex.InnerException) { Console.WriteLine(ex.GetType().FullName + ": " + ex.Message); } } } }