mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2026-02-07 13:40:59 +00:00
docs: Fix user-guide/maps.md
This commit is contained in:
@ -33,7 +33,7 @@ def my_map() -> HashMap:
|
|||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
|
|
||||||
* `key` - The type of the key (must be a ctypes type)
|
* `key` - The type of the key (must be a ctypes type or struct)
|
||||||
* `value` - The type of the value (must be a ctypes type or struct)
|
* `value` - The type of the value (must be a ctypes type or struct)
|
||||||
* `max_entries` - Maximum number of entries the map can hold
|
* `max_entries` - Maximum number of entries the map can hold
|
||||||
|
|
||||||
@ -47,11 +47,10 @@ Look up a value by key. Returns the value if found, `None` otherwise.
|
|||||||
@bpf
|
@bpf
|
||||||
@section("tracepoint/syscalls/sys_enter_open")
|
@section("tracepoint/syscalls/sys_enter_open")
|
||||||
def trace_open(ctx: c_void_p) -> c_int64:
|
def trace_open(ctx: c_void_p) -> c_int64:
|
||||||
key = c_uint32(1)
|
value = my_map.lookup(1)
|
||||||
value = my_map.lookup(key)
|
|
||||||
if value:
|
if value:
|
||||||
print(f"Found value: {value}")
|
print(f"Found value: {value}")
|
||||||
return c_int64(0)
|
return 0
|
||||||
```
|
```
|
||||||
|
|
||||||
##### update(key, value, flags=None)
|
##### update(key, value, flags=None)
|
||||||
@ -67,8 +66,8 @@ def track_opens(ctx: c_void_p) -> c_int64:
|
|||||||
if count:
|
if count:
|
||||||
my_map.update(key, count + 1)
|
my_map.update(key, count + 1)
|
||||||
else:
|
else:
|
||||||
my_map.update(key, c_uint64(1))
|
my_map.update(key, 1)
|
||||||
return c_int64(0)
|
return 0
|
||||||
```
|
```
|
||||||
|
|
||||||
##### delete(key)
|
##### delete(key)
|
||||||
@ -78,9 +77,8 @@ Remove an entry from the map.
|
|||||||
```python
|
```python
|
||||||
@bpf
|
@bpf
|
||||||
def cleanup(ctx: c_void_p) -> c_int64:
|
def cleanup(ctx: c_void_p) -> c_int64:
|
||||||
key = c_uint32(1)
|
my_map.delete(1)
|
||||||
my_map.delete(key)
|
return 0
|
||||||
return c_int64(0)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Use Cases
|
#### Use Cases
|
||||||
@ -108,14 +106,14 @@ def process_count() -> HashMap:
|
|||||||
def count_processes(ctx: c_void_p) -> c_int64:
|
def count_processes(ctx: c_void_p) -> c_int64:
|
||||||
process_id = pid()
|
process_id = pid()
|
||||||
count = process_count.lookup(process_id)
|
count = process_count.lookup(process_id)
|
||||||
|
|
||||||
if count:
|
if count:
|
||||||
new_count = count + 1
|
new_count = count + 1
|
||||||
process_count.update(process_id, new_count)
|
process_count.update(process_id, new_count)
|
||||||
else:
|
else:
|
||||||
process_count.update(process_id, c_uint64(1))
|
process_count.update(process_id, 1)
|
||||||
|
|
||||||
return c_int64(0)
|
return 0
|
||||||
|
|
||||||
@bpf
|
@bpf
|
||||||
@bpfglobal
|
@bpfglobal
|
||||||
@ -179,7 +177,7 @@ def send_event(ctx: c_void_p) -> c_int64:
|
|||||||
event.pid = pid()
|
event.pid = pid()
|
||||||
event.timestamp = ktime()
|
event.timestamp = ktime()
|
||||||
events.output(event)
|
events.output(event)
|
||||||
return c_int64(0)
|
return 0
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Use Cases
|
#### Use Cases
|
||||||
@ -215,10 +213,9 @@ def log_exec(ctx: c_void_p) -> c_int64:
|
|||||||
event = ProcessEvent()
|
event = ProcessEvent()
|
||||||
event.timestamp = ktime()
|
event.timestamp = ktime()
|
||||||
event.pid = pid()
|
event.pid = pid()
|
||||||
# Note: comm() requires a buffer parameter
|
comm(event.comm) # Fills event.comm with process name
|
||||||
# comm(event.comm) # Fills event.comm with process name
|
|
||||||
events.output(event)
|
events.output(event)
|
||||||
return c_int64(0)
|
return 0
|
||||||
|
|
||||||
@bpf
|
@bpf
|
||||||
@bpfglobal
|
@bpfglobal
|
||||||
@ -258,7 +255,7 @@ def log_event(ctx: c_void_p) -> c_int64:
|
|||||||
event = Event()
|
event = Event()
|
||||||
event.pid = pid()
|
event.pid = pid()
|
||||||
events.output(event)
|
events.output(event)
|
||||||
return c_int64(0)
|
return 0
|
||||||
```
|
```
|
||||||
|
|
||||||
##### reserve(size)
|
##### reserve(size)
|
||||||
@ -272,7 +269,7 @@ def reserve_space(ctx: c_void_p) -> c_int64:
|
|||||||
if ptr:
|
if ptr:
|
||||||
# Use the reserved space
|
# Use the reserved space
|
||||||
events.submit(ptr)
|
events.submit(ptr)
|
||||||
return c_int64(0)
|
return 0
|
||||||
```
|
```
|
||||||
|
|
||||||
##### submit(data, flags=0)
|
##### submit(data, flags=0)
|
||||||
@ -343,18 +340,18 @@ def process_stats() -> HashMap:
|
|||||||
def track_stats(ctx: c_void_p) -> c_int64:
|
def track_stats(ctx: c_void_p) -> c_int64:
|
||||||
process_id = pid()
|
process_id = pid()
|
||||||
stats = process_stats.lookup(process_id)
|
stats = process_stats.lookup(process_id)
|
||||||
|
|
||||||
if stats:
|
if stats:
|
||||||
stats.count = stats.count + 1
|
stats.count = stats.count + 1
|
||||||
process_stats.update(process_id, stats)
|
process_stats.update(process_id, stats)
|
||||||
else:
|
else:
|
||||||
new_stats = Stats()
|
new_stats = Stats()
|
||||||
new_stats.count = c_uint64(1)
|
new_stats.count = 1
|
||||||
new_stats.total_time = c_uint64(0)
|
new_stats.total_time = 0
|
||||||
new_stats.max_time = c_uint64(0)
|
new_stats.max_time = 0
|
||||||
process_stats.update(process_id, new_stats)
|
process_stats.update(process_id, new_stats)
|
||||||
|
|
||||||
return c_int64(0)
|
return 0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Accessing Maps from Userspace
|
## Accessing Maps from Userspace
|
||||||
@ -392,32 +389,6 @@ map_obj[key] = new_value
|
|||||||
del map_obj[key]
|
del map_obj[key]
|
||||||
```
|
```
|
||||||
|
|
||||||
## Best Practices
|
|
||||||
|
|
||||||
1. **Choose the right map type**
|
|
||||||
* Use `HashMap` for key-value storage
|
|
||||||
* Use `RingBuffer` for event streaming (kernel 5.8+)
|
|
||||||
* Use `PerfEventArray` for older kernels
|
|
||||||
|
|
||||||
2. **Size maps appropriately**
|
|
||||||
* Consider maximum expected entries
|
|
||||||
* Balance memory usage vs. capacity
|
|
||||||
* Use LRU maps for automatic eviction
|
|
||||||
|
|
||||||
3. **Handle lookup failures**
|
|
||||||
* Always check if `lookup()` returns `None`
|
|
||||||
* Initialize new entries properly
|
|
||||||
|
|
||||||
4. **Minimize map operations**
|
|
||||||
* BPF has instruction limits
|
|
||||||
* Reduce unnecessary lookups
|
|
||||||
* Batch operations when possible
|
|
||||||
|
|
||||||
5. **Use structs for complex data**
|
|
||||||
* More efficient than multiple lookups
|
|
||||||
* Atomic updates of related fields
|
|
||||||
* Better cache locality
|
|
||||||
|
|
||||||
## Common Patterns
|
## Common Patterns
|
||||||
|
|
||||||
### Counter Pattern
|
### Counter Pattern
|
||||||
@ -427,7 +398,7 @@ count = my_map.lookup(key)
|
|||||||
if count:
|
if count:
|
||||||
my_map.update(key, count + 1)
|
my_map.update(key, count + 1)
|
||||||
else:
|
else:
|
||||||
my_map.update(key, c_uint64(1))
|
my_map.update(key, 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Latency Tracking
|
### Latency Tracking
|
||||||
@ -452,7 +423,7 @@ if start_time:
|
|||||||
count = counter.lookup(key)
|
count = counter.lookup(key)
|
||||||
if count and (count % 100) == 0:
|
if count and (count % 100) == 0:
|
||||||
events.output(data)
|
events.output(data)
|
||||||
counter.update(key, count + 1 if count else c_uint64(1))
|
counter.update(key, count + 1 if count else 1)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
@ -476,7 +447,6 @@ If updates fail due to map being full:
|
|||||||
If you get type-related errors:
|
If you get type-related errors:
|
||||||
* Verify key and value types match the definition
|
* Verify key and value types match the definition
|
||||||
* Check that structs are properly defined
|
* Check that structs are properly defined
|
||||||
* Ensure ctypes are used correctly
|
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user