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