@@ -47,6 +47,10 @@ type collector struct {
47
47
onlineCPUs []int
48
48
eventToCustomEvent map [Event ]* CustomEvent
49
49
uncore stats.Collector
50
+
51
+ // Handle for mocking purposes.
52
+ perfEventOpen func (attr * unix.PerfEventAttr , pid int , cpu int , groupFd int , flags int ) (fd int , err error )
53
+ ioctlSetInt func (fd int , req uint , value int ) error
50
54
}
51
55
52
56
type group struct {
@@ -76,7 +80,7 @@ func init() {
76
80
}
77
81
78
82
func newCollector (cgroupPath string , events PerfEvents , onlineCPUs []int , cpuToSocket map [int ]int ) * collector {
79
- collector := & collector {cgroupPath : cgroupPath , events : events , onlineCPUs : onlineCPUs , cpuFiles : map [int ]group {}, uncore : NewUncoreCollector (cgroupPath , events , cpuToSocket )}
83
+ collector := & collector {cgroupPath : cgroupPath , events : events , onlineCPUs : onlineCPUs , cpuFiles : map [int ]group {}, uncore : NewUncoreCollector (cgroupPath , events , cpuToSocket ), perfEventOpen : unix . PerfEventOpen , ioctlSetInt : unix . IoctlSetInt }
80
84
mapEventsToCustomEvents (collector )
81
85
return collector
82
86
}
@@ -185,44 +189,30 @@ func (c *collector) setup() error {
185
189
c .cpuFilesLock .Lock ()
186
190
defer c .cpuFilesLock .Unlock ()
187
191
cgroupFd := int (cgroup .Fd ())
188
- for i , group := range c .events .Core .Events {
192
+ groupIndex := 0
193
+ for _ , group := range c .events .Core .Events {
189
194
// CPUs file descriptors of group leader needed for perf_event_open.
190
195
leaderFileDescriptors := make (map [int ]int , len (c .onlineCPUs ))
191
196
for _ , cpu := range c .onlineCPUs {
192
197
leaderFileDescriptors [cpu ] = groupLeaderFileDescriptor
193
198
}
194
199
195
- for j , event := range group .events {
196
- // First element is group leader.
197
- isGroupLeader := j == 0
198
- customEvent , ok := c .eventToCustomEvent [event ]
199
- if ok {
200
- config := c .createConfigFromRawEvent (customEvent )
201
- leaderFileDescriptors , err = c .registerEvent (eventInfo {string (customEvent .Name ), config , cgroupFd , i , isGroupLeader }, leaderFileDescriptors )
202
- if err != nil {
203
- return err
204
- }
205
- } else {
206
- config , err := c .createConfigFromEvent (event )
207
- if err != nil {
208
- return err
209
- }
210
- leaderFileDescriptors , err = c .registerEvent (eventInfo {string (event ), config , cgroupFd , i , isGroupLeader }, leaderFileDescriptors )
211
- if err != nil {
212
- return err
213
- }
214
- // Clean memory allocated by C code.
215
- C .free (unsafe .Pointer (config ))
216
- }
200
+ leaderFileDescriptors , err := c .createLeaderFileDescriptors (group .events , cgroupFd , groupIndex , leaderFileDescriptors )
201
+ if err != nil {
202
+ klog .Errorf ("Cannot count perf event group %v: %v" , group .events , err )
203
+ c .deleteGroup (groupIndex )
204
+ continue
205
+ } else {
206
+ groupIndex ++
217
207
}
218
208
219
209
// Group is prepared so we should reset and enable counting.
220
210
for _ , fd := range leaderFileDescriptors {
221
- err = unix . IoctlSetInt (fd , unix .PERF_EVENT_IOC_RESET , 0 )
211
+ err = c . ioctlSetInt (fd , unix .PERF_EVENT_IOC_RESET , 0 )
222
212
if err != nil {
223
213
return err
224
214
}
225
- err = unix . IoctlSetInt (fd , unix .PERF_EVENT_IOC_ENABLE , 0 )
215
+ err = c . ioctlSetInt (fd , unix .PERF_EVENT_IOC_ENABLE , 0 )
226
216
if err != nil {
227
217
return err
228
218
}
@@ -232,6 +222,35 @@ func (c *collector) setup() error {
232
222
return nil
233
223
}
234
224
225
+ func (c * collector ) createLeaderFileDescriptors (events []Event , cgroupFd int , groupIndex int , leaderFileDescriptors map [int ]int ) (map [int ]int , error ) {
226
+ for j , event := range events {
227
+ // First element is group leader.
228
+ isGroupLeader := j == 0
229
+ customEvent , ok := c .eventToCustomEvent [event ]
230
+ var err error
231
+ if ok {
232
+ config := c .createConfigFromRawEvent (customEvent )
233
+ leaderFileDescriptors , err = c .registerEvent (eventInfo {string (customEvent .Name ), config , cgroupFd , groupIndex , isGroupLeader }, leaderFileDescriptors )
234
+ if err != nil {
235
+ return nil , fmt .Errorf ("cannot register perf event: %v" , err )
236
+ }
237
+ } else {
238
+ config , err := c .createConfigFromEvent (event )
239
+ if err != nil {
240
+ return nil , fmt .Errorf ("cannot create config from perf event: %v" , err )
241
+
242
+ }
243
+ leaderFileDescriptors , err = c .registerEvent (eventInfo {string (event ), config , cgroupFd , groupIndex , isGroupLeader }, leaderFileDescriptors )
244
+ if err != nil {
245
+ return nil , fmt .Errorf ("cannot register perf event: %v" , err )
246
+ }
247
+ // Clean memory allocated by C code.
248
+ C .free (unsafe .Pointer (config ))
249
+ }
250
+ }
251
+ return leaderFileDescriptors , nil
252
+ }
253
+
235
254
func readPerfEventAttr (name string , pfmGetOsEventEncoding func (string , unsafe.Pointer ) error ) (* unix.PerfEventAttr , error ) {
236
255
perfEventAttrMemory := C .malloc (C .ulong (unsafe .Sizeof (unix.PerfEventAttr {})))
237
256
// Fill memory with 0 values.
@@ -279,13 +298,13 @@ func (c *collector) registerEvent(event eventInfo, leaderFileDescriptors map[int
279
298
setAttributes (event .config , event .isGroupLeader )
280
299
281
300
for _ , cpu := range c .onlineCPUs {
282
- fd , err := unix . PerfEventOpen (event .config , pid , cpu , leaderFileDescriptors [cpu ], flags )
301
+ fd , err := c . perfEventOpen (event .config , pid , cpu , leaderFileDescriptors [cpu ], flags )
283
302
if err != nil {
284
- return nil , fmt .Errorf ("setting up perf event %#v failed: %q" , event .config , err )
303
+ return leaderFileDescriptors , fmt .Errorf ("setting up perf event %#v failed: %q" , event .config , err )
285
304
}
286
305
perfFile := os .NewFile (uintptr (fd ), event .name )
287
306
if perfFile == nil {
288
- return nil , fmt .Errorf ("unable to create os.File from file descriptor %#v" , fd )
307
+ return leaderFileDescriptors , fmt .Errorf ("unable to create os.File from file descriptor %#v" , fd )
289
308
}
290
309
291
310
c .addEventFile (event .groupIndex , event .name , cpu , perfFile )
@@ -333,6 +352,19 @@ func (c *collector) addEventFile(index int, name string, cpu int, perfFile *os.F
333
352
}
334
353
}
335
354
355
+ func (c * collector ) deleteGroup (index int ) {
356
+ for name , files := range c .cpuFiles [index ].cpuFiles {
357
+ for cpu , file := range files {
358
+ klog .V (5 ).Infof ("Closing perf event file descriptor for cgroup %q, event %q and CPU %d" , c .cgroupPath , name , cpu )
359
+ err := file .Close ()
360
+ if err != nil {
361
+ klog .Warningf ("Unable to close perf event file descriptor for cgroup %q, event %q and CPU %d" , c .cgroupPath , name , cpu )
362
+ }
363
+ }
364
+ }
365
+ delete (c .cpuFiles , index )
366
+ }
367
+
336
368
func createPerfEventAttr (event CustomEvent ) * unix.PerfEventAttr {
337
369
length := len (event .Config )
338
370
@@ -369,17 +401,8 @@ func (c *collector) Destroy() {
369
401
c .cpuFilesLock .Lock ()
370
402
defer c .cpuFilesLock .Unlock ()
371
403
372
- for _ , group := range c .cpuFiles {
373
- for name , files := range group .cpuFiles {
374
- for cpu , file := range files {
375
- klog .V (5 ).Infof ("Closing perf_event file descriptor for cgroup %q, event %q and CPU %d" , c .cgroupPath , name , cpu )
376
- err := file .Close ()
377
- if err != nil {
378
- klog .Warningf ("Unable to close perf_event file descriptor for cgroup %q, event %q and CPU %d" , c .cgroupPath , name , cpu )
379
- }
380
- }
381
- delete (group .cpuFiles , name )
382
- }
404
+ for i := range c .cpuFiles {
405
+ c .deleteGroup (i )
383
406
}
384
407
}
385
408
0 commit comments