             <<< DECWET::DOCD$:[NOTES$LIBRARY]WINDOWS-NT.NOTE;1 >>>
                                -< Windows NT >-
================================================================================
Note 5232.1                     time command ???                          1 of 1
TIGNES::HOBBS "Congrats to the Ignoble Peace Prize" 289 lines  31-OCT-1996 01:36
     -< SPAWN.C - UNIX 'time'-like program for measuring CPU time of sin >-
--------------------------------------------------------------------------------
            <<< DECWET::DOCD$:[NOTES$LIBRARY]NT-DEVELOPERS.NOTE;1 >>>
                         -< MS Windows NT Developers >-
================================================================================
Note 1483.4            equivalent of UNIX 'time' command?                 4 of 7
CERN::HOBBS "Digital Joint Project - CERN"           16 lines   5-DEC-1993 05:55
                       -< if in doubt, roll your own... >-
--------------------------------------------------------------------------------
The next reply is a little program called SPAWN.  You can call it like
the UNIX 'time' command, and it will return user/kernel/total CPU times,
and the start/stop/elapsed times.

It seems to work for me from an MSDOS command window, and is good enough
for the suite I need to run.

Unfortunately, it only works for a single image.  If you run it with a
script, or a driver like 'claxp' or 'f77' you don't see the processes that
do the work, just the driver.

-cw

ps:  suggestions will probably be cheerfully ignored.  this is my first
win32 program....

================================================================================
Note 1483.5            equivalent of UNIX 'time' command?                 5 of 7
CERN::HOBBS "Digital Joint Project - CERN"          255 lines   5-DEC-1993 05:59
-< SPAWN.C - UNIX 'time'-like program for measuring CPU time of single images >-
--------------------------------------------------------------------------------
/**************************************************************************\
*
*  spawn.c
*
*	This program executes a command in another process, and displays
*	the CPU time used by the command.
*
\**************************************************************************/

#include <windows.h>
#include <stdio.h>
#include <io.h>
#include <time.h>


/**************************************************************************\
*
*  function:		main(argc, argv)
*
*  input parameters:	command line to execute
*
\**************************************************************************/
void main(int argc, char *argv[])
{
    double		 tTotal, tKernel, tUser;
    char		 buffer [512];
    char		 *CommandLine;
    int			 stdout_fileno, put_to_stderr;

    DWORD		 ret, dwExitCode;
    FILE		 *logfile;
    FILETIME		 ftKernel, ftUser, ftCreate, ftExit, ftLocal;
    PROCESS_INFORMATION  pi;
    STARTUPINFO          sui;
    SYSTEMTIME		 stCreate, stExit, stElapsed;
    time_t		 time_value;


    /* If the 'stdout' has been redirected to a file (via a '>'
     * on the command line), echo time information to 'stderr'.
     */
    put_to_stderr = FALSE;
    stdout_fileno = _fileno(stdout);
    if (_isatty(stdout_fileno)==0) put_to_stderr = TRUE;


    /* Open a logfile for append access
     */
    logfile = fopen ("spawn.log", "a");
    if (logfile == NULL){
      sprintf(buffer, "%%SPAWN  failed to open logfile");
      fprintf (stdout, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }

    /* Get the original command line for the application.
     * Remove the first token (which will be our name) by
     * finding the first space and bumping the pointer over
     * it.
     *		[This is pretty lame - it should allow more flexible
     *		 command syntax, and probably UNICODE as well...]
     */
    CommandLine = GetCommandLine();
    CommandLine = strchr(CommandLine, ' ');
    if (CommandLine == NULL){
      sprintf(buffer, "%%SPAWN  no command on line");
      fprintf (stdout,  "%s\n", buffer);
      fprintf (logfile, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }
    CommandLine = CommandLine + 1;


    /* Print the command line and start time.  Note that the 'ctime'
     * function puts a newline "\n" in the buffer...
     */
    time_value = time(NULL);
    sprintf (buffer, "%%SPAWN  command line '%s',  date  %s",
	CommandLine, ctime(&time_value));
    fprintf (stdout,  "\n%s", buffer);
    fprintf (logfile, "\n%s", buffer);
    if (put_to_stderr) fprintf (stderr, "\n%s", buffer);


    /* Set up a blank STARTUPINFO structure.
     */
    sui.cb               = sizeof (STARTUPINFO);
    sui.lpReserved       = 0;
    sui.lpDesktop        = NULL;
    sui.lpTitle          = NULL;
    sui.dwX              = 0;
    sui.dwY              = 0;
    sui.dwXSize          = 0;
    sui.dwYSize          = 0;
    sui.dwXCountChars    = 0;
    sui.dwYCountChars    = 0;
    sui.dwFillAttribute  = 0;
    sui.dwFlags          = 0;
    sui.wShowWindow      = 0;
    sui.cbReserved2      = 0;
    sui.lpReserved2      = 0;


    /* Create the process.
     */
    ret = CreateProcess (NULL, CommandLine, NULL, NULL,
                   TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &sui, &pi );
    if (ret != TRUE){
      /* report failure to the user. */
      ret = GetLastError ();
      sprintf (buffer,
	"%%SPAWN  create process failed, status0x%lx", (int)ret);
      fprintf (stdout,  "%s\n", buffer);
      fprintf (logfile, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }


    /* Print the process ID of the created process
     */
    sprintf (buffer, "%%SPAWN  created process %08lx", (LONG) pi.dwProcessId);
    fprintf (stdout,  "%s\n", buffer);
    fprintf (logfile, "%s\n", buffer);
    if (put_to_stderr) fprintf (stderr, "%s\n", buffer);


    /* Wait for the process handle to signal (part of process termination)
     */
    ret = WaitForSingleObject (pi.hProcess, INFINITE);
    if (ret == WAIT_FAILED){
      ret = GetLastError ();
      sprintf (buffer,
	"%%SPAWN  WaitForSingleObject failed, status 0x%lx", (int)ret);
      fprintf (stdout,  "%s\n", buffer);
      fprintf (logfile, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }


    /* Get timing statistics for process
     */
    ret = GetProcessTimes (pi.hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser);
    if (ret != TRUE){
      ret = GetLastError ();
      sprintf (buffer,
	"%%SPAWN  GetProcessTimes failed, status 0x%lx", (int)ret);
      fprintf (stdout,  "%s\n", buffer);
      fprintf (logfile, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }


    /* Get exit code for process
     */
    ret = GetExitCodeProcess (pi.hProcess, &dwExitCode);
    if (ret != TRUE){
      ret = GetLastError ();
      sprintf (buffer,
	"%%SPAWN  GetExitCodeProcess failed, status 0x%lx", (int)ret);
      fprintf (stdout,  "%s\n", buffer);
      fprintf (logfile, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }
    if (dwExitCode != 0){
      sprintf (buffer,
	"%%SPAWN  abnormal process exit status 0x%lx", (int)dwExitCode);
      fprintf (stdout,  "%s\n", buffer);
      fprintf (logfile, "%s\n", buffer);
      if (put_to_stderr) fprintf (stderr, "%s\n", buffer);
      return;
    }

    /* Process times are returned in a 64-bit structure, as the number of
     * 100 nanosecond ticks since 1 January 1601.  User mode and kernel mode
     * times for this process are in separate 64-bit structures.
     * To convert to floating point seconds, we will:
     *
     *		Convert high 32-bit quantities to 64-bit float
     *		Multiply by 2**32 to scale
     *		Add low 32-bit tick counts
     *		Divide by 10,000,000 to convert to seconds
     */
    tUser   = ftUser.dwHighDateTime;
    tUser   = tUser * 4294967296.0;
    tUser   = tUser + ftUser.dwLowDateTime;
    tUser   = tUser * 1.0E-7;

    tKernel = ftKernel.dwHighDateTime;
    tKernel = tKernel * 4294967296.0;
    tKernel = tKernel + ftKernel.dwLowDateTime;
    tKernel = tKernel * 1.0E-7;

    tTotal = tUser + tKernel;


    /* To get start/end/elapsed times, use the system times.  We convert
     * the file time to local file time, then to system time format.  We then
     * subtract Create from Exit to get elapsed (manually checking for carry). 
     * Milliseconds are then converted to centiseconds.
     */
    FileTimeToLocalFileTime(&ftCreate, &ftLocal);
    FileTimeToSystemTime(&ftLocal,     &stCreate);
    FileTimeToLocalFileTime(&ftExit,   &ftLocal);
    FileTimeToSystemTime(&ftLocal,     &stExit);

    stElapsed.wHour         = stExit.wHour         - stCreate.wHour;
    stElapsed.wMinute       = stExit.wMinute       - stCreate.wMinute;
    stElapsed.wSecond       = stExit.wSecond       - stCreate.wSecond;
    stElapsed.wMilliseconds = stExit.wMilliseconds - stCreate.wMilliseconds;

    if ((short) stElapsed.wMilliseconds < 0){
      stElapsed.wSecond       = stElapsed.wSecond - 1;
      stElapsed.wMilliseconds = stElapsed.wMilliseconds + 1000;
    }

    if ((short) stElapsed.wSecond < 0){
      stElapsed.wMinute       = stElapsed.wMinute - 1;
      stElapsed.wSecond       = stElapsed.wSecond + 60;
    }

    if ((short) stElapsed.wMinute < 0){
      stElapsed.wHour         = stElapsed.wHour   - 1;
      stElapsed.wMinute       = stElapsed.wMinute + 60;
    }

    stCreate.wMilliseconds  = (stCreate.wMilliseconds+5)  / 10;
    stExit.wMilliseconds    = (stExit.wMilliseconds+5)    / 10;
    stElapsed.wMilliseconds = (stElapsed.wMilliseconds+5) / 10;

    /* Print the start/end/elapsed times.
     */
    sprintf (buffer,
	"%%SPAWN  start time %02d:%02d:%02d.%02d  exit time %02d:%02d:%02d.%02d 
elapsed %02d:%02d:%02d.%02d",
		 stCreate.wHour,  stCreate.wMinute,  stCreate.wSecond, 
stCreate.wMilliseconds,
		   stExit.wHour,    stExit.wMinute,    stExit.wSecond,   
stExit.wMilliseconds,
		stElapsed.wHour, stElapsed.wMinute, stElapsed.wSecond,
stElapsed.wMilliseconds);
    fprintf (stdout,  "\n%s\n", buffer);
    fprintf (logfile, "%s\n",   buffer);
    if (put_to_stderr) fprintf (stderr, "\n%s\n", buffer);


    /* Print the CPU times.
     */
    sprintf (buffer, "%%SPAWN  user CPU       %7.2f  kernel CPU   %8.2f  total
CPU %9.2f",
	tUser, tKernel, tTotal);
    fprintf (stdout,  "%s\n", buffer);
    fprintf (logfile, "%s\n", buffer);
    if (put_to_stderr) fprintf (stderr, "%s\n", buffer);

}
