diff --git a/tsc/internal/execute/tsc/statistics.go b/tsc/internal/execute/tsc/statistics.go index ce2ac6d5d4bdc..0ad1a3bb08c8d 100644 --- a/tsc/internal/execute/tsc/statistics.go +++ b/tsc/internal/execute/tsc/statistics.go @@ -10,6 +10,7 @@ import ( "time" "github.com/microsoft/TypeScript/tsc/internal/compiler" + "github.com/microsoft/TypeScript/tsc/internal/osutil" ) type tableRow struct { @@ -125,6 +126,9 @@ func (s *Statistics) Report(w io.Writer, testing CommandLineTesting) { table.add(prefix+"Changes compute time", s.compileTimes.ChangesComputeTime) } s.addContentMapperStatistics(&table, prefix) + if cpuTime, err := osutil.ProcessCPUTime(); err == nil { + table.add("CPU time", cpuTime) + } table.add(prefix+"Total time", s.compileTimes.totalTime) table.print(w) } diff --git a/tsc/internal/osutil/cputime_other.go b/tsc/internal/osutil/cputime_other.go new file mode 100644 index 0000000000000..3b09c61fc3d67 --- /dev/null +++ b/tsc/internal/osutil/cputime_other.go @@ -0,0 +1,12 @@ +//go:build !unix && !windows + +package osutil + +import ( + "errors" + "time" +) + +func processCPUTime() (time.Duration, error) { + return 0, errors.ErrUnsupported +} diff --git a/tsc/internal/osutil/cputime_unix.go b/tsc/internal/osutil/cputime_unix.go new file mode 100644 index 0000000000000..ec9d3eb57bb16 --- /dev/null +++ b/tsc/internal/osutil/cputime_unix.go @@ -0,0 +1,17 @@ +//go:build unix + +package osutil + +import ( + "time" + + "golang.org/x/sys/unix" +) + +func processCPUTime() (time.Duration, error) { + var usage unix.Rusage + if err := unix.Getrusage(unix.RUSAGE_SELF, &usage); err != nil { + return 0, err + } + return time.Duration(usage.Utime.Nano()) + time.Duration(usage.Stime.Nano()), nil +} diff --git a/tsc/internal/osutil/cputime_windows.go b/tsc/internal/osutil/cputime_windows.go new file mode 100644 index 0000000000000..b25d84f897b8d --- /dev/null +++ b/tsc/internal/osutil/cputime_windows.go @@ -0,0 +1,17 @@ +package osutil + +import ( + "time" + + "golang.org/x/sys/windows" +) + +func processCPUTime() (time.Duration, error) { + var creation, exit, kernel, user windows.Filetime + if err := windows.GetProcessTimes(windows.CurrentProcess(), &creation, &exit, &kernel, &user); err != nil { + return 0, err + } + kernelTicks := uint64(kernel.HighDateTime)<<32 | uint64(kernel.LowDateTime) + userTicks := uint64(user.HighDateTime)<<32 | uint64(user.LowDateTime) + return time.Duration(kernelTicks+userTicks) * 100 * time.Nanosecond, nil +} diff --git a/tsc/internal/osutil/osutil.go b/tsc/internal/osutil/osutil.go index ed6bc22edd697..16d5d49972be9 100644 --- a/tsc/internal/osutil/osutil.go +++ b/tsc/internal/osutil/osutil.go @@ -1,5 +1,7 @@ package osutil +import "time" + // Args returns the command-line arguments with platform-specific launcher details removed. func Args() []string { return args() @@ -9,3 +11,9 @@ func Args() []string { func Executable() (string, error) { return executable() } + +// ProcessCPUTime returns cumulative user and system CPU time across all threads +// of the current process, excluding child processes. +func ProcessCPUTime() (time.Duration, error) { + return processCPUTime() +}