/* Tapsets Instrumentation of Python's module loading: */ // FIXME: this will be lib64 on 64-bit; need to consolidate all these repeated references to the exact library path probe libpython.load_source_module = process("/usr/lib/libpython2.6.so.1.0").function("load_source_module") { name = user_string($name); pathname = user_string($pathname); } probe libpython.load_source_module.return = process("/usr/lib/libpython2.6.so.1.0").function("load_source_module").return { name = user_string($name); pathname = user_string($pathname); } probe libpython.read_compiled_module = process("/usr/lib/libpython2.6.so.1.0").function("read_compiled_module") { cpathname = user_string($cpathname); } probe libpython.read_compiled_module.return = process("/usr/lib/libpython2.6.so.1.0").function("read_compiled_module").return { cpathname = user_string($cpathname); } /* Usage of tapsets: */ global cumu_string_sizes; global cumu_large_sizes; //global module_sizes; //global stats; global unique_demarshalled_strings; probe libpython.load_source_module { printf("%s => load_source_module(\"%s\", \"%s\")\n", thread_indent(1), name, pathname); } probe libpython.load_source_module.return { printf("%s <= load_source_module(\"%s\", \"%s\")\n", thread_indent(-1), name, pathname); print_live_python_objects(); } probe libpython.read_compiled_module { printf("%s => BEGIN READING: %s\n", thread_indent(1), cpathname); } probe libpython.read_compiled_module.return { printf("%s <= END READING: %s\n", thread_indent(-1), cpathname); } global vm_brks; global first_vm_brk = 1; probe vm.brk { printf("vm.brk %i %i %p\n", length, address, address); if (first_vm_brk) { first_vm_brk = 0; vm_brks <<< address; } else { vm_brks <<< length; } printf("Heap Size: %s\n", bytes_to_string(@sum(vm_brks))); # FIXME: is this correct? } probe process("/usr/lib/libpython2.6.so.1.0").function("new_arena") { printf("new_arena()\n"); } probe end { printf("Total cumulative size of r_string calls: %s\n", bytes_to_string(@sum(cumu_string_sizes))); print(@hist_log(cumu_string_sizes)); printf("Total cumulative size of r_string calls above 18 bytes: %s\n", bytes_to_string(@sum(cumu_large_sizes))); print(@hist_log(cumu_large_sizes)); printf("String stuff\n"); //print(@hist_log(string_allocs)); printf("Total cumulative size of r_object() calls returning strings with refcnt==1: %s\n", bytes_to_string(@sum(unique_demarshalled_strings))); print(@hist_log(unique_demarshalled_strings)); printf("Total length of vmbrks: %s\n", bytes_to_string(@sum(vm_brks))); print(@hist_log(vm_brks)); print_live_python_objects(); } function starting_read(info) { if (1==0) { printf("%s => BEING READING: %s\n", thread_indent(1), info); } } function finished_read(info) { if (1==0) { printf("%s <= END READING: %s\n", thread_indent(-1), info); } } probe process("/usr/lib/libpython2.6.so.1.0").function("r_string") { starting_read("string"); cumu_string_sizes <<< $n; if ($n > 18) { cumu_large_sizes <<< $n; } } probe process("/usr/lib/libpython2.6.so.1.0").function("r_string").return { finished_read("string"); } probe process("/usr/lib/libpython2.6.so.1.0").function("r_object") { starting_read("object"); } probe process("/usr/lib/libpython2.6.so.1.0").function("r_object").return { ob_refcnt = $return->ob_refcnt; tp_name = user_string($return->ob_type->tp_name); finished_read(sprintf("object(%s)", tp_name)); if (tp_name == "str") { length = @cast($return, "PyStringObject")->ob_size; ob_sval = user_string(@cast($return, "PyStringObject")->ob_sval); //printf("r_object returned string refcnt=%i\n", ob_refcnt); if (ob_refcnt == 1) { /* ...then we have a unique string demarshalled from a .pyc file, no interning benefit: */ unique_demarshalled_strings <<< length; } } } probe process("/usr/lib/libpython2.6.so.1.0").function("marshal_loads").return { printf("marshal_loads\n"); } probe process("/usr/lib/libpython2.6.so").function("collect") { //printf("%d %s %s\n", pid(), execname(), pp()) printf("%s => collect(%i)\n", thread_indent(1), $generation); } probe process("/usr/lib/libpython2.6.so").function("collect").return { //printf("%d %s %s\n", pid(), execname(), pp()) printf("%s <= collect(%i) %i\n", thread_indent(-1), $generation, $return); } /****/ global live_py_objects; function print_live_python_objects() { printf("# live PyObjects by tp_name\n"); foreach ([tp_name] in live_py_objects) { printf("%16s: %3i\n", tp_name, live_py_objects[tp_name]); } } probe process("/usr/lib/libpython2.6.so.1.0").function("PyList_New").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("list_dealloc") { live_py_objects["list"] --; } probe process("/usr/lib/libpython2.6.so.1.0").function("PyString_From*").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("string_dealloc") { live_py_objects["str"] --; } probe process("/usr/lib/libpython2.6.so.1.0").function("PyTuple_New").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("tupledealloc") { live_py_objects["tuple"] --; } probe process("/usr/lib/libpython2.6.so.1.0").function("PyFrame_New").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("frame_dealloc") { live_py_objects["frame"] --; } probe process("/usr/lib/libpython2.6.so.1.0").function("PyDict_New").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("dict_dealloc") { live_py_objects["dict"] --; } probe process("/usr/lib/libpython2.6.so.1.0").function("PyClass_New").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("class_dealloc") { live_py_objects["classobj"] --; } probe process("/usr/lib/libpython2.6.so.1.0").function("PyInstance_NewRaw").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; # FIXME } } probe process("/usr/lib/libpython2.6.so.1.0").function("instance_dealloc") { live_py_objects["instance"] --; # FIXME } probe process("/usr/lib/libpython2.6.so.1.0").function("PyMethod_New").return { if ($return) { live_py_objects[user_string($return->ob_type->tp_name)] ++; } } probe process("/usr/lib/libpython2.6.so.1.0").function("instancemethod_dealloc") { live_py_objects["instancemethod"] --; } /* probe process("/usr/lib/libpython2.6.so").function("PyObject_GC_Del") { printf("%s %s()\n", thread_indent(0), probefunc()); //user_string(@cast(op, "PyObject")->ob_type->tp_name)) } */ /* function repr(obj) { tp_name = user_string(@cast(obj, "PyObject")->ob_type->tp_name); return sprintf("<%s at %p>", tp_name, obj); } */ // The remainder are taken from the "proc_mem.stp" which isn't yet in F-12's systemtap rpm: // Return a 5 character wide string " x.yyp", " xx.yp", " xxxp", "xxxxp". function _stp_number_to_string_postfix:string (x:long, y:long, p:string) { if (x < 10) return sprintf("%d.%.2d%s", x, y * 100 / 1024, p); if (x < 100) return sprintf("%2d.%d%s", x, y * 10 / 1024, p); return sprintf("%4d%s", x, p); } /** * sfunction bytes_to_string - Human readable string for given bytes. * @bytes: Number of bytes to translate. * * Description: Returns a string representing the number of bytes (up * to 1024 bytes), the number of kilobytes (when less than 1024K) * postfixed by 'K', the number of megabytes (when less than 1024M) * postfixed by 'M' or the number of gigabytes postfixed by 'G'. If * representing K, M or G, and the number is amount is less than 100, * it includes a '.' plus the remainer. The returned string will be 5 * characters wide (padding with whitespace at the front) unless * negative or representing more than 9999G bytes. */ function bytes_to_string:string (bytes:long) { if (bytes < 1024) return sprintf("%5d", bytes); remain = bytes % 1024; bytes = bytes / 1024; if (bytes < 1024) return _stp_number_to_string_postfix(bytes, remain, "K"); remain = bytes % 1024; bytes = bytes / 1024; if (bytes < 1024) return _stp_number_to_string_postfix(bytes, remain, "M"); remain = bytes % 1024; bytes = bytes / 1024; return _stp_number_to_string_postfix(bytes, remain, "G"); }