Skip to content

Commit 44e2257

Browse files
committed
optimize pdh syscalls
Signed-off-by: Jan-Otto Kröpke <[email protected]>
1 parent 2ba863b commit 44e2257

File tree

3 files changed

+55
-52
lines changed

3 files changed

+55
-52
lines changed

.idea/dictionaries/project.xml

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/pdh/collector.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ func (c *Collector) collectWorkerRaw() {
301301
)
302302

303303
buf := make([]byte, 1)
304+
// Reuse string cache across collection cycles to reduce allocations
305+
stringCache := make(map[*uint16]string, 64)
304306

305307
for data := range c.collectCh {
306308
err = (func() error {
@@ -334,7 +336,10 @@ func (c *Collector) collectWorkerRaw() {
334336
elemValue := reflect.ValueOf(reflect.New(elemType).Interface()).Elem()
335337

336338
indexMap := map[string]int{}
337-
stringMap := map[*uint16]string{}
339+
// Clear and reuse string cache instead of creating new one each time
340+
for k := range stringCache {
341+
delete(stringCache, k)
342+
}
338343

339344
for _, counter := range c.counters {
340345
for _, instance := range counter.Instances {
@@ -372,11 +377,6 @@ func (c *Collector) collectWorkerRaw() {
372377

373378
items = unsafe.Slice((*RawCounterItem)(unsafe.Pointer(&buf[0])), itemCount)
374379

375-
var (
376-
instanceName string
377-
ok bool
378-
)
379-
380380
for _, item := range items {
381381
if item.RawValue.CStatus != CstatusValidData && item.RawValue.CStatus != CstatusNewData {
382382
c.logger.Debug("skipping counter item with invalid data status",
@@ -388,9 +388,14 @@ func (c *Collector) collectWorkerRaw() {
388388
continue
389389
}
390390

391-
if instanceName, ok = stringMap[item.SzName]; !ok {
391+
var (
392+
instanceName string
393+
ok bool
394+
)
395+
396+
if instanceName, ok = stringCache[item.SzName]; !ok {
392397
instanceName = windows.UTF16PtrToString(item.SzName)
393-
stringMap[item.SzName] = instanceName
398+
stringCache[item.SzName] = instanceName
394399
}
395400

396401
if strings.HasSuffix(instanceName, InstanceTotal) && !c.totalCounterRequested {
@@ -401,12 +406,8 @@ func (c *Collector) collectWorkerRaw() {
401406
instanceName = InstanceEmpty
402407
}
403408

404-
var (
405-
index int
406-
ok bool
407-
)
408-
409-
if index, ok = indexMap[instanceName]; !ok {
409+
index, indexExists := indexMap[instanceName]
410+
if !indexExists {
410411
index = dv.Len()
411412
indexMap[instanceName] = index
412413

@@ -475,6 +476,8 @@ func (c *Collector) collectWorkerFormatted() {
475476
)
476477

477478
buf := make([]byte, 1)
479+
// Reuse string cache across collection cycles to reduce allocations
480+
stringCache := make(map[*uint16]string, 64)
478481

479482
for data := range c.collectCh {
480483
err = (func() error {
@@ -508,7 +511,10 @@ func (c *Collector) collectWorkerFormatted() {
508511
elemValue := reflect.ValueOf(reflect.New(elemType).Interface()).Elem()
509512

510513
indexMap := map[string]int{}
511-
stringMap := map[*uint16]string{}
514+
// Clear and reuse string cache instead of creating new one each time
515+
for k := range stringCache {
516+
delete(stringCache, k)
517+
}
512518

513519
for _, counter := range c.counters {
514520
for _, instance := range counter.Instances {
@@ -556,9 +562,9 @@ func (c *Collector) collectWorkerFormatted() {
556562
continue
557563
}
558564

559-
if instanceName, ok = stringMap[item.SzName]; !ok {
565+
if instanceName, ok = stringCache[item.SzName]; !ok {
560566
instanceName = windows.UTF16PtrToString(item.SzName)
561-
stringMap[item.SzName] = instanceName
567+
stringCache[item.SzName] = instanceName
562568
}
563569

564570
if strings.HasSuffix(instanceName, InstanceTotal) && !c.totalCounterRequested {
@@ -569,12 +575,8 @@ func (c *Collector) collectWorkerFormatted() {
569575
instanceName = InstanceEmpty
570576
}
571577

572-
var (
573-
index int
574-
ok bool
575-
)
576-
577-
if index, ok = indexMap[instanceName]; !ok {
578+
index, indexExists := indexMap[instanceName]
579+
if !indexExists {
578580
index = dv.Len()
579581
indexMap[instanceName] = index
580582

internal/pdh/collector_bench_test.go

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,34 +28,34 @@ import (
2828
type processFull struct {
2929
Name string
3030

31-
ProcessorTime float64 `pdh:"% Processor Time"`
32-
PrivilegedTime float64 `pdh:"% Privileged Time"`
33-
UserTime float64 `pdh:"% User Time"`
34-
CreatingProcessID float64 `pdh:"Creating Process ID"`
35-
ElapsedTime float64 `pdh:"Elapsed Time"`
36-
HandleCount float64 `pdh:"Handle Count"`
37-
IDProcess float64 `pdh:"ID Process"`
38-
IODataBytesSec float64 `pdh:"IO Data Bytes/sec"`
39-
IODataOperationsSec float64 `pdh:"IO Data Operations/sec"`
40-
IOOtherBytesSec float64 `pdh:"IO Other Bytes/sec"`
41-
IOOtherOperationsSec float64 `pdh:"IO Other Operations/sec"`
42-
IOReadBytesSec float64 `pdh:"IO Read Bytes/sec"`
43-
IOReadOperationsSec float64 `pdh:"IO Read Operations/sec"`
44-
IOWriteBytesSec float64 `pdh:"IO Write Bytes/sec"`
45-
IOWriteOperationsSec float64 `pdh:"IO Write Operations/sec"`
46-
PageFaultsSec float64 `pdh:"Page Faults/sec"`
47-
PageFileBytesPeak float64 `pdh:"Page File Bytes Peak"`
48-
PageFileBytes float64 `pdh:"Page File Bytes"`
49-
PoolNonpagedBytes float64 `pdh:"Pool Nonpaged Bytes"`
50-
PoolPagedBytes float64 `pdh:"Pool Paged Bytes"`
51-
PriorityBase float64 `pdh:"Priority Base"`
52-
PrivateBytes float64 `pdh:"Private Bytes"`
53-
ThreadCount float64 `pdh:"Thread Count"`
54-
VirtualBytesPeak float64 `pdh:"Virtual Bytes Peak"`
55-
VirtualBytes float64 `pdh:"Virtual Bytes"`
56-
WorkingSetPrivate float64 `pdh:"Working Set - Private"`
57-
WorkingSetPeak float64 `pdh:"Working Set Peak"`
58-
WorkingSet float64 `pdh:"Working Set"`
31+
ProcessorTime float64 `perfdata:"% Processor Time"`
32+
PrivilegedTime float64 `perfdata:"% Privileged Time"`
33+
UserTime float64 `perfdata:"% User Time"`
34+
CreatingProcessID float64 `perfdata:"Creating Process ID"`
35+
ElapsedTime float64 `perfdata:"Elapsed Time"`
36+
HandleCount float64 `perfdata:"Handle Count"`
37+
IDProcess float64 `perfdata:"ID Process"`
38+
IODataBytesSec float64 `perfdata:"IO Data Bytes/sec"`
39+
IODataOperationsSec float64 `perfdata:"IO Data Operations/sec"`
40+
IOOtherBytesSec float64 `perfdata:"IO Other Bytes/sec"`
41+
IOOtherOperationsSec float64 `perfdata:"IO Other Operations/sec"`
42+
IOReadBytesSec float64 `perfdata:"IO Read Bytes/sec"`
43+
IOReadOperationsSec float64 `perfdata:"IO Read Operations/sec"`
44+
IOWriteBytesSec float64 `perfdata:"IO Write Bytes/sec"`
45+
IOWriteOperationsSec float64 `perfdata:"IO Write Operations/sec"`
46+
PageFaultsSec float64 `perfdata:"Page Faults/sec"`
47+
PageFileBytesPeak float64 `perfdata:"Page File Bytes Peak"`
48+
PageFileBytes float64 `perfdata:"Page File Bytes"`
49+
PoolNonpagedBytes float64 `perfdata:"Pool Nonpaged Bytes"`
50+
PoolPagedBytes float64 `perfdata:"Pool Paged Bytes"`
51+
PriorityBase float64 `perfdata:"Priority Base"`
52+
PrivateBytes float64 `perfdata:"Private Bytes"`
53+
ThreadCount float64 `perfdata:"Thread Count"`
54+
VirtualBytesPeak float64 `perfdata:"Virtual Bytes Peak"`
55+
VirtualBytes float64 `perfdata:"Virtual Bytes"`
56+
WorkingSetPrivate float64 `perfdata:"Working Set - Private"`
57+
WorkingSetPeak float64 `perfdata:"Working Set Peak"`
58+
WorkingSet float64 `perfdata:"Working Set"`
5959
}
6060

6161
func BenchmarkTestCollector(b *testing.B) {

0 commit comments

Comments
 (0)