github.com/google/cadvisor@v0.49.1/perf/uncore_libpfm_test.go (about) 1 //go:build libpfm && cgo 2 // +build libpfm,cgo 3 4 // Copyright 2020 Google Inc. All Rights Reserved. 5 // 6 // Licensed under the Apache License, Version 2.0 (the "License"); 7 // you may not use this file except in compliance with the License. 8 // You may obtain a copy of the License at 9 // 10 // http://www.apache.org/licenses/LICENSE-2.0 11 // 12 // Unless required by applicable law or agreed to in writing, software 13 // distributed under the License is distributed on an "AS IS" BASIS, 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 // See the License for the specific language governing permissions and 16 // limitations under the License. 17 18 // Uncore perf events logic tests. 19 package perf 20 21 import ( 22 "bytes" 23 "encoding/binary" 24 "os" 25 "path/filepath" 26 "testing" 27 28 "golang.org/x/sys/unix" 29 30 "github.com/stretchr/testify/assert" 31 32 v1 "github.com/google/cadvisor/info/v1" 33 ) 34 35 func mockSystemDevices() (string, error) { 36 testDir, err := os.MkdirTemp("", "uncore_imc_test") 37 if err != nil { 38 return "", err 39 } 40 41 // First Uncore IMC PMU. 42 firstPMUPath := filepath.Join(testDir, "uncore_imc_0") 43 err = os.MkdirAll(firstPMUPath, os.ModePerm) 44 if err != nil { 45 return "", err 46 } 47 err = os.WriteFile(filepath.Join(firstPMUPath, "cpumask"), []byte("0-1"), 0777) 48 if err != nil { 49 return "", err 50 } 51 err = os.WriteFile(filepath.Join(firstPMUPath, "type"), []byte("18"), 0777) 52 if err != nil { 53 return "", err 54 } 55 56 // Second Uncore IMC PMU. 57 secondPMUPath := filepath.Join(testDir, "uncore_imc_1") 58 err = os.MkdirAll(secondPMUPath, os.ModePerm) 59 if err != nil { 60 return "", err 61 } 62 err = os.WriteFile(filepath.Join(secondPMUPath, "cpumask"), []byte("0,1"), 0777) 63 if err != nil { 64 return "", err 65 } 66 err = os.WriteFile(filepath.Join(secondPMUPath, "type"), []byte("19"), 0777) 67 if err != nil { 68 return "", err 69 } 70 71 return testDir, nil 72 } 73 74 func TestUncore(t *testing.T) { 75 path, err := mockSystemDevices() 76 assert.Nil(t, err) 77 defer func() { 78 err := os.RemoveAll(path) 79 assert.Nil(t, err) 80 }() 81 82 actual, err := getUncorePMUs(path) 83 assert.Nil(t, err) 84 expected := uncorePMUs{ 85 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 86 "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, 87 } 88 assert.Equal(t, expected, actual) 89 90 pmuSet := uncorePMUs{ 91 "uncore_imc_0": actual["uncore_imc_0"], 92 "uncore_imc_1": actual["uncore_imc_1"], 93 } 94 95 actualPMU, err := getPMU(pmuSet, expected["uncore_imc_0"].typeOf) 96 assert.Nil(t, err) 97 assert.Equal(t, expected["uncore_imc_0"], *actualPMU) 98 } 99 100 func TestUncoreCollectorSetup(t *testing.T) { 101 path, err := mockSystemDevices() 102 assert.Nil(t, err) 103 defer func() { 104 err := os.RemoveAll(path) 105 assert.Nil(t, err) 106 }() 107 108 events := PerfEvents{ 109 Core: Events{ 110 Events: []Group{ 111 {[]Event{"cache-misses"}, false}, 112 }, 113 }, 114 Uncore: Events{ 115 Events: []Group{ 116 {[]Event{"uncore_imc_1/cas_count_read"}, false}, 117 {[]Event{"uncore_imc_1/non_existing_event"}, false}, 118 {[]Event{"uncore_imc_0/cas_count_write", "uncore_imc_0/cas_count_read"}, true}, 119 }, 120 CustomEvents: []CustomEvent{ 121 {19, Config{0x01, 0x02}, "uncore_imc_1/cas_count_read"}, 122 {0, Config{0x02, 0x03}, "uncore_imc_0/cas_count_write"}, 123 {18, Config{0x01, 0x02}, "uncore_imc_0/cas_count_read"}, 124 }, 125 }, 126 } 127 128 collector := &uncoreCollector{} 129 collector.perfEventOpen = func(attr *unix.PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { 130 return int(attr.Config), nil 131 } 132 collector.ioctlSetInt = func(fd int, req uint, value int) error { 133 return nil 134 } 135 136 err = collector.setup(events, path) 137 assert.Equal(t, []string{"uncore_imc_1/cas_count_read"}, 138 getMapKeys(collector.cpuFiles[0]["uncore_imc_1"].cpuFiles)) 139 assert.ElementsMatch(t, []string{"uncore_imc_0/cas_count_write", "uncore_imc_0/cas_count_read"}, 140 getMapKeys(collector.cpuFiles[2]["uncore_imc_0"].cpuFiles)) 141 142 // There are no errors. 143 assert.Nil(t, err) 144 } 145 146 func TestParseUncoreEvents(t *testing.T) { 147 events := PerfEvents{ 148 Uncore: Events{ 149 Events: []Group{ 150 {[]Event{"cas_count_read"}, false}, 151 {[]Event{"cas_count_write"}, false}, 152 }, 153 CustomEvents: []CustomEvent{ 154 { 155 Type: 17, 156 Config: Config{0x50, 0x60}, 157 Name: "cas_count_read", 158 }, 159 }, 160 }, 161 } 162 eventToCustomEvent := parseUncoreEvents(events.Uncore) 163 assert.Len(t, eventToCustomEvent, 1) 164 assert.Equal(t, eventToCustomEvent["cas_count_read"].Name, Event("cas_count_read")) 165 assert.Equal(t, eventToCustomEvent["cas_count_read"].Type, uint32(17)) 166 assert.Equal(t, eventToCustomEvent["cas_count_read"].Config, Config{0x50, 0x60}) 167 } 168 169 func TestObtainPMUs(t *testing.T) { 170 got := uncorePMUs{ 171 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 172 "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, 173 } 174 175 actual := obtainPMUs("uncore_imc_0", got) 176 assert.Equal(t, uncorePMUs{"uncore_imc_0": got["uncore_imc_0"]}, actual) 177 178 actual = obtainPMUs("uncore_imc_1", got) 179 assert.Equal(t, uncorePMUs{"uncore_imc_1": got["uncore_imc_1"]}, actual) 180 181 actual = obtainPMUs("", got) 182 assert.Equal(t, uncorePMUs{}, actual) 183 } 184 185 func TestUncoreParseEventName(t *testing.T) { 186 eventName, pmuPrefix := parseEventName("some_event") 187 assert.Equal(t, "some_event", eventName) 188 assert.Empty(t, pmuPrefix) 189 190 eventName, pmuPrefix = parseEventName("some_pmu/some_event") 191 assert.Equal(t, "some_pmu", pmuPrefix) 192 assert.Equal(t, "some_event", eventName) 193 194 eventName, pmuPrefix = parseEventName("some_pmu/some_event/first_slash/second_slash") 195 assert.Equal(t, "some_pmu", pmuPrefix) 196 assert.Equal(t, "some_event/first_slash/second_slash", eventName) 197 } 198 199 func TestCheckGroup(t *testing.T) { 200 var testCases = []struct { 201 group Group 202 eventPMUs map[Event]uncorePMUs 203 expectedOutput string 204 }{ 205 { 206 Group{[]Event{"uncore_imc/cas_count_write"}, false}, 207 map[Event]uncorePMUs{}, 208 "the event \"uncore_imc/cas_count_write\" don't have any PMU to count with", 209 }, 210 { 211 Group{[]Event{"uncore_imc/cas_count_write", "uncore_imc/cas_count_read"}, true}, 212 map[Event]uncorePMUs{"uncore_imc/cas_count_write": { 213 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 214 "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, 215 }, 216 "uncore_imc/cas_count_read": { 217 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 218 "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, 219 }, 220 }, 221 "the events in group usually have to be from single PMU, try reorganizing the \"[uncore_imc/cas_count_write uncore_imc/cas_count_read]\" group", 222 }, 223 { 224 Group{[]Event{"uncore_imc_0/cas_count_write", "uncore_imc_1/cas_count_read"}, true}, 225 map[Event]uncorePMUs{"uncore_imc_0/cas_count_write": { 226 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 227 }, 228 "uncore_imc_1/cas_count_read": { 229 "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, 230 }, 231 }, 232 "the events in group usually have to be from the same PMU, try reorganizing the \"[uncore_imc_0/cas_count_write uncore_imc_1/cas_count_read]\" group", 233 }, 234 { 235 Group{[]Event{"uncore_imc/cas_count_write"}, false}, 236 map[Event]uncorePMUs{"uncore_imc/cas_count_write": { 237 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 238 "uncore_imc_1": {name: "uncore_imc_1", typeOf: 19, cpus: []uint32{0, 1}}, 239 }}, 240 "", 241 }, 242 { 243 Group{[]Event{"uncore_imc_0/cas_count_write", "uncore_imc_0/cas_count_read"}, true}, 244 map[Event]uncorePMUs{"uncore_imc_0/cas_count_write": { 245 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 246 }, 247 "uncore_imc_0/cas_count_read": { 248 "uncore_imc_0": {name: "uncore_imc_0", typeOf: 18, cpus: []uint32{0, 1}}, 249 }}, 250 "", 251 }, 252 } 253 254 for _, tc := range testCases { 255 err := checkGroup(tc.group, tc.eventPMUs) 256 if tc.expectedOutput == "" { 257 assert.Nil(t, err) 258 } else { 259 assert.EqualError(t, err, tc.expectedOutput) 260 } 261 } 262 } 263 264 func TestReadPerfUncoreStat(t *testing.T) { 265 file := GroupReadFormat{ 266 TimeEnabled: 0, 267 TimeRunning: 1, 268 Nr: 1, 269 } 270 271 valuesFile := Values{ 272 Value: 4, 273 ID: 0, 274 } 275 276 expectedStat := []v1.PerfUncoreStat{{ 277 PerfValue: v1.PerfValue{ 278 ScalingRatio: 1, 279 Value: 4, 280 Name: "foo", 281 }, 282 Socket: 0, 283 PMU: "bar", 284 }} 285 cpuToSocket := map[int]int{ 286 1: 0, 287 2: 0, 288 } 289 290 buf := &buffer{bytes.NewBuffer([]byte{})} 291 err := binary.Write(buf, binary.LittleEndian, file) 292 assert.NoError(t, err) 293 err = binary.Write(buf, binary.LittleEndian, valuesFile) 294 assert.NoError(t, err) 295 296 stat, err := readPerfUncoreStat(buf, group{ 297 cpuFiles: nil, 298 names: []string{"foo"}, 299 leaderName: "foo", 300 }, 1, "bar", cpuToSocket) 301 assert.NoError(t, err) 302 assert.Equal(t, expectedStat, stat) 303 } 304 305 func getMapKeys(someMap map[string]map[int]readerCloser) []string { 306 var keys []string 307 for key := range someMap { 308 keys = append(keys, key) 309 } 310 return keys 311 }