From dd2b43ba526144e8e22ab0e58319179c951ccd4c Mon Sep 17 00:00:00 2001 From: elfrucool Date: Thu, 29 Sep 2022 01:21:50 -0500 Subject: [PATCH 1/5] [issue-1357] fix by calling NtQuerySystemInformation --- internal/procstats/procstats_windows.go | 219 ++++++++++++++++++++++++ load/load_windows.go | 16 +- 2 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 internal/procstats/procstats_windows.go diff --git a/internal/procstats/procstats_windows.go b/internal/procstats/procstats_windows.go new file mode 100644 index 000000000..7d080d446 --- /dev/null +++ b/internal/procstats/procstats_windows.go @@ -0,0 +1,219 @@ +//go:build windows +// +build windows + +package procstats + +import ( + "unsafe" + + "github.com/shirou/gopsutil/v3/internal/common" + "golang.org/x/sys/windows" +) + +// represents a win32 thread status +// see for possible values +type THREAD_STATE uint32 + +const ( + StateInitialized THREAD_STATE = iota + StateReady + StateRunning + StateStandby + StateTerminated + StateWait + StateTransition + StateUnknown +) + +func (s THREAD_STATE) String() string { + switch s { + case StateInitialized: + return "StateInitialized" + case StateReady: + return "StateReady" + case StateRunning: + return "StateRunning" + case StateStandby: + return "StateStandby" + case StateTerminated: + return "StateTerminated" + case StateWait: + return "StateWait" + case StateTransition: + return "StateTransition" + case StateUnknown: + return "StateUnknown" + default: + return "" + } +} + +// "BUSY" thread means a thread that is either running, transitioning to run or on a state that demans resources +// see https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html +func (s THREAD_STATE) Busy() bool { + switch s { + case StateReady, StateRunning, StateStandby, StateTransition: + return true + default: + return false + } +} + +// SYSTEM_THREAD_INFORMATION contains thread information as it is returned by NtQuerySystemInformation() API call +// look for its structure & documentation at: +// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation +type SYSTEM_THREAD_INFORMATION struct { + Reserved1 [3]int64 + Reserved2 uint32 + StartAddress uintptr + UniqueProcess windows.Handle + UniqueThread windows.Handle + Priority int32 + BasePriority int32 + Reserved3 uint32 + ThreadState THREAD_STATE + WaitReason uint32 +} + +// SYSTEM_PROCESS_INFORMATION is a convenience struct to have first thread address at hand +// for this technique to access to heterogeneous data, see: +// https://justen.codes/breaking-all-the-rules-using-go-to-call-windows-api-2cbfd8c79724 +type SYSTEM_PROCESS_INFORMATION struct { + windows.SYSTEM_PROCESS_INFORMATION + ThreadsTable [1]SYSTEM_THREAD_INFORMATION +} + +// Stats are the stats this package offers +type Stats struct { + ProcessCount uint32 + ThreadCount uint32 + ThreadsByStatus map[THREAD_STATE]uint32 + Load uint32 // number of threads that contribute to system load, see https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html +} + +func EmptyStats() *Stats { + return &Stats{ + ThreadsByStatus: make(map[THREAD_STATE]uint32), + } +} + +// AddProc increments process count and returns itself. +func (s *Stats) AddProc() *Stats { + s.ProcessCount += 1 + return s +} + +// AddThread increments thread count, also updates ThreadsByStatus based on the status, +// finally if the state represents a busy thread, it increments the load. +// returns the current stats structure pointer. +func (s *Stats) AddThread(state THREAD_STATE) *Stats { + s.ThreadCount += 1 + s.ThreadsByStatus[state] += 1 + + if state.Busy() { + s.Load += 1 + } + + return s +} + +// SystemProcessInformationWalk is a helper structure to walk through the raw bytes +// that NtQuerySystemInformation produces and get correct structures +type SystemProcessInformationWalk struct { + SizeInBytes uint32 // buffer size + Offset uint32 // current offset + Buffer []byte // buffer with the data +} + +// Process returns the process under current offset +func (w *SystemProcessInformationWalk) Process() *SYSTEM_PROCESS_INFORMATION { + return (*SYSTEM_PROCESS_INFORMATION)(unsafe.Pointer(&w.Buffer[w.Offset])) +} + +// Next moves offset to the next process structure +// it returns true if there are still more PENDING processess to iterate +// it returns false if there are no more PENDING processess to iterate +// calling Next() when there are no more processes, has no effect +func (w *SystemProcessInformationWalk) Next() bool { + proc := w.Process() + + if proc.NextEntryOffset == 0 || proc.NextEntryOffset+w.Offset > w.SizeInBytes { + return false // reached the end + } + + w.Offset += proc.NextEntryOffset + + return true +} + +// Stats calculate stats for all processes and their threads +func (w *SystemProcessInformationWalk) Stats() *Stats { + stats := EmptyStats() + + for { + proc := w.Process() + + stats.AddProc() + + WalkThreads(proc, func(t SYSTEM_THREAD_INFORMATION) { + stats.AddThread(t.ThreadState) + }) + + if ok := w.Next(); !ok { + break + } + } + + return stats +} + +// WalkThreads() iterates over all threads of current process and applies given function +func WalkThreads(proc *SYSTEM_PROCESS_INFORMATION, fn func(t SYSTEM_THREAD_INFORMATION)) { + for i := 0; i < int(proc.NumberOfThreads); i++ { + thread := *(*SYSTEM_THREAD_INFORMATION)(unsafe.Pointer( + uintptr(unsafe.Pointer(&proc.ThreadsTable[0])) + + uintptr(i)*unsafe.Sizeof(proc.ThreadsTable[0]), + )) + + fn(thread) + } +} + +// GetSystemProcessInformation retrieves information of all procecess and threads +// see: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation +// look for SystemProcessInformation and related structures SYSTEM_PROCESS_INFORMATION and SYSTEM_THREAD_INFORMATION +// the returned structure has methods to walk through the structure +func GetSystemProcessInformation() (*SystemProcessInformationWalk, error) { + var ( + oneKb uint32 = 1024 + allocKb uint32 = 1 + allocBytes uint32 = allocKb * oneKb + buffer []byte + usedBytes uint32 + ) + + buffer = make([]byte, allocBytes) + + st := common.CallWithExpandingBuffer( + func() common.NtStatus { + return common.NtQuerySystemInformation( + windows.SystemProcessInformation, + &buffer[0], + allocBytes, + &usedBytes, + ) + }, + &buffer, + &usedBytes, + ) + + if st.IsError() { + return nil, st.Error() + } + + return &SystemProcessInformationWalk{ + SizeInBytes: usedBytes, + Offset: 0, + Buffer: buffer, + }, nil +} diff --git a/load/load_windows.go b/load/load_windows.go index 3ff0c0aa6..5cf004cd6 100644 --- a/load/load_windows.go +++ b/load/load_windows.go @@ -11,6 +11,7 @@ import ( "time" "github.com/shirou/gopsutil/v3/internal/common" + "github.com/shirou/gopsutil/v3/internal/procstats" ) var ( @@ -35,15 +36,16 @@ func loadAvgGoroutine() { currentLoad float64 ) - counter, err := common.ProcessorQueueLengthCounter() - if err != nil || counter == nil { - log.Println("gopsutil: unexpected processor queue length counter error, please file an issue on github: err") - return - } - tick := time.NewTicker(samplingFrequency).C for { - currentLoad, err = counter.GetValue() + // calling this because common.ProcessorQueueLengthCounter() returns zero values all time + w, err := procstats.GetSystemProcessInformation() + if err != nil { + log.Printf("gopsutil: unexpected GetSystemProcessInformation error, please file an issue on github: %v", err) + } else { + currentLoad = float64(w.Stats().Load) + } + loadAvgMutex.Lock() loadErr = err loadAvg1M = loadAvg1M*loadAvgFactor1M + currentLoad*(1-loadAvgFactor1M) From 91974eca6363f4eec66635164d583d1f985212f5 Mon Sep 17 00:00:00 2001 From: elfrucool Date: Thu, 29 Sep 2022 02:14:33 -0500 Subject: [PATCH 2/5] [issue-1357] manually allocating increasing buffer --- load/load_windows.go | 2 +- .../procstats_windows.go | 46 ++++++++++--------- 2 files changed, 26 insertions(+), 22 deletions(-) rename {internal/procstats => procstats}/procstats_windows.go (90%) diff --git a/load/load_windows.go b/load/load_windows.go index 5cf004cd6..2d7c9db3b 100644 --- a/load/load_windows.go +++ b/load/load_windows.go @@ -11,7 +11,7 @@ import ( "time" "github.com/shirou/gopsutil/v3/internal/common" - "github.com/shirou/gopsutil/v3/internal/procstats" + "github.com/shirou/gopsutil/v3/procstats" ) var ( diff --git a/internal/procstats/procstats_windows.go b/procstats/procstats_windows.go similarity index 90% rename from internal/procstats/procstats_windows.go rename to procstats/procstats_windows.go index 7d080d446..505ec6bbe 100644 --- a/internal/procstats/procstats_windows.go +++ b/procstats/procstats_windows.go @@ -185,30 +185,34 @@ func WalkThreads(proc *SYSTEM_PROCESS_INFORMATION, fn func(t SYSTEM_THREAD_INFOR // the returned structure has methods to walk through the structure func GetSystemProcessInformation() (*SystemProcessInformationWalk, error) { var ( - oneKb uint32 = 1024 - allocKb uint32 = 1 - allocBytes uint32 = allocKb * oneKb - buffer []byte - usedBytes uint32 + oneKb uint32 = 1024 + allocKb uint32 = 1 + buffer []byte + usedBytes uint32 ) - buffer = make([]byte, allocBytes) - - st := common.CallWithExpandingBuffer( - func() common.NtStatus { - return common.NtQuerySystemInformation( - windows.SystemProcessInformation, - &buffer[0], - allocBytes, - &usedBytes, - ) - }, - &buffer, - &usedBytes, - ) + // iterating instead of calling common.CallWithExpandingBuffer hangs forever + for { + var allocBytes uint32 = allocKb * oneKb + buffer = make([]byte, allocBytes) + + st := common.NtQuerySystemInformation( + windows.SystemProcessInformation, + &buffer[0], + allocBytes, + &usedBytes, + ) + + if st == common.NtStatus(windows.STATUS_INFO_LENGTH_MISMATCH) { + allocKb *= 2 + continue + } + + if st.IsError() { + return nil, st.Error() + } - if st.IsError() { - return nil, st.Error() + break } return &SystemProcessInformationWalk{ From 878eb66a04f3b45941c6d1bb6577051ee3bf7971 Mon Sep 17 00:00:00 2001 From: elfrucool Date: Tue, 4 Oct 2022 18:15:20 -0500 Subject: [PATCH 3/5] [issue-1357] remove procstats package Types and functions from procstats package are moved to internal/common package --- internal/common/common_windows.go | 212 ++++++++++++++++++++++++++++ load/load_windows.go | 3 +- procstats/procstats_windows.go | 223 ------------------------------ 3 files changed, 213 insertions(+), 225 deletions(-) delete mode 100644 procstats/procstats_windows.go diff --git a/internal/common/common_windows.go b/internal/common/common_windows.go index 295b70bfa..c98e59c3a 100644 --- a/internal/common/common_windows.go +++ b/internal/common/common_windows.go @@ -299,3 +299,215 @@ func NtQuerySystemInformation( uintptr(unsafe.Pointer(ReturnLength))) return NtStatus(r0) } + +// represents a win32 thread status +// see for possible values +type THREAD_STATE uint32 + +const ( + StateInitialized THREAD_STATE = iota + StateReady + StateRunning + StateStandby + StateTerminated + StateWait + StateTransition + StateUnknown +) + +func (s THREAD_STATE) String() string { + switch s { + case StateInitialized: + return "StateInitialized" + case StateReady: + return "StateReady" + case StateRunning: + return "StateRunning" + case StateStandby: + return "StateStandby" + case StateTerminated: + return "StateTerminated" + case StateWait: + return "StateWait" + case StateTransition: + return "StateTransition" + case StateUnknown: + return "StateUnknown" + default: + return "" + } +} + +// "BUSY" thread means a thread that is either running, transitioning to run or on a state that demans resources +// see https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html +func (s THREAD_STATE) Busy() bool { + switch s { + case StateReady, StateRunning, StateStandby, StateTransition: + return true + default: + return false + } +} + +// SYSTEM_THREAD_INFORMATION contains thread information as it is returned by NtQuerySystemInformation() API call +// look for its structure & documentation at: +// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation +type SYSTEM_THREAD_INFORMATION struct { + Reserved1 [3]int64 + Reserved2 uint32 + StartAddress uintptr + UniqueProcess windows.Handle + UniqueThread windows.Handle + Priority int32 + BasePriority int32 + Reserved3 uint32 + ThreadState THREAD_STATE + WaitReason uint32 +} + +// SYSTEM_PROCESS_INFORMATION is a convenience struct to have first thread address at hand +// for this technique to access to heterogeneous data, see: +// https://justen.codes/breaking-all-the-rules-using-go-to-call-windows-api-2cbfd8c79724 +type SYSTEM_PROCESS_INFORMATION struct { + windows.SYSTEM_PROCESS_INFORMATION + ThreadsTable [1]SYSTEM_THREAD_INFORMATION +} + +// Stats are the stats this package offers +type Stats struct { + ProcessCount uint32 + ThreadCount uint32 + ThreadsByStatus map[THREAD_STATE]uint32 + Load uint32 // number of threads that contribute to system load, see https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html +} + +func EmptyStats() *Stats { + return &Stats{ + ThreadsByStatus: make(map[THREAD_STATE]uint32), + } +} + +// AddProc increments process count and returns itself. +func (s *Stats) AddProc() *Stats { + s.ProcessCount += 1 + return s +} + +// AddThread increments thread count, also updates ThreadsByStatus based on the status, +// finally if the state represents a busy thread, it increments the load. +// returns the current stats structure pointer. +func (s *Stats) AddThread(state THREAD_STATE) *Stats { + s.ThreadCount += 1 + s.ThreadsByStatus[state] += 1 + + if state.Busy() { + s.Load += 1 + } + + return s +} + +// SystemProcessInformationWalk is a helper structure to walk through the raw bytes +// that NtQuerySystemInformation produces and get correct structures +type SystemProcessInformationWalk struct { + SizeInBytes uint32 // buffer size + Offset uint32 // current offset + Buffer []byte // buffer with the data +} + +// Process returns the process under current offset +func (w *SystemProcessInformationWalk) Process() *SYSTEM_PROCESS_INFORMATION { + return (*SYSTEM_PROCESS_INFORMATION)(unsafe.Pointer(&w.Buffer[w.Offset])) +} + +// Next moves offset to the next process structure +// it returns true if there are still more PENDING processess to iterate +// it returns false if there are no more PENDING processess to iterate +// calling Next() when there are no more processes, has no effect +func (w *SystemProcessInformationWalk) Next() bool { + proc := w.Process() + + if proc.NextEntryOffset == 0 || proc.NextEntryOffset+w.Offset > w.SizeInBytes { + return false // reached the end + } + + w.Offset += proc.NextEntryOffset + + return true +} + +// Stats calculate stats for all processes and their threads +func (w *SystemProcessInformationWalk) Stats() *Stats { + stats := EmptyStats() + + for { + proc := w.Process() + + stats.AddProc() + + WalkThreads(proc, func(t SYSTEM_THREAD_INFORMATION) { + stats.AddThread(t.ThreadState) + }) + + if ok := w.Next(); !ok { + break + } + } + + return stats +} + +// WalkThreads() iterates over all threads of current process and applies given function +func WalkThreads(proc *SYSTEM_PROCESS_INFORMATION, fn func(t SYSTEM_THREAD_INFORMATION)) { + for i := 0; i < int(proc.NumberOfThreads); i++ { + thread := *(*SYSTEM_THREAD_INFORMATION)(unsafe.Pointer( + uintptr(unsafe.Pointer(&proc.ThreadsTable[0])) + + uintptr(i)*unsafe.Sizeof(proc.ThreadsTable[0]), + )) + + fn(thread) + } +} + +// GetSystemProcessInformation retrieves information of all procecess and threads +// see: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation +// look for SystemProcessInformation and related structures SYSTEM_PROCESS_INFORMATION and SYSTEM_THREAD_INFORMATION +// the returned structure has methods to walk through the structure +func GetSystemProcessInformation() (*SystemProcessInformationWalk, error) { + var ( + oneKb uint32 = 1024 + allocKb uint32 = 1 + buffer []byte + usedBytes uint32 + ) + + // iterating instead of calling common.CallWithExpandingBuffer hangs forever + for { + var allocBytes uint32 = allocKb * oneKb + buffer = make([]byte, allocBytes) + + st := NtQuerySystemInformation( + windows.SystemProcessInformation, + &buffer[0], + allocBytes, + &usedBytes, + ) + + if st == NtStatus(windows.STATUS_INFO_LENGTH_MISMATCH) { + allocKb *= 2 + continue + } + + if st.IsError() { + return nil, st.Error() + } + + break + } + + return &SystemProcessInformationWalk{ + SizeInBytes: usedBytes, + Offset: 0, + Buffer: buffer, + }, nil +} diff --git a/load/load_windows.go b/load/load_windows.go index 2d7c9db3b..e1dec29d8 100644 --- a/load/load_windows.go +++ b/load/load_windows.go @@ -11,7 +11,6 @@ import ( "time" "github.com/shirou/gopsutil/v3/internal/common" - "github.com/shirou/gopsutil/v3/procstats" ) var ( @@ -39,7 +38,7 @@ func loadAvgGoroutine() { tick := time.NewTicker(samplingFrequency).C for { // calling this because common.ProcessorQueueLengthCounter() returns zero values all time - w, err := procstats.GetSystemProcessInformation() + w, err := common.GetSystemProcessInformation() if err != nil { log.Printf("gopsutil: unexpected GetSystemProcessInformation error, please file an issue on github: %v", err) } else { diff --git a/procstats/procstats_windows.go b/procstats/procstats_windows.go deleted file mode 100644 index 505ec6bbe..000000000 --- a/procstats/procstats_windows.go +++ /dev/null @@ -1,223 +0,0 @@ -//go:build windows -// +build windows - -package procstats - -import ( - "unsafe" - - "github.com/shirou/gopsutil/v3/internal/common" - "golang.org/x/sys/windows" -) - -// represents a win32 thread status -// see for possible values -type THREAD_STATE uint32 - -const ( - StateInitialized THREAD_STATE = iota - StateReady - StateRunning - StateStandby - StateTerminated - StateWait - StateTransition - StateUnknown -) - -func (s THREAD_STATE) String() string { - switch s { - case StateInitialized: - return "StateInitialized" - case StateReady: - return "StateReady" - case StateRunning: - return "StateRunning" - case StateStandby: - return "StateStandby" - case StateTerminated: - return "StateTerminated" - case StateWait: - return "StateWait" - case StateTransition: - return "StateTransition" - case StateUnknown: - return "StateUnknown" - default: - return "" - } -} - -// "BUSY" thread means a thread that is either running, transitioning to run or on a state that demans resources -// see https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html -func (s THREAD_STATE) Busy() bool { - switch s { - case StateReady, StateRunning, StateStandby, StateTransition: - return true - default: - return false - } -} - -// SYSTEM_THREAD_INFORMATION contains thread information as it is returned by NtQuerySystemInformation() API call -// look for its structure & documentation at: -// https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation -type SYSTEM_THREAD_INFORMATION struct { - Reserved1 [3]int64 - Reserved2 uint32 - StartAddress uintptr - UniqueProcess windows.Handle - UniqueThread windows.Handle - Priority int32 - BasePriority int32 - Reserved3 uint32 - ThreadState THREAD_STATE - WaitReason uint32 -} - -// SYSTEM_PROCESS_INFORMATION is a convenience struct to have first thread address at hand -// for this technique to access to heterogeneous data, see: -// https://justen.codes/breaking-all-the-rules-using-go-to-call-windows-api-2cbfd8c79724 -type SYSTEM_PROCESS_INFORMATION struct { - windows.SYSTEM_PROCESS_INFORMATION - ThreadsTable [1]SYSTEM_THREAD_INFORMATION -} - -// Stats are the stats this package offers -type Stats struct { - ProcessCount uint32 - ThreadCount uint32 - ThreadsByStatus map[THREAD_STATE]uint32 - Load uint32 // number of threads that contribute to system load, see https://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html -} - -func EmptyStats() *Stats { - return &Stats{ - ThreadsByStatus: make(map[THREAD_STATE]uint32), - } -} - -// AddProc increments process count and returns itself. -func (s *Stats) AddProc() *Stats { - s.ProcessCount += 1 - return s -} - -// AddThread increments thread count, also updates ThreadsByStatus based on the status, -// finally if the state represents a busy thread, it increments the load. -// returns the current stats structure pointer. -func (s *Stats) AddThread(state THREAD_STATE) *Stats { - s.ThreadCount += 1 - s.ThreadsByStatus[state] += 1 - - if state.Busy() { - s.Load += 1 - } - - return s -} - -// SystemProcessInformationWalk is a helper structure to walk through the raw bytes -// that NtQuerySystemInformation produces and get correct structures -type SystemProcessInformationWalk struct { - SizeInBytes uint32 // buffer size - Offset uint32 // current offset - Buffer []byte // buffer with the data -} - -// Process returns the process under current offset -func (w *SystemProcessInformationWalk) Process() *SYSTEM_PROCESS_INFORMATION { - return (*SYSTEM_PROCESS_INFORMATION)(unsafe.Pointer(&w.Buffer[w.Offset])) -} - -// Next moves offset to the next process structure -// it returns true if there are still more PENDING processess to iterate -// it returns false if there are no more PENDING processess to iterate -// calling Next() when there are no more processes, has no effect -func (w *SystemProcessInformationWalk) Next() bool { - proc := w.Process() - - if proc.NextEntryOffset == 0 || proc.NextEntryOffset+w.Offset > w.SizeInBytes { - return false // reached the end - } - - w.Offset += proc.NextEntryOffset - - return true -} - -// Stats calculate stats for all processes and their threads -func (w *SystemProcessInformationWalk) Stats() *Stats { - stats := EmptyStats() - - for { - proc := w.Process() - - stats.AddProc() - - WalkThreads(proc, func(t SYSTEM_THREAD_INFORMATION) { - stats.AddThread(t.ThreadState) - }) - - if ok := w.Next(); !ok { - break - } - } - - return stats -} - -// WalkThreads() iterates over all threads of current process and applies given function -func WalkThreads(proc *SYSTEM_PROCESS_INFORMATION, fn func(t SYSTEM_THREAD_INFORMATION)) { - for i := 0; i < int(proc.NumberOfThreads); i++ { - thread := *(*SYSTEM_THREAD_INFORMATION)(unsafe.Pointer( - uintptr(unsafe.Pointer(&proc.ThreadsTable[0])) + - uintptr(i)*unsafe.Sizeof(proc.ThreadsTable[0]), - )) - - fn(thread) - } -} - -// GetSystemProcessInformation retrieves information of all procecess and threads -// see: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation -// look for SystemProcessInformation and related structures SYSTEM_PROCESS_INFORMATION and SYSTEM_THREAD_INFORMATION -// the returned structure has methods to walk through the structure -func GetSystemProcessInformation() (*SystemProcessInformationWalk, error) { - var ( - oneKb uint32 = 1024 - allocKb uint32 = 1 - buffer []byte - usedBytes uint32 - ) - - // iterating instead of calling common.CallWithExpandingBuffer hangs forever - for { - var allocBytes uint32 = allocKb * oneKb - buffer = make([]byte, allocBytes) - - st := common.NtQuerySystemInformation( - windows.SystemProcessInformation, - &buffer[0], - allocBytes, - &usedBytes, - ) - - if st == common.NtStatus(windows.STATUS_INFO_LENGTH_MISMATCH) { - allocKb *= 2 - continue - } - - if st.IsError() { - return nil, st.Error() - } - - break - } - - return &SystemProcessInformationWalk{ - SizeInBytes: usedBytes, - Offset: 0, - Buffer: buffer, - }, nil -} From e45e81788326c508acd7412fb0c18255cb4c40b3 Mon Sep 17 00:00:00 2001 From: elfrucool Date: Thu, 21 Sep 2023 13:14:10 -0600 Subject: [PATCH 4/5] Fix code --- load/load_windows.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/load/load_windows.go b/load/load_windows.go index 005ef4364..e95ab3996 100644 --- a/load/load_windows.go +++ b/load/load_windows.go @@ -36,7 +36,8 @@ func loadAvgGoroutine(ctx context.Context) { ) tick := time.NewTicker(samplingFrequency).C - for { + + f := func() { // calling this because common.ProcessorQueueLengthCounter() returns zero values all time w, err := common.GetSystemProcessInformation() if err != nil { From dc499ca1b74064c0f5c85bd034d8527c0cf8f134 Mon Sep 17 00:00:00 2001 From: elfrucool Date: Thu, 29 Feb 2024 15:01:13 -0600 Subject: [PATCH 5/5] Fix import --- load/load_windows.go | 1 + 1 file changed, 1 insertion(+) diff --git a/load/load_windows.go b/load/load_windows.go index 3fbc7909f..3580cc7d4 100644 --- a/load/load_windows.go +++ b/load/load_windows.go @@ -5,6 +5,7 @@ package load import ( "context" + "log" "math" "sync" "time"