@@ -393,6 +393,58 @@ func (bpf *Module) AttachPerfEvent(evType, evConfig int, samplePeriod int, sampl
393393 return nil
394394}
395395
396+ // OpenPerfEvent attaches perf events, describe by parameters `typ` and `config`, to a Table.
397+ // The described perf event counters can be fetched in `BPF_PERF_ARRAY` that the Table is associated with.
398+ // a typical invocation process is as the following
399+ // in BPF program:
400+ // BPF_PERF_ARRAY(cpu_cycles, NUM_CPUS);
401+ // ...
402+ // u64 val = cpu_cycles.perf_read(CUR_CPU_IDENTIFIER);
403+ // In go program:
404+ // evType := unix.PERF_TYPE_HARDWARE
405+ // evConfig := unix.PERF_COUNT_HW_CPU_CYCLES
406+ // t := bpf.NewTable(m.TableId("cpu_cycles"), m)
407+ // if t != nil { return bpf.OpenPerfEvent(t, evType, evConfig) }
408+ func (bpf * Module ) OpenPerfEvent (table * bpf.Table , typ , config int ) error {
409+ // the perf key is different from those used by `AttachPerfEvent`
410+ perfKey := fmt .Sprintf ("perf:%d:%d" , typ , config )
411+ if _ , ok := bpf .perfEvents [perfKey ]; ok {
412+ return nil
413+ }
414+
415+ cpus , err := cpuonline .Get ()
416+ if err != nil {
417+ return fmt .Errorf ("failed to determine online cpus: %v" , err )
418+ }
419+ keySize := table .Config ()["key_size" ].(uint64 )
420+ leafSize := table .Config ()["leaf_size" ].(uint64 )
421+
422+ if keySize != 4 || leafSize != 4 {
423+ return fmt .Errorf ("passed table has wrong size" )
424+ }
425+
426+ res := []int {}
427+
428+ for _ , i := range cpus {
429+ fd , err := C .bpf_open_perf_event (C .uint (typ ), C .ulong (config ), C .int (- 1 ), C .int (i ))
430+ if fd < 0 {
431+ return fmt .Errorf ("failed to open bpf perf event: %v" , err )
432+ }
433+ key := make ([]byte , keySize )
434+ leaf := make ([]byte , leafSize )
435+ byteOrder .PutUint32 (key , uint32 (i ))
436+ byteOrder .PutUint32 (leaf , uint32 (fd ))
437+ keyP := unsafe .Pointer (& key [0 ])
438+ leafP := unsafe .Pointer (& leaf [0 ])
439+ table .SetP (keyP , leafP )
440+ res = append (res , int (fd ))
441+ }
442+
443+ bpf .perfEvents [perfKey ] = res
444+
445+ return nil
446+ }
447+
396448// AttachUprobe attaches a uprobe fd to the symbol in the library or binary 'name'
397449// The 'name' argument can be given as either a full library path (/usr/lib/..),
398450// a library without the lib prefix, or as a binary with full path (/bin/bash)
0 commit comments