Skip to content

Commit

Permalink
bcc: Fix hash table batch operation attribute error
Browse files Browse the repository at this point in the history
Some tools get errors when kernel supports hash table batch operations
and hash key or value is integer type.

  AttributeError: 'long' object has no attribute 'value'

It's caused by ctypes library from python. For example, when hash tables
try to do batch lookup, it will alloc arrays to stores keys and values
first. If it is a ctypes integer type, after expanding to array, type of
element will be changed to python 'long' or 'int'. When trying to access
its value attribute, error message is generated.

  >>> from ctypes import *
  >>> a = c_uint(10)
  >>> type(a)
  <class 'ctypes.c_uint'>
  >>> a.value
  10
  >>> b = (c_uint * 1)(10)
  >>> type(b)
  <class '__main__.c_uint_Array_1'>
  >>> b[0].value
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  AttributeError: 'int' object has no attribute 'value'

Turn back to original ctypes type can avoid this error.

Change-Id: Ia8598510e79ec9a3b73de3e343b9781c97ead894
Signed-off-by: mickey_zhu <[email protected]>
  • Loading branch information
michael-chuh authored and yonghong-song committed Jun 20, 2023
1 parent 5c92af6 commit 82469ea
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 11 deletions.
8 changes: 7 additions & 1 deletion src/python/bcc/table.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,13 @@ def _items_lookup_and_optionally_delete_batch(self, delete=True):
break

for i in range(0, total):
yield (ct_keys[i], ct_values[i])
k = ct_keys[i]
v = ct_values[i]
if not isinstance(k, ct.Structure):
k = self.Key(k)
if not isinstance(v, ct.Structure):
v = self.Leaf(v)
yield (k, v)

def zero(self):
# Even though this is not very efficient, we grab the entire list of
Expand Down
23 changes: 13 additions & 10 deletions tests/python/test_map_batch_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ def prepare_keys_subset(self, hmap, count=None):
count = self.SUBSET_SIZE
keys = (hmap.Key * count)()
i = 0
for k, _ in sorted(hmap.items_lookup_batch()):
for k, _ in sorted(hmap.items_lookup_batch(), key=lambda k:k[0].value):
if i < count:
keys[i] = k
keys[i] = k.value
i += 1
else:
break
Expand All @@ -45,19 +45,19 @@ def prepare_values_subset(self, hmap, count=None):
count = self.SUBSET_SIZE
values = (hmap.Leaf * count)()
i = 0
for _, v in sorted(hmap.items_lookup_batch()):
for _, v in sorted(hmap.items_lookup_batch(), key=lambda k:k[0].value):
if i < count:
values[i] = v*v
values[i] = v.value * v.value
i += 1
else:
break
return values

def check_hashmap_values(self, it):
i = 0
for k, v in sorted(it):
self.assertEqual(k, i)
self.assertEqual(v, i)
for k, v in sorted(it, key=lambda kv:kv[0].value):
self.assertEqual(k.value, i)
self.assertEqual(v.value, i)
i += 1
return i

Expand Down Expand Up @@ -129,12 +129,15 @@ def test_update_batch_subset(self):
# the first self.SUBSET_SIZE keys follow this rule value = keys * keys
# the remaning keys follow this rule : value = keys
i = 0
for k, v in sorted(hmap.items_lookup_batch()):
for k, v in sorted(hmap.items_lookup_batch(),
key=lambda kv:kv[0].value):
if i < self.SUBSET_SIZE:
self.assertEqual(v, k*k) # values are the square of the keys
# values are the square of the keys
self.assertEqual(v.value, k.value * k.value)
i += 1
else:
self.assertEqual(v, k) # values = keys
# values = keys
self.assertEqual(v.value, k.value)

self.assertEqual(i, self.SUBSET_SIZE)

Expand Down

0 comments on commit 82469ea

Please sign in to comment.