[windows] go-sysinfo KernelVersion() re-stats ntoskrnl.exe on every call — cache the result

Open Beginner friendly
#293 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Refactor
Clarity
Clearly specified
Activity status
Quiet
Tech stack
go

Research direction

Start with providers/windows/kernel_windows.go to trace KernelVersion() and then inspect providers/windows/host_windows.go to confirm how newHost() invokes it. Add first-call caching with sync.Once, preserving the returned version and error, and verify repeated host-info collection no longer re-stats ntoskrnl.exe.

Written by the indexing model from the issue text.

Description

Team:Elastic-Agent-Control-Plane

KernelVersion() on Windows has no cache. It calls GetFileVersionInfo against %SystemRoot%\System32\ntoskrnl.exe on every invocation. The kernel version cannot change while the process runs. Every repeated call is unnecessary.

Why this matters:

GetFileVersionInfo issues a syscall to stat the file. Go runs syscalls on real OS threads. If the syscall blocks, the Go runtime spawns a new OS thread to keep other goroutines running. Each blocked goroutine produces another thread. A caller that collects host info in a tight loop — or from many concurrent goroutines — can produce a large number of OS threads, all blocked on the same file stat. This amplifies any transient filesystem stall into a thread explosion.

Code path:

  • providers/windows/kernel_windows.goKernelVersion() calls GetFileVersionInfo unconditionally.
  • providers/windows/host_windows.gonewHost() calls r.kernelVersion(h) on every host-info collection. It does not store the result.

Fix:

Cache the result on first call. Use `sync.Once`. The kernel version is constant for the life of the process.

type windowsSystem struct {
    kernelVersionOnce sync.Once
    kernelVersionVal  string
    kernelVersionErr  error
}

func (r *windowsSystem) KernelVersion() (string, error) {
    r.kernelVersionOnce.Do(func() {
        r.kernelVersionVal, r.kernelVersionErr = getKernelVersion()
    })
    return r.kernelVersionVal, r.kernelVersionErr
}

No TTL is needed. The value does not change.

Affected versions: Any caller that collects host info in a loop on Windows. Confirmed in Elastic Agent 9.4 with `metricbeat.default: otel`.

Dominant language
Go
Stars
405
Forks
92
PR merge metrics
No merged PRs in 30d

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from elastic/go-sysinfo

All issues in elastic/go-sysinfo

Similar issues

More Go issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.