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