1 /* TimeWin.cpp --- A simple Windows tool inspired by Unix' "time".
2  *
3  * ====================================================================
4  *    Licensed to the Apache Software Foundation (ASF) under one
5  *    or more contributor license agreements.  See the NOTICE file
6  *    distributed with this work for additional information
7  *    regarding copyright ownership.  The ASF licenses this file
8  *    to you under the Apache License, Version 2.0 (the
9  *    "License"); you may not use this file except in compliance
10  *    with the License.  You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  *    Unless required by applicable law or agreed to in writing,
15  *    software distributed under the License is distributed on an
16  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  *    KIND, either express or implied.  See the License for the
18  *    specific language governing permissions and limitations
19  *    under the License.
20  * ====================================================================
21  */
22 
23 #include "targetver.h"
24 
25 #include <Windows.h>
26 
27 #include <stdio.h>
28 #include <tchar.h>
29 
usage()30 void usage()
31 {
32   _tprintf(_T("Execute a command, redirect its stdout to NUL and print\n"));
33   _tprintf(_T("execution times ELAPSED\\tUSER\\tKERNEL in seconds.\n"));
34   _tprintf(_T("\n"));
35   _tprintf(_T("Usage: TimeWin.EXE COMMAND [PARAMETERS]\n"));
36 }
37 
skip_first_arg(LPCTSTR targv)38 LPCTSTR skip_first_arg(LPCTSTR targv)
39 {
40   LPCTSTR s = _tcschr(targv, ' ');
41   while (s && *s == ' ')
42     ++s;
43 
44   return s;
45 }
46 
as_seconds(FILETIME time)47 double as_seconds(FILETIME time)
48 {
49   return (double)*reinterpret_cast<LONGLONG *>(&time) / 10000000.0;
50 }
51 
_tmain(int argc,LPTSTR argv[])52 int _tmain(int argc, LPTSTR argv[])
53 {
54   // Minimal CL help support
55   if (argc < 2 || _tcscmp(argv[1], _T("/?")) == 0)
56     {
57       usage();
58       return 0;
59     }
60 
61   // Get a file handle for NUL.
62   SECURITY_ATTRIBUTES sa;
63   sa.nLength = sizeof(sa);
64   sa.lpSecurityDescriptor = NULL;
65   sa.bInheritHandle = TRUE;
66 
67   HANDLE nul = CreateFile(_T("nul"), FILE_APPEND_DATA, FILE_SHARE_WRITE,
68                           &sa, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
69 
70   // Construct a process startup info that uses the same handles as this
71   // one but redirects stdout to NUL.
72   STARTUPINFO startup_info;
73   GetStartupInfo(&startup_info);
74   startup_info.dwFlags |= STARTF_USESTDHANDLES;
75   startup_info.hStdOutput = nul;
76 
77   // Execute the command line.
78   PROCESS_INFORMATION process_info;
79   CreateProcess(NULL, _tscdup(skip_first_arg(GetCommandLine())), NULL, NULL,
80                 TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &startup_info,
81                 &process_info);
82 
83   // Get a handle with the needed access rights to the child process.
84   HANDLE child = INVALID_HANDLE_VALUE;
85   DuplicateHandle(GetCurrentProcess(), process_info.hProcess,
86                   GetCurrentProcess(), &child,
87                   PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, 0);
88 
89   // Wait for the child to finish.
90   // If there was problem earlier (application not found etc.), this will fail.
91   bool success = false;
92   if (WaitForSingleObject(child, INFINITE) == WAIT_OBJECT_0)
93     {
94       // Finally, query the timers and show the result
95       FILETIME start_time, end_time, user_time, kernel_time;
96       if (GetProcessTimes(child, &start_time, &end_time, &kernel_time,
97                           &user_time))
98         {
99           _tprintf(_T("%1.3f\t%1.3f\t%1.3f\n"),
100                    as_seconds(end_time) - as_seconds(start_time),
101                    as_seconds(user_time), as_seconds(kernel_time));
102           success = true;
103         }
104     }
105 
106   // In case of failure, give some indication that something went wrong.
107   if (!success)
108     _tprintf(_T("?.???\t?.???f\t?.???\n"),
109 
110   // Be good citizens and clean up our mess
111   CloseHandle(child);
112   CloseHandle(process_info.hThread);
113   CloseHandle(process_info.hProcess);
114 
115   CloseHandle(nul);
116 
117   return 0;
118 }
119