class RbBCC::PerfEventArray

Public Class Methods

new(bpf, map_id, map_fd, keytype, leaftype, name: nil) click to toggle source
Calls superclass method RbBCC::TableBase::new
# File lib/rbbcc/table.rb, line 263
def initialize(bpf, map_id, map_fd, keytype, leaftype, name: nil)
  super
  @open_key_fds = {}
  @event_class = nil
  @_cbs = {}
  @_open_key_fds = {}
end

Public Instance Methods

event(data) click to toggle source
# File lib/rbbcc/table.rb, line 271
def event(data)
  @event_class ||= get_event_class
  ev = @event_class.malloc
  Fiddle::Pointer.new(ev.to_ptr)[0, @event_class.size] = data[0, @event_class.size]
  return ev
end
open_perf_buffer(page_cnt: 8, lost_cb: nil, &callback) click to toggle source
# File lib/rbbcc/table.rb, line 278
def open_perf_buffer(page_cnt: 8, lost_cb: nil, &callback)
  if page_cnt & (page_cnt - 1) != 0
    raise "Perf buffer page_cnt must be a power of two"
  end

  get_online_cpus.each do |i|
    _open_perf_buffer(i, callback, page_cnt, lost_cb)
  end
end

Private Instance Methods

_open_perf_buffer(cpu, callback, page_cnt, lost_cb) click to toggle source
# File lib/rbbcc/table.rb, line 342
def _open_perf_buffer(cpu, callback, page_cnt, lost_cb)
  # bind("void raw_cb_callback(void *, void *, int)")
  fn = Fiddle::Closure::BlockCaller.new(
    Fiddle::TYPE_VOID,
    [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT]
  ) do |_dummy, data, size|
    begin
      callback.call(cpu, data, size)
    rescue => e
      if Fiddle.last_error == 32 # EPIPE
        exit
      else
        raise e
      end
    end
  end
  lost_fn = Fiddle::Closure::BlockCaller.new(
    Fiddle::TYPE_VOID,
    [Fiddle::TYPE_VOIDP, Fiddle::TYPE_ULONG]
  ) do |_dummy, lost|
    begin
      lost_cb(lost)
    rescue => e
      if Fiddle.last_error == 32 # EPIPE
        exit
      else
        raise e
      end
    end
  end if lost_cb
  reader = Clib.bpf_open_perf_buffer(fn, lost_fn, nil, -1, cpu, page_cnt)
  if !reader || reader.null?
    raise "Could not open perf buffer"
  end
  fd = Clib.perf_reader_fd(reader)

  self[byref(cpu, @keysize)] = byref(fd, @leafsize)
  self.bpf.perf_buffers[[object_id, cpu]] = reader
  @_cbs[cpu] = [fn, lost_fn]
  @_open_key_fds[cpu] = -1
end
get_event_class() click to toggle source
Calls superclass method
# File lib/rbbcc/table.rb, line 289
def get_event_class
  ct_mapping = {
    's8': 'char',
    'u8': 'unsined char',
    's8 *': 'char *',
    's16': 'short',
    'u16': 'unsigned short',
    's32': 'int',
    'u32': 'unsigned int',
    's64': 'long long',
    'u64': 'unsigned long long'
  }

  array_type = /(.+) \[([0-9]+)\]$/
  fields = []
  num_fields = Clib.bpf_perf_event_fields(self.bpf.module, @name)
  num_fields.times do |i|
    field = Clib.__extract_char(Clib.bpf_perf_event_field(self.bpf.module, @name, i))
    field_name, field_type = *field.split('#')
    if field_type =~ /enum .*/
      field_type = "int" #it is indeed enum...
    end
    if _field_type = ct_mapping[field_type.to_sym]
      field_type = _field_type
    end

    m = array_type.match(field_type)
    if m
      field_type = "#{m[1]}[#{m[2]}]"
      fields << [field_type, field_name].join(" ")
    else
      fields << [field_type, field_name].join(" ")
    end
  end
  klass = Fiddle::Importer.struct(fields)
  char_ps = fields.select {|f| f =~ /^char\[(\d+)\] ([_a-zA-Z0-9]+)/ }
  unless char_ps.empty?
    m = Module.new do
      char_ps.each do |char_p|
        md = /^char\[(\d+)\] ([_a-zA-Z0-9]+)/.match(char_p)
        define_method md[2] do
          # Split the char[] in the place where the first \0 appears
          raw = super()
          raw = raw[0...raw.index(0)] if raw.index(0)
          raw.pack("c*")
        end
      end
    end
    klass.prepend m
  end
  klass
end