diff --git a/collector/perflib.go b/collector/perflib.go index ab646480..743c797d 100644 --- a/collector/perflib.go +++ b/collector/perflib.go @@ -12,10 +12,8 @@ import ( "github.com/go-kit/log/level" ) -var nametable = perflib.CounterNameTable - func MapCounterToIndex(name string) string { - return strconv.Itoa(int(nametable.LookupIndex(name))) + return strconv.Itoa(int(perflib.CounterNameTable.LookupIndex(name))) } func getPerflibSnapshot(objNames string) (map[string]*perflib.PerfObject, error) { diff --git a/perflib/nametable.go b/perflib/nametable.go index cd717e4f..b10a7610 100644 --- a/perflib/nametable.go +++ b/perflib/nametable.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "strconv" + "sync" ) // Initialize global name tables @@ -18,54 +19,63 @@ func (p *perfObjectType) LookupName() string { } type NameTable struct { - byIndex map[uint32]string - byString map[string]uint32 + once sync.Once + + name string + + table struct { + index map[uint32]string + string map[string]uint32 + } } func (t *NameTable) LookupString(index uint32) string { - return t.byIndex[index] + t.initialize() + return t.table.index[index] } func (t *NameTable) LookupIndex(str string) uint32 { - return t.byString[str] + t.initialize() + return t.table.string[str] } // QueryNameTable Query a perflib name table from the registry. Specify the type and the language // code (i.e. "Counter 009" or "Help 009") for English language. func QueryNameTable(tableName string) *NameTable { - nameTable := new(NameTable) - nameTable.byIndex = make(map[uint32]string) - - buffer, err := queryRawData(tableName) - if err != nil { - panic(err) + return &NameTable{ + name: tableName, } - r := bytes.NewReader(buffer) - for { - index, err := readUTF16String(r) - if err != nil { - break - } - - desc, err := readUTF16String(r) - if err != nil { - break - } - - indexInt, _ := strconv.Atoi(index) - - if err != nil { - panic(fmt.Sprint("Invalid index ", index)) - } - - nameTable.byIndex[uint32(indexInt)] = desc - } - - nameTable.byString = make(map[string]uint32) - - for k, v := range nameTable.byIndex { - nameTable.byString[v] = k - } - - return nameTable +} + +func (t *NameTable) initialize() { + t.once.Do(func() { + t.table.index = make(map[uint32]string) + t.table.string = make(map[string]uint32) + + buffer, err := queryRawData(t.name) + if err != nil { + panic(err) + } + r := bytes.NewReader(buffer) + for { + index, err := readUTF16String(r) + if err != nil { + break + } + + desc, err := readUTF16String(r) + if err != nil { + break + } + + if err != nil { + panic(fmt.Sprint("Invalid index ", index)) + } + + indexInt, _ := strconv.Atoi(index) + + t.table.index[uint32(indexInt)] = desc + t.table.string[desc] = uint32(indexInt) + } + }) } diff --git a/perflib/perflib.go b/perflib/perflib.go index b4366aba..e6e1d78c 100644 --- a/perflib/perflib.go +++ b/perflib/perflib.go @@ -175,9 +175,6 @@ type PerfCounter struct { SecondValue int64 } -// Error value returned by RegQueryValueEx if the buffer isn't sufficiently large -const errorMoreData = syscall.Errno(syscall.ERROR_MORE_DATA) - var ( bufLenGlobal = uint32(400000) bufLenCostly = uint32(2000000) @@ -223,7 +220,7 @@ func queryRawData(query string) ([]byte, error) { (*byte)(unsafe.Pointer(&buffer[0])), &bufLen) - if err == errorMoreData { + if err == error(syscall.ERROR_MORE_DATA) { newBuffer := make([]byte, len(buffer)+16384) copy(newBuffer, buffer) buffer = newBuffer