optimised the percpu support patch.
authorZaafar Ahmed <zaafar.tahir@gmail.com>
Tue, 29 Mar 2016 17:13:50 +0000 (22:13 +0500)
committerZaafar Ahmed <zaafar.tahir@gmail.com>
Tue, 29 Mar 2016 17:13:50 +0000 (22:13 +0500)
removed kernel checks.

src/cc/frontends/clang/b_frontend_action.cc
src/python/bcc/__init__.py
src/python/bcc/table.py

index 1ba30cb..358a894 100644 (file)
@@ -571,11 +571,9 @@ bool BTypeVisitor::VisitVarDecl(VarDecl *Decl) {
     } else if (A->getName() == "maps/array") {
       map_type = BPF_MAP_TYPE_ARRAY;
     } else if (A->getName() == "maps/pc_hash") {
-      if (KERNEL_VERSION(major,minor,0) >= KERNEL_VERSION(4,5,0))
-        map_type = BPF_MAP_TYPE_PERCPU_HASH;
+      map_type = BPF_MAP_TYPE_PERCPU_HASH;
     } else if (A->getName() == "maps/pc_array") {
-      if (KERNEL_VERSION(major,minor,0) >= KERNEL_VERSION(4,5,0))
-        map_type = BPF_MAP_TYPE_PERCPU_ARRAY;
+      map_type = BPF_MAP_TYPE_PERCPU_ARRAY;
     } else if (A->getName() == "maps/histogram") {
       if (table.key_desc == "\"int\"")
         map_type = BPF_MAP_TYPE_ARRAY;
index a286f26..0da5632 100644 (file)
@@ -228,7 +228,7 @@ class BPF(object):
         cls = type(str(desc[0]), (base,), dict(_fields_=fields))
         return cls
 
-    def get_table(self, name, keytype=None, leaftype=None, func_reducer=None):
+    def get_table(self, name, keytype=None, leaftype=None, reducer=None):
         map_id = lib.bpf_table_id(self.module, name.encode("ascii"))
         map_fd = lib.bpf_table_fd(self.module, name.encode("ascii"))
         if map_fd < 0:
@@ -243,7 +243,7 @@ class BPF(object):
             if not leaf_desc:
                 raise Exception("Failed to load BPF Table %s leaf desc" % name)
             leaftype = BPF._decode_table_type(json.loads(leaf_desc.decode()))
-        return Table(self, map_id, map_fd, keytype, leaftype, func_reducer)
+        return Table(self, map_id, map_fd, keytype, leaftype, reducer=reducer)
 
     def __getitem__(self, key):
         if key not in self.tables:
index f1c317d..47d5227 100644 (file)
@@ -74,8 +74,8 @@ def _print_log2_hist(vals, val_type):
                       _stars(val, val_max, stars)))
 
 
-def Table(bpf, map_id, map_fd, keytype, leaftype, func_reducer):
-    """Table(bpf, map_id, map_fd, keytype, leaftype, func_reducer)
+def Table(bpf, map_id, map_fd, keytype, leaftype, **kwargs):
+    """Table(bpf, map_id, map_fd, keytype, leaftype, **kwargs)
 
     Create a python object out of a reference to a bpf table handle"""
 
@@ -90,11 +90,9 @@ def Table(bpf, map_id, map_fd, keytype, leaftype, func_reducer):
     elif ttype == BPF_MAP_TYPE_PERF_EVENT_ARRAY:
         t = PerfEventArray(bpf, map_id, map_fd, keytype, leaftype)
     elif ttype == BPF_MAP_TYPE_PERCPU_HASH:
-        t = PerCpuHash(bpf, map_id, map_fd, keytype,
-                            leaftype, func=func_reducer)
+        t = PerCpuHash(bpf, map_id, map_fd, keytype, leaftype, **kwargs)
     elif ttype == BPF_MAP_TYPE_PERCPU_ARRAY:
-        t = PerCpuArray(bpf, map_id, map_fd, keytype,
-                            leaftype, func=func_reducer)
+        t = PerCpuArray(bpf, map_id, map_fd, keytype, leaftype, **kwargs)
     elif ttype == BPF_MAP_TYPE_STACK_TRACE:
         t = StackTrace(bpf, map_id, map_fd, keytype, leaftype)
     if t == None:
@@ -149,9 +147,9 @@ class TableBase(MutableMapping):
             raise Exception("Could not scanf leaf")
         return leaf
 
-    def __getitem__(self, key, leaf=None):
+    def __getitem__(self, key):
         key_p = ct.pointer(key)
-        if not leaf: leaf = self.Leaf()
+        leaf = self.Leaf()
         leaf_p = ct.pointer(leaf)
         res = lib.bpf_lookup_elem(self.map_fd,
                 ct.cast(key_p, ct.c_void_p),
@@ -312,9 +310,9 @@ class ArrayBase(TableBase):
     def __len__(self):
         return self.max_entries
 
-    def __getitem__(self, key, leaf=None):
+    def __getitem__(self, key):
         key = self._normalize_key(key)
-        return super(ArrayBase, self).__getitem__(key, leaf)
+        return super(ArrayBase, self).__getitem__(key)
 
     def __setitem__(self, key, leaf):
         key = self._normalize_key(key)
@@ -408,127 +406,121 @@ class PerfEventArray(ArrayBase):
 
 class PerCpuHash(HashTable):
     def __init__(self, *args, **kwargs):
-        self.func_reducer = kwargs['func']
-        del kwargs['func']
-        self.total_cpu = multiprocessing.cpu_count()
-        self.alignment = int(check_output(["grep", "-m", "1", "cache_alignment", "/proc/cpuinfo"]).split(' ', 2)[1])/8
+        self.reducer = kwargs["reducer"]
+        del kwargs["reducer"]
         super(PerCpuHash, self).__init__(*args, **kwargs)
-        self.leafsize = ct.sizeof(self.Leaf)
-        if isinstance(self.Leaf(), ct.Structure) and self.leafsize % self.alignment is not 0:
-            # Struct that are not aligned to cache.
-            raise IndexError("Struct must be aligned to %s, please add some padding" % self.alignment)
+        self.sLeaf = self.Leaf
+        self.total_cpu = multiprocessing.cpu_count()
+        # This needs to be 8 as hard coded into the linux kernel.
+        self.alignment = ct.sizeof(self.sLeaf) % 8
+        if self.alignment is 0:
+            self.Leaf = self.sLeaf * self.total_cpu
+        else:
+            # Currently Float, Char, un-aligned structs are not supported
+            if self.sLeaf == ct.c_uint:
+                self.Leaf = ct.c_uint64 * self.total_cpu
+            elif self.sLeaf == ct.c_int:
+                self.Leaf = ct.c_int64 * self.total_cpu
+            else:
+                raise IndexError("Leaf must be aligned to 8 bytes")
 
     def __getitem__(self, key):
-        if self.leafsize % self.alignment is 0:
-            # Struct/DataTypes that are aligned to cache
-            leaf_arr = (self.Leaf * self.total_cpu)()
+        result = super(PerCpuHash, self).__getitem__(key)
+        if self.alignment is 0:
+            ret = result
         else:
-            # DataTypes that are not aligned to cache
-            leaf_arr = (ct.c_uint64 * self.total_cpu)()
-
-        if (self.func_reducer):
-            super(PerCpuHash, self).__getitem__(key, leaf_arr)
-            leaf_ret = (self.Leaf * self.total_cpu)()
+            ret = (self.sLeaf * self.total_cpu)()
             for i in range(0, self.total_cpu):
-                leaf_ret[i] = leaf_arr[i]
-            return reduce(self.func_reducer, leaf_ret)
+                ret[i] = result[i]
+        if (self.reducer):
+            return reduce(self.reducer, ret)
         else:
-            super(PerCpuHash,self).__getitem__(key,leaf_arr)
-            leaf_ret = (self.Leaf * self.total_cpu)()
-            for i in range(0, self.total_cpu):
-                leaf_ret[i] = leaf_arr[i]
-            return leaf_ret
+            return ret
 
     def __setitem__(self, key, leaf):
-        if self.leafsize % self.alignment is 0:
-            leaf_arr = (self.Leaf * self.total_cpu)()
-            for i in range(0, self.total_cpu):
-                leaf_arr[i] = leaf
-        else:
-            leaf_arr = (ct.c_uint64 * self.total_cpu)()
-            for i in range(0, self.total_cpu):
-                leaf_arr[i] = leaf.value
-        super(PerCpuHash, self).__setitem__(key, leaf_arr)
+        super(PerCpuHash, self).__setitem__(key, leaf)
 
     def sum(self, key):
         if isinstance(self.Leaf(), ct.Structure):
             raise IndexError("Leaf must be an integer type for default sum functions")
-        leaf_arr = (ct.c_uint64 * self.total_cpu)()
-        return self.Leaf(reduce(lambda x,y: x+y, super(PerCpuHash, self).__getitem__(key, leaf_arr)))
+        temp = self.reducer
+        self.reducer = None
+        result = self.__getitem__(key)
+        self.reducer = temp
+        return self.sLeaf(reduce(lambda x,y: x+y, result))
 
     def max(self, key):
         if isinstance(self.Leaf(), ct.Structure):
-            raise IndexError("Leaf must be an integer type for default sum functions")
-        leaf_arr = (ct.c_uint64 * self.total_cpu)()
-        return self.Leaf(max(super(PerCpuHash, self).__getitem__(key, leaf_arr)))
+            raise IndexError("Leaf must be an integer type for default max functions")
+        temp = self.reducer
+        self.reducer = None
+        result = self.__getitem__(key)
+        self.reducer = temp
+        return self.sLeaf(max(result))
 
     def average(self, key):
-        if isinstance(self.Leaf(), ct.Structure):
-            raise IndexError("Leaf must be an integer type for default sum functions")
-        leaf_arr = (ct.c_uint64 * self.total_cpu)()
-        return self.Leaf(reduce(lambda x,y: x+y, super(PerCpuHash, self).__getitem__(key, leaf_arr))/self.total_cpu)
+        result = self.sum(key)
+        result.value/=self.total_cpu
+        return result
 
 class PerCpuArray(ArrayBase):
     def __init__(self, *args, **kwargs):
-        self.func_reducer = kwargs['func']
-        del kwargs['func']
-        self.total_cpu = multiprocessing.cpu_count()
-        self.alignment = int(check_output(["grep", "-m", "1", "cache_alignment", "/proc/cpuinfo"]).split(' ', 2)[1])/8
+        self.reducer = kwargs["reducer"]
+        del kwargs["reducer"]
         super(PerCpuArray, self).__init__(*args, **kwargs)
-        self.leafsize = ct.sizeof(self.Leaf)
-        if isinstance(self.Leaf(), ct.Structure) and self.leafsize % self.alignment is not 0:
-            # Struct that are not aligned to cache.
-            raise IndexError("Struct must be aligned to %s, please add some padding" % self.alignment)
+        self.sLeaf = self.Leaf
+        self.total_cpu = multiprocessing.cpu_count()
+        # This needs to be 8 as hard coded into the linux kernel.
+        self.alignment = ct.sizeof(self.sLeaf) % 8
+        if self.alignment is 0:
+            self.Leaf = self.sLeaf * self.total_cpu
+        else:
+            # Currently Float, Char, un-aligned structs are not supported
+            if self.sLeaf == ct.c_uint:
+                self.Leaf = ct.c_uint64 * self.total_cpu
+            elif self.sLeaf == ct.c_int:
+                self.Leaf = ct.c_int64 * self.total_cpu
+            else:
+                raise IndexError("Leaf must be aligned to 8 bytes")
 
     def __getitem__(self, key):
-        if self.leafsize % self.alignment is 0:
-            # Struct/DataTypes that are aligned to cache
-            leaf_arr = (self.Leaf * self.total_cpu)()
+        result = super(PerCpuArray, self).__getitem__(key)
+        if self.alignment is 0:
+            ret = result
         else:
-            # DataTypes that are not aligned to cache
-            leaf_arr = (ct.c_uint64 * self.total_cpu)()
-
-        if (self.func_reducer):
-            super(PerCpuArray, self).__getitem__(key, leaf_arr)
-            leaf_ret = (self.Leaf * self.total_cpu)()
+            ret = (self.sLeaf * self.total_cpu)()
             for i in range(0, self.total_cpu):
-                leaf_ret[i] = leaf_arr[i]
-            return reduce(self.func_reducer, leaf_ret)
+                ret[i] = result[i]
+        if (self.reducer):
+            return reduce(self.reducer, ret)
         else:
-            super(PerCpuArray,self).__getitem__(key,leaf_arr)
-            leaf_ret = (self.Leaf * self.total_cpu)()
-            for i in range(0, self.total_cpu):
-                leaf_ret[i] = leaf_arr[i]
-            return leaf_ret
+            return ret
 
     def __setitem__(self, key, leaf):
-        if self.leafsize % self.alignment is 0:
-            leaf_arr = (self.Leaf * self.total_cpu)()
-            for i in range(0, self.total_cpu):
-                leaf_arr[i] = leaf
-        else:
-            leaf_arr = (ct.c_uint64 * self.total_cpu)()
-            for i in range(0, self.total_cpu):
-                leaf_arr[i] = leaf.value
-        super(PerCpuArray, self).__setitem__(key, leaf_arr)
+        super(PerCpuArray, self).__setitem__(key, leaf)
 
     def sum(self, key):
         if isinstance(self.Leaf(), ct.Structure):
             raise IndexError("Leaf must be an integer type for default sum functions")
-        leaf_arr = (ct.c_uint64 * self.total_cpu)()
-        return self.Leaf(reduce(lambda x,y: x+y, super(PerCpuArray, self).__getitem__(key, leaf_arr)))
+        temp = self.reducer
+        self.reducer = None
+        result = self.__getitem__(key)
+        self.reducer = temp
+        return self.sLeaf(reduce(lambda x,y: x+y, result))
 
     def max(self, key):
         if isinstance(self.Leaf(), ct.Structure):
-            raise IndexError("Leaf must be an integer type for default sum functions")
-        leaf_arr = (ct.c_uint64 * self.total_cpu)()
-        return self.Leaf(max(super(PerCpuArray, self).__getitem__(key, leaf_arr)))
+            raise IndexError("Leaf must be an integer type for default max functions")
+        temp = self.reducer
+        self.reducer = None
+        result = self.__getitem__(key)
+        self.reducer = temp
+        return self.sLeaf(max(result))
 
     def average(self, key):
-        if isinstance(self.Leaf(), ct.Structure):
-            raise IndexError("Leaf must be an integer type for default sum functions")
-        leaf_arr = (ct.c_uint64 * self.total_cpu)()
-        return self.Leaf(reduce(lambda x,y: x+y, super(PerCpuArray, self).__getitem__(key, leaf_arr))/self.total_cpu)
+        result = self.sum(key)
+        result.value/=self.total_cpu
+        return result
 
 class StackTrace(TableBase):
     def __init__(self, *args, **kwargs):