mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2025-12-31 21:06:25 +00:00
421 lines
49 KiB
Plaintext
421 lines
49 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "22dd4e7b-2ea2-49cb-a8d5-1da108c10034",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import time\n",
|
|
"\n",
|
|
"from pythonbpf import *\n",
|
|
"from pylibbpf import *\n",
|
|
"\n",
|
|
"from ctypes import c_void_p, c_int64, c_uint64, c_int32\n",
|
|
"import matplotlib.pyplot as plt"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "ac7a07bf-440f-41e2-bec8-95f520f9cd53",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Module(\n",
|
|
" body=[\n",
|
|
" FunctionDef(\n",
|
|
" name='hist',\n",
|
|
" args=arguments(\n",
|
|
" posonlyargs=[],\n",
|
|
" args=[],\n",
|
|
" kwonlyargs=[],\n",
|
|
" kw_defaults=[],\n",
|
|
" defaults=[]),\n",
|
|
" body=[\n",
|
|
" Return(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='HashMap', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[\n",
|
|
" keyword(\n",
|
|
" arg='key',\n",
|
|
" value=Name(id='c_int32', ctx=Load())),\n",
|
|
" keyword(\n",
|
|
" arg='value',\n",
|
|
" value=Name(id='c_uint64', ctx=Load())),\n",
|
|
" keyword(\n",
|
|
" arg='max_entries',\n",
|
|
" value=Constant(value=4096))]))],\n",
|
|
" decorator_list=[\n",
|
|
" Name(id='bpf', ctx=Load()),\n",
|
|
" Name(id='map', ctx=Load())],\n",
|
|
" returns=Name(id='HashMap', ctx=Load()),\n",
|
|
" type_params=[]),\n",
|
|
" FunctionDef(\n",
|
|
" name='hello',\n",
|
|
" args=arguments(\n",
|
|
" posonlyargs=[],\n",
|
|
" args=[\n",
|
|
" arg(\n",
|
|
" arg='ctx',\n",
|
|
" annotation=Name(id='c_void_p', ctx=Load()))],\n",
|
|
" kwonlyargs=[],\n",
|
|
" kw_defaults=[],\n",
|
|
" defaults=[]),\n",
|
|
" body=[\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='process_id', ctx=Store())],\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='pid', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[])),\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='one', ctx=Store())],\n",
|
|
" value=Constant(value=1)),\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='prev', ctx=Store())],\n",
|
|
" value=Call(\n",
|
|
" func=Attribute(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='hist', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]),\n",
|
|
" attr='lookup',\n",
|
|
" ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Name(id='process_id', ctx=Load())],\n",
|
|
" keywords=[])),\n",
|
|
" If(\n",
|
|
" test=Name(id='prev', ctx=Load()),\n",
|
|
" body=[\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='previous_value', ctx=Store())],\n",
|
|
" value=BinOp(\n",
|
|
" left=Name(id='prev', ctx=Load()),\n",
|
|
" op=Add(),\n",
|
|
" right=Constant(value=1))),\n",
|
|
" Expr(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='print', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" JoinedStr(\n",
|
|
" values=[\n",
|
|
" Constant(value='count: '),\n",
|
|
" FormattedValue(\n",
|
|
" value=Name(id='previous_value', ctx=Load()),\n",
|
|
" conversion=-1),\n",
|
|
" Constant(value=' with '),\n",
|
|
" FormattedValue(\n",
|
|
" value=Name(id='process_id', ctx=Load()),\n",
|
|
" conversion=-1)])],\n",
|
|
" keywords=[])),\n",
|
|
" Expr(\n",
|
|
" value=Call(\n",
|
|
" func=Attribute(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='hist', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]),\n",
|
|
" attr='update',\n",
|
|
" ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Name(id='process_id', ctx=Load()),\n",
|
|
" Name(id='previous_value', ctx=Load())],\n",
|
|
" keywords=[])),\n",
|
|
" Return(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='c_int64', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Constant(value=0)],\n",
|
|
" keywords=[]))],\n",
|
|
" orelse=[\n",
|
|
" Expr(\n",
|
|
" value=Call(\n",
|
|
" func=Attribute(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='hist', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]),\n",
|
|
" attr='update',\n",
|
|
" ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Name(id='process_id', ctx=Load()),\n",
|
|
" Name(id='one', ctx=Load())],\n",
|
|
" keywords=[]))]),\n",
|
|
" Return(\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='c_int64', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Constant(value=0)],\n",
|
|
" keywords=[]))],\n",
|
|
" decorator_list=[\n",
|
|
" Name(id='bpf', ctx=Load()),\n",
|
|
" Call(\n",
|
|
" func=Name(id='section', ctx=Load()),\n",
|
|
" args=[\n",
|
|
" Constant(value='tracepoint/syscalls/sys_enter_clone')],\n",
|
|
" keywords=[])],\n",
|
|
" returns=Name(id='c_int64', ctx=Load()),\n",
|
|
" type_params=[]),\n",
|
|
" FunctionDef(\n",
|
|
" name='LICENSE',\n",
|
|
" args=arguments(\n",
|
|
" posonlyargs=[],\n",
|
|
" args=[],\n",
|
|
" kwonlyargs=[],\n",
|
|
" kw_defaults=[],\n",
|
|
" defaults=[]),\n",
|
|
" body=[\n",
|
|
" Return(\n",
|
|
" value=Constant(value='GPL'))],\n",
|
|
" decorator_list=[\n",
|
|
" Name(id='bpf', ctx=Load()),\n",
|
|
" Name(id='bpfglobal', ctx=Load())],\n",
|
|
" returns=Name(id='str', ctx=Load()),\n",
|
|
" type_params=[]),\n",
|
|
" Assign(\n",
|
|
" targets=[\n",
|
|
" Name(id='b', ctx=Store())],\n",
|
|
" value=Call(\n",
|
|
" func=Name(id='BPF', ctx=Load()),\n",
|
|
" args=[],\n",
|
|
" keywords=[]))],\n",
|
|
" type_ignores=[])\n",
|
|
"Found BPF function/struct: hist\n",
|
|
"Found BPF function/struct: hello\n",
|
|
"Found BPF function/struct: LICENSE\n",
|
|
"Found BPF map: hist\n",
|
|
"Processing BPF map: hist\n",
|
|
"Creating HashMap map: hist\n",
|
|
"Map parameters: {'type': 'HASH', 'key': 'c_int32', 'value': 'c_uint64', 'max_entries': 4096}\n",
|
|
"Created BPF map: hist\n",
|
|
"Found probe_string of hello: tracepoint/syscalls/sys_enter_clone\n",
|
|
"Pre-allocated variable process_id for helper\n",
|
|
"Pre-allocated variable one of type c_int64\n",
|
|
"Pre-allocated variable prev for map\n",
|
|
"Pre-allocated variable previous_value of type c_int64\n",
|
|
"Local symbol table: dict_keys(['process_id', 'one', 'prev', 'previous_value'])\n",
|
|
"Processing statement: Assign(targets=[Name(id='process_id', ctx=Store())], value=Call(func=Name(id='pid', ctx=Load()), args=[], keywords=[]))\n",
|
|
"Handling assignment to Name(id='process_id', ctx=Store())\n",
|
|
"Assignment call type: pid\n",
|
|
"{}\n",
|
|
"Assigned constant pid to process_id\n",
|
|
"Processing statement: Assign(targets=[Name(id='one', ctx=Store())], value=Constant(value=1))\n",
|
|
"Handling assignment to Name(id='one', ctx=Store())\n",
|
|
"Assigned constant 1 to one\n",
|
|
"Processing statement: Assign(targets=[Name(id='prev', ctx=Store())], value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='lookup', ctx=Load()), args=[Name(id='process_id', ctx=Load())], keywords=[]))\n",
|
|
"Handling assignment to Name(id='prev', ctx=Store())\n",
|
|
"Assignment call attribute: Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='lookup', ctx=Load())\n",
|
|
"{}\n",
|
|
"{}\n",
|
|
"Processing statement: If(test=Name(id='prev', ctx=Load()), body=[Assign(targets=[Name(id='previous_value', ctx=Store())], value=BinOp(left=Name(id='prev', ctx=Load()), op=Add(), right=Constant(value=1))), Expr(value=Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[])), Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[])), Return(value=Call(func=Name(id='c_int64', ctx=Load()), args=[Constant(value=0)], keywords=[]))], orelse=[Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[]))])\n",
|
|
"Handling if statement\n",
|
|
"Processing statement: Assign(targets=[Name(id='previous_value', ctx=Store())], value=BinOp(left=Name(id='prev', ctx=Load()), op=Add(), right=Constant(value=1)))\n",
|
|
"Handling assignment to Name(id='previous_value', ctx=Store())\n",
|
|
"; ModuleID = \"/tmp/tmpf9jfb5h5.py\"\n",
|
|
"target triple = \"bpf\"\n",
|
|
"target datalayout = \"e-m:e-p:64:64-i64:64-i128:128-n32:64-S128\"\n",
|
|
"\n",
|
|
"@\"hist\" = dso_local global {ptr, ptr, ptr, ptr} zeroinitializer, section \".maps\", align 8, !dbg !22\n",
|
|
"define dso_local i64 @\"hello\"(ptr nocapture %\".1\") noinline nounwind optnone section \"tracepoint/syscalls/sys_enter_clone\"\n",
|
|
"{\n",
|
|
"entry:\n",
|
|
" %\"process_id\" = alloca i64, align 8\n",
|
|
" %\"one\" = alloca i64, align 8\n",
|
|
" %\"prev\" = alloca i64*\n",
|
|
" %\"previous_value\" = alloca i64, align 8\n",
|
|
" %\".3\" = inttoptr i64 14 to i64 ()*\n",
|
|
" %\".4\" = call i64 %\".3\"()\n",
|
|
" %\".5\" = and i64 %\".4\", 4294967295\n",
|
|
" store i64 %\".5\", i64* %\"process_id\"\n",
|
|
" store i64 1, i64* %\"one\"\n",
|
|
" %\".8\" = inttoptr i64 1 to ptr (ptr, ptr)*\n",
|
|
" %\".9\" = call ptr %\".8\"({ptr, ptr, ptr, ptr}* @\"hist\", i64* %\"process_id\")\n",
|
|
" store ptr %\".9\", i64** %\"prev\"\n",
|
|
" %\".11\" = load i64*, i64** %\"prev\"\n",
|
|
" %\".12\" = icmp ne i64* %\".11\", null\n",
|
|
" br i1 %\".12\", label %\"if.then\", label %\"if.else\"\n",
|
|
"if.then:\n",
|
|
"if.end:\n",
|
|
"if.else:\n",
|
|
"}\n",
|
|
"\n",
|
|
"!llvm.dbg.cu = !{ !1 }\n",
|
|
"!0 = !DIFile(directory: \"/tmp\", filename: \"/tmp/tmpf9jfb5h5.py\")\n",
|
|
"!1 = distinct !DICompileUnit(emissionKind: 1, file: !0, isOptimized: true, language: 29, nameTableKind: 0, producer: \"PythonBPF DSL Compiler\", runtimeVersion: 0, splitDebugInlining: false)\n",
|
|
"!2 = !DIBasicType(encoding: 7, name: \"unsigned int\", size: 32)\n",
|
|
"!3 = !DIBasicType(encoding: 7, name: \"unsigned long long\", size: 64)\n",
|
|
"!4 = !DISubrange(count: 1)\n",
|
|
"!5 = !{ !4 }\n",
|
|
"!6 = !DICompositeType(baseType: !2, elements: !5, size: 32, tag: 1)\n",
|
|
"!7 = !DIDerivedType(baseType: !6, size: 64, tag: 15)\n",
|
|
"!8 = !DIDerivedType(baseType: !2, size: 64, tag: 15)\n",
|
|
"!9 = !DIDerivedType(baseType: !3, size: 64, tag: 15)\n",
|
|
"!10 = !DIDerivedType(baseType: !7, file: !0, name: \"type\", offset: 0, size: 64, tag: 13)\n",
|
|
"!11 = !DIDerivedType(baseType: !8, file: !0, name: \"key\", offset: 64, size: 64, tag: 13)\n",
|
|
"!12 = !DIDerivedType(baseType: !9, file: !0, name: \"value\", offset: 128, size: 64, tag: 13)\n",
|
|
"!13 = !DISubrange(count: 4096)\n",
|
|
"!14 = !{ !13 }\n",
|
|
"!15 = !DICompositeType(baseType: !2, elements: !14, size: 32, tag: 1)\n",
|
|
"!16 = !DIDerivedType(baseType: !15, size: 64, tag: 15)\n",
|
|
"!17 = !DIDerivedType(baseType: !16, file: !0, name: \"max_entries\", offset: 192, size: 64, tag: 13)\n",
|
|
"!18 = !{ !10, !11, !12, !17 }\n",
|
|
"!19 = distinct !DICompositeType(elements: !18, file: !0, size: 256, tag: 19)\n",
|
|
"!20 = distinct !DIGlobalVariable(file: !0, isDefinition: true, isLocal: false, name: \"hist\", scope: !1, type: !19)\n",
|
|
"!21 = !DIExpression()\n",
|
|
"!22 = !DIGlobalVariableExpression(expr: !21, var: !20)\n",
|
|
"left is %\".15\" = load i64, i64* %\".14\", right is i64 1, op is <ast.Add object at 0x7f6e5a8c1410>\n",
|
|
"Processing statement: Expr(value=Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[]))\n",
|
|
"{}\n",
|
|
"Handling expression: Expr(value=Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[]))\n",
|
|
"{}\n",
|
|
"Evaluating expression: Call(func=Name(id='print', ctx=Load()), args=[JoinedStr(values=[Constant(value='count: '), FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1), Constant(value=' with '), FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)])], keywords=[])\n",
|
|
"{}\n",
|
|
"{}\n",
|
|
"Value in f-string: Constant(value='count: ')\n",
|
|
"Value in f-string: FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1)\n",
|
|
"Formatted value: FormattedValue(value=Name(id='previous_value', ctx=Load()), conversion=-1)\n",
|
|
"Value in f-string: Constant(value=' with ')\n",
|
|
"Value in f-string: FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)\n",
|
|
"Formatted value: FormattedValue(value=Name(id='process_id', ctx=Load()), conversion=-1)\n",
|
|
"Name(id='previous_value', ctx=Load())\n",
|
|
"Evaluating expression: Name(id='previous_value', ctx=Load())\n",
|
|
"{}\n",
|
|
"Name(id='process_id', ctx=Load())\n",
|
|
"Evaluating expression: Name(id='process_id', ctx=Load())\n",
|
|
"{}\n",
|
|
"Processing statement: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[]))\n",
|
|
"{}\n",
|
|
"Handling expression: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[]))\n",
|
|
"{}\n",
|
|
"Evaluating expression: Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='previous_value', ctx=Load())], keywords=[])\n",
|
|
"{}\n",
|
|
"Handling method call: Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load())\n",
|
|
"{}\n",
|
|
"{}\n",
|
|
"Processing statement: Return(value=Call(func=Name(id='c_int64', ctx=Load()), args=[Constant(value=0)], keywords=[]))\n",
|
|
"Processing statement: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[]))\n",
|
|
"{}\n",
|
|
"Handling expression: Expr(value=Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[]))\n",
|
|
"{}\n",
|
|
"Evaluating expression: Call(func=Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load()), args=[Name(id='process_id', ctx=Load()), Name(id='one', ctx=Load())], keywords=[])\n",
|
|
"{}\n",
|
|
"Handling method call: Attribute(value=Call(func=Name(id='hist', ctx=Load()), args=[], keywords=[]), attr='update', ctx=Load())\n",
|
|
"{}\n",
|
|
"{}\n",
|
|
"Processing statement: Return(value=Call(func=Name(id='c_int64', ctx=Load()), args=[Constant(value=0)], keywords=[]))\n",
|
|
"IR written to /tmp/tmpowf1hvxf.ll\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"@bpf\n",
|
|
"@map\n",
|
|
"def hist() -> HashMap:\n",
|
|
" return HashMap(key=c_int32, value=c_uint64, max_entries=4096)\n",
|
|
"\n",
|
|
"@bpf\n",
|
|
"@section(\"tracepoint/syscalls/sys_enter_clone\")\n",
|
|
"def hello(ctx: c_void_p) -> c_int64:\n",
|
|
" process_id = pid()\n",
|
|
" one = 1\n",
|
|
" prev = hist().lookup(process_id)\n",
|
|
" if prev:\n",
|
|
" previous_value = prev + 1\n",
|
|
" print(f\"count: {previous_value} with {process_id}\")\n",
|
|
" hist().update(process_id, previous_value)\n",
|
|
" return c_int64(0)\n",
|
|
" else:\n",
|
|
" hist().update(process_id, one)\n",
|
|
" return c_int64(0)\n",
|
|
"\n",
|
|
"\n",
|
|
"@bpf\n",
|
|
"@bpfglobal\n",
|
|
"def LICENSE() -> str:\n",
|
|
" return \"GPL\"\n",
|
|
"\n",
|
|
"b = BPF()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "93fae9f8-464e-48d6-b61e-57b9f93e508a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Recording\n",
|
|
"PID 116823 called clone() >40 times\n",
|
|
"PID 117099 called clone() >40 times\n",
|
|
"PID 116696 called clone() >40 times\n",
|
|
"Total PIDs with clone() >40 times: 3\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "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r149tG7dGn5+flw5nIiIiKodrXp2nj59ioULF8LZ2RkBAQE4ePAg8vLyYGhoiPT0dMyZMweNGjVCQEAAzpw5o+/MRERERFrTqmenSZMmUCgU2LBhA95//30YGRlV2OfOnTuIjIxE//79MWPGDIwYMULysERERERiaVXsHD58GM2aNfvbfVxcXBAWFobJkycjMzNTknBEREREutLqNtY/FTp/ZWRkhMaNG1c6EBEREZGUtCp2xPbU3Lt3r1JhiIiIiKSmVbHTrl07jBo1CufPn3/pPvn5+diwYQNatGiBXbt2SRaQiIiISBdajdm5du0avvzyS7z//vswNTWFt7c3nJycYGpqij///BPXrl3D1atX0aZNG0RERCAgIEDfuYmIiIi0olXPjq2tLZYvX44HDx7gP//5D9zc3PDw4UPcuHEDADBw4EAkJCQgPj6ehQ4RERFVK6ImFTQzM8OHH36IDz/8UF95iIiIiCRV6eUi0tPTER0djadPnwIABEGQLBQRERGRVEQXO48ePYKvry+aNGmCgIAAPHjwAAAwfPhwTJo0SfKARERERLoQXeyEhITAyMgImZmZMDc3V7f369cPhw4dkjQcERERka5EjdkBns2mHB0djfr162u0u7m54c6dO5IFIyIiIpKC6J6doqIijR6d53Jzc2FiYiJJKCIiIiKpiC523n77bWzbtk39XiaTQaVSISIiAu+++66k4YiIiIh0Jfo2VkREBHx9fXHhwgWUlpZi6tSpuHr1KnJzc3Hq1Cl9ZCQiIiKqNNE9Oy1atEBaWho6deqEXr16oaioCH369MGlS5e4ACgRERFVO6J7dgBALpdjxowZUmchIiIiklylip28vDycO3cOOTk5UKlUGtsGDx4sSTAiIiIiKYgudvbt24eBAweisLAQ1tbWkMlk6m0ymYzFDhEREVUrosfsTJo0CZ999hkKCwuRl5eHP//8U/3Kzc3VR0YiIiKiShNd7Ny7dw/jx49/4Vw7RERERNWN6GLH398fFy5c0EcWIiIiIsmJHrMTGBiIKVOm4Nq1a/D09ISRkZHG9p49e0oWjoiIiEhXooudESNGAADmz59fYZtMJoNSqdQ9FREREZFERBc7//uoOREREVF1JnrMDhEREdGrpFLFTlxcHHr06AFXV1e4urqiZ8+e+O2336TORkRERKQz0cXO999/Dz8/P5ib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",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"b.load_and_attach()\n",
|
|
"hist = BpfMap(b, hist)\n",
|
|
"print(\"Recording\")\n",
|
|
"time.sleep(10)\n",
|
|
"\n",
|
|
"counts = list(hist.values())\n",
|
|
"x = 0\n",
|
|
"for key in hist.keys():\n",
|
|
" if hist[key] > 40:\n",
|
|
" x += 1\n",
|
|
" print(f\"PID {key} called clone() >40 times\")\n",
|
|
"print(f\"Total PIDs with clone() >40 times: {x}\")\n",
|
|
"plt.hist(counts, bins=20)\n",
|
|
"plt.xlabel(\"Clone calls per PID\")\n",
|
|
"plt.ylabel(\"Number of processes that called clone() x times in last 10 seconds\")\n",
|
|
"plt.title(\"x\")\n",
|
|
"plt.show()"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.12.3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|