aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/elastic/gosigar/sys/windows/ntquery.go')
-rw-r--r--vendor/github.com/elastic/gosigar/sys/windows/ntquery.go132
1 files changed, 132 insertions, 0 deletions
diff --git a/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go b/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go
new file mode 100644
index 000000000..85de365e1
--- /dev/null
+++ b/vendor/github.com/elastic/gosigar/sys/windows/ntquery.go
@@ -0,0 +1,132 @@
+// +build windows
+
+package windows
+
+import (
+ "bytes"
+ "encoding/binary"
+ "io"
+ "runtime"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/pkg/errors"
+)
+
+// On both 32-bit and 64-bit systems NtQuerySystemInformation expects the
+// size of SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION to be 48.
+const sizeofSystemProcessorPerformanceInformation = 48
+
+// ProcessBasicInformation is an equivalent representation of
+// PROCESS_BASIC_INFORMATION in the Windows API.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx
+type ProcessBasicInformation struct {
+ ExitStatus uint
+ PebBaseAddress uintptr
+ AffinityMask uint
+ BasePriority uint
+ UniqueProcessID uint
+ InheritedFromUniqueProcessID uint
+}
+
+// NtQueryProcessBasicInformation queries basic information about the process
+// associated with the given handle (provided by OpenProcess). It uses the
+// NtQueryInformationProcess function to collect the data.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx
+func NtQueryProcessBasicInformation(handle syscall.Handle) (ProcessBasicInformation, error) {
+ var processBasicInfo ProcessBasicInformation
+ processBasicInfoPtr := (*byte)(unsafe.Pointer(&processBasicInfo))
+ size := uint32(unsafe.Sizeof(processBasicInfo))
+ ntStatus, _ := _NtQueryInformationProcess(handle, 0, processBasicInfoPtr, size, nil)
+ if ntStatus != 0 {
+ return ProcessBasicInformation{}, errors.Errorf("NtQueryInformationProcess failed, NTSTATUS=0x%X", ntStatus)
+ }
+
+ return processBasicInfo, nil
+}
+
+// SystemProcessorPerformanceInformation contains CPU performance information
+// for a single CPU.
+type SystemProcessorPerformanceInformation struct {
+ IdleTime time.Duration // Amount of time spent idle.
+ KernelTime time.Duration // Kernel time does NOT include time spent in idle.
+ UserTime time.Duration // Amount of time spent executing in user mode.
+}
+
+// _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION is an equivalent representation of
+// SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION in the Windows API. This struct is
+// used internally with NtQuerySystemInformation call and is not exported. The
+// exported equivalent is SystemProcessorPerformanceInformation.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
+type _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION struct {
+ IdleTime int64
+ KernelTime int64
+ UserTime int64
+ Reserved1 [2]int64
+ Reserved2 uint32
+}
+
+// NtQuerySystemProcessorPerformanceInformation queries CPU performance
+// information for each CPU. It uses the NtQuerySystemInformation function to
+// collect the SystemProcessorPerformanceInformation.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
+func NtQuerySystemProcessorPerformanceInformation() ([]SystemProcessorPerformanceInformation, error) {
+ // NTSTATUS code for success.
+ // https://msdn.microsoft.com/en-us/library/cc704588.aspx
+ const STATUS_SUCCESS = 0
+
+ // From the _SYSTEM_INFORMATION_CLASS enum.
+ // http://processhacker.sourceforge.net/doc/ntexapi_8h.html#ad5d815b48e8f4da1ef2eb7a2f18a54e0
+ const systemProcessorPerformanceInformation = 8
+
+ // Create a buffer large enough to hold an entry for each processor.
+ b := make([]byte, runtime.NumCPU()*sizeofSystemProcessorPerformanceInformation)
+
+ // Query the performance information. Note that this function uses 0 to
+ // indicate success. Most other Windows functions use non-zero for success.
+ var returnLength uint32
+ ntStatus, _ := _NtQuerySystemInformation(systemProcessorPerformanceInformation, &b[0], uint32(len(b)), &returnLength)
+ if ntStatus != STATUS_SUCCESS {
+ return nil, errors.Errorf("NtQuerySystemInformation failed, NTSTATUS=0x%X, bufLength=%v, returnLength=%v", ntStatus, len(b), returnLength)
+ }
+
+ return readSystemProcessorPerformanceInformationBuffer(b)
+}
+
+// readSystemProcessorPerformanceInformationBuffer reads from a buffer
+// containing SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION data. The buffer should
+// contain one entry for each CPU.
+// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724509(v=vs.85).aspx
+func readSystemProcessorPerformanceInformationBuffer(b []byte) ([]SystemProcessorPerformanceInformation, error) {
+ n := len(b) / sizeofSystemProcessorPerformanceInformation
+ r := bytes.NewReader(b)
+
+ rtn := make([]SystemProcessorPerformanceInformation, 0, n)
+ for i := 0; i < n; i++ {
+ _, err := r.Seek(int64(i*sizeofSystemProcessorPerformanceInformation), io.SeekStart)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to seek to cpuN=%v in buffer", i)
+ }
+
+ times := make([]uint64, 3)
+ for j := range times {
+ err := binary.Read(r, binary.LittleEndian, &times[j])
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed reading cpu times for cpuN=%v", i)
+ }
+ }
+
+ idleTime := time.Duration(times[0] * 100)
+ kernelTime := time.Duration(times[1] * 100)
+ userTime := time.Duration(times[2] * 100)
+
+ rtn = append(rtn, SystemProcessorPerformanceInformation{
+ IdleTime: idleTime,
+ KernelTime: kernelTime - idleTime, // Subtract out idle time from kernel time.
+ UserTime: userTime,
+ })
+ }
+
+ return rtn, nil
+}