Hello community, here is the log from the commit of package bcc for openSUSE:Factory checked in at 2017-03-12 20:05:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/bcc (Old) and /work/SRC/openSUSE:Factory/.bcc.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "bcc" Sun Mar 12 20:05:02 2017 rev:5 rq:478085 version:0.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/bcc/bcc.changes 2017-03-03 17:55:02.428090760 +0100 +++ /work/SRC/openSUSE:Factory/.bcc.new/bcc.changes 2017-03-12 20:05:04.992560381 +0100 @@ -1,0 +2,18 @@ +Fri Mar 10 02:20:39 UTC 2017 - [email protected] + +- Update to 0.3.0 + + Added s390x support. Needs 4.10 Kernel + + Restrict rewrite of unary operators to dereference operator + + cmake: Explicitly mark static libraries as such + + Fix bpf_dins_pkt rewrite in BinaryOperator + + cc: Symbol resolution with multiple executable regions per + module + + cc: Fix assertion for debug builds + + cc: Don't parse the same module multiple times for USDT probes + + add XDP return values to python interface + + python: handle null module in BPF.sym + + filetop: support specifying sort column via cmdline argument + + cc: Retry symbol resolution using perfmap + + cc: Handle nested functions correctly when resolving symbols + +------------------------------------------------------------------- Old: ---- bcc-v0.2.0+git1488325605.4d0d430.tar.xz New: ---- bcc-v0.3.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ bcc.spec ++++++ --- /var/tmp/diff_new_pack.9e1EsI/_old 2017-03-12 20:05:05.948425124 +0100 +++ /var/tmp/diff_new_pack.9e1EsI/_new 2017-03-12 20:05:05.948425124 +0100 @@ -16,7 +16,7 @@ # -%define libversion 0.2.0 +%define libversion 0.3.0 %ifarch ppc64 aarch64 ppc64le %{!?with_lua: %global with_lua 0} %else @@ -24,7 +24,7 @@ %endif Name: bcc -Version: 0.2.0+git1488325605.4d0d430 +Version: 0.3.0 Release: 0 Summary: BPF Compiler Collection (BCC) License: Apache-2.0 ++++++ bcc-v0.2.0+git1488325605.4d0d430.tar.xz -> bcc-v0.3.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/.travis.yml new/bcc-v0.3.0/.travis.yml --- old/bcc-v0.2.0+git1488325605.4d0d430/.travis.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/bcc-v0.3.0/.travis.yml 2017-03-10 03:07:20.000000000 +0100 @@ -0,0 +1,6 @@ +language: generic +install: + - sudo apt-get install -y python-pip + - sudo pip install pep8 +script: + - find tools/ -type f -name "*.py" | xargs pep8 -r --show-source --ignore=E123,E125,E126,E127,E128,E302 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/debian/changelog new/bcc-v0.3.0/debian/changelog --- old/bcc-v0.2.0+git1488325605.4d0d430/debian/changelog 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/debian/changelog 2017-03-10 03:07:20.000000000 +0100 @@ -1,3 +1,16 @@ +bcc (0.3.0-1) unstable; urgency=low + + * Many bugfixes + * Many tools converted to perf ring buffer + * New utilities in tools/ + * capable, cpuunclaimed, dbslower, dbstat, deadlock_detector, llcstat, + mountsnoop, runqlen, slabratetop, syscount, tcplife, tcptop, ttysnoop, + ucalls, uflow, ugc, uobjnew, ustat, uthreads + * New C++ API + * Support for kernel up to 4.10 + + -- Brenden Blanco <[email protected]> Thu, 09 Mar 2017 19:08:08 +0000 + bcc (0.2.0-1) unstable; urgency=low * Add many new utilities in tools/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/debian/rules new/bcc-v0.3.0/debian/rules --- old/bcc-v0.2.0+git1488325605.4d0d430/debian/rules 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/debian/rules 2017-03-10 03:07:20.000000000 +0100 @@ -11,6 +11,10 @@ %: dh $@ --buildsystem=cmake --parallel +# tests cannot be run in parallel +override_dh_auto_test: + dh_auto_test -O--buildsystem=cmake -O--no-parallel + # FIXME: LLVM_DEFINITIONS is broken somehow in LLVM cmake upstream override_dh_auto_configure: dh_auto_configure -- -DREVISION_LAST=$(UPSTREAM_VERSION) -DREVISION=$(UPSTREAM_VERSION) -DLLVM_DEFINITIONS="-D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/docs/tutorial_bcc_python_developer.md new/bcc-v0.3.0/docs/tutorial_bcc_python_developer.md --- old/bcc-v0.2.0+git1488325605.4d0d430/docs/tutorial_bcc_python_developer.md 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/docs/tutorial_bcc_python_developer.md 2017-03-10 03:07:20.000000000 +0100 @@ -96,7 +96,7 @@ 1. ```b.attach_kprobe(event="sys_clone", fn_name="hello")```: Creates a kprobe for the sys_clone() kernel function, which will execute our defined hello() function. You can call attach_kprobe() more than once, and attach your C function to multiple kernel functions. -1. ```b.trace_fields()```: Returns a fixed set of fields from trace_pipe. Simalar to trace_print(), this is handy for hacking, but for real tooling we should switch to BPF_PERF_OUTPUT(). +1. ```b.trace_fields()```: Returns a fixed set of fields from trace_pipe. Similar to trace_print(), this is handy for hacking, but for real tooling we should switch to BPF_PERF_OUTPUT(). ### Lesson 4. sync_timing.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/man/man8/filetop.8 new/bcc-v0.3.0/man/man8/filetop.8 --- old/bcc-v0.2.0+git1488325605.4d0d430/man/man8/filetop.8 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/man/man8/filetop.8 2017-03-10 03:07:20.000000000 +0100 @@ -2,14 +2,15 @@ .SH NAME filetop \- File reads and writes by filename and process. Top for files. .SH SYNOPSIS -.B filetop [\-h] [\-C] [\-r MAXROWS] [\-p PID] [interval] [count] +.B filetop [\-h] [\-C] [\-r MAXROWS] [\-s {reads,writes,rbytes,wbytes}] [\-p PID] [interval] [count] .SH DESCRIPTION This is top for files. -This traces file reads and writes, and prints a per-file summary every -interval (by default, 1 second). The summary is sorted on the highest read -throughput (Kbytes). By default only IO on regular files is shown. The -a -option will list all file types (sokets, FIFOs, etc). +This traces file reads and writes, and prints a per-file summary every interval +(by default, 1 second). By default the summary is sorted on the highest read +throughput (Kbytes). Sorting order can be changed via -s option. By default only +IO on regular files is shown. The -a option will list all file types (sokets, +FIFOs, etc). This uses in-kernel eBPF maps to store per process summaries for efficiency. @@ -39,6 +40,9 @@ \-r MAXROWS Maximum number of rows to print. Default is 20. .TP +\-s {reads,writes,rbytes,wbytes} +Sort column. Default is rbytes (read throughput). +.TP \-p PID Trace this PID only. .TP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/CMakeLists.txt new/bcc-v0.3.0/src/cc/CMakeLists.txt --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/CMakeLists.txt 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/CMakeLists.txt 2017-03-10 03:07:20.000000000 +0100 @@ -39,7 +39,7 @@ set_target_properties(bcc-shared PROPERTIES VERSION ${REVISION_LAST} SOVERSION 0) set_target_properties(bcc-shared PROPERTIES OUTPUT_NAME bcc) -add_library(bcc-loader-static libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c) +add_library(bcc-loader-static STATIC libbpf.c perf_reader.c bcc_elf.c bcc_perf_map.c bcc_proc.c) add_library(bcc-static STATIC bpf_common.cc bpf_module.cc shared_table.cc exported_files.cc bcc_syms.cc usdt_args.cc usdt.cc common.cc BPF.cc BPFTable.cc) set_target_properties(bcc-static PROPERTIES OUTPUT_NAME bcc) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/bcc_syms.cc new/bcc-v0.3.0/src/cc/bcc_syms.cc --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/bcc_syms.cc 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/bcc_syms.cc 2017-03-10 03:07:20.000000000 +0100 @@ -101,7 +101,11 @@ int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end, void *payload) { ProcSyms *ps = static_cast<ProcSyms *>(payload); - ps->modules_.emplace_back(modname, start, end); + auto it = std::find_if(ps->modules_.begin(), ps->modules_.end(), + [=](const ProcSyms::Module &m) { return m.name_ == modname; }); + if (it == ps->modules_.end()) + it = ps->modules_.insert(ps->modules_.end(), modname); + it->ranges_.push_back(ProcSyms::Module::Range(start, end)); return 0; } @@ -114,15 +118,30 @@ sym->demangle_name = nullptr; sym->offset = 0x0; + const char *original_module = nullptr; for (Module &mod : modules_) { - if (addr >= mod.start_ && addr < mod.end_) { + if (mod.contains(addr)) { bool res = mod.find_addr(addr, sym); if (sym->name) { sym->demangle_name = abi::__cxa_demangle(sym->name, nullptr, nullptr, nullptr); if (!sym->demangle_name) sym->demangle_name = sym->name; } - return res; + // If we have a match, return right away. But if we don't have a match in + // this module, we might have a match in the perf map (even though the + // module itself doesn't have symbols). Wait until we see the perf map if + // any, but keep the original module name for reporting. + if (res) { + // If we have already seen this module, report the original name rather + // than the perf map name: + if (original_module) + sym->module = original_module; + return res; + } else { + // Record the module to which this symbol belongs, so that even if it's + // later found using a perf map, we still report the right module name. + original_module = mod.name_.c_str(); + } } } return false; @@ -140,8 +159,8 @@ return false; } -ProcSyms::Module::Module(const char *name, uint64_t start, uint64_t end) - : name_(name), start_(start), end_(end) { +ProcSyms::Module::Module(const char *name) + : name_(name) { is_so_ = bcc_elf_is_shared_obj(name) == 1; } @@ -169,12 +188,20 @@ std::sort(syms_.begin(), syms_.end()); } +bool ProcSyms::Module::contains(uint64_t addr) const { + for (const auto &range : ranges_) { + if (addr >= range.start && addr < range.end) + return true; + } + return false; +} + bool ProcSyms::Module::find_name(const char *symname, uint64_t *addr) { load_sym_table(); for (Symbol &s : syms_) { if (*(s.name) == symname) { - *addr = is_so() ? start_ + s.start : s.start; + *addr = is_so() ? start() + s.start : s.start; return true; } } @@ -182,7 +209,7 @@ } bool ProcSyms::Module::find_addr(uint64_t addr, struct bcc_symbol *sym) { - uint64_t offset = is_so() ? (addr - start_) : addr; + uint64_t offset = is_so() ? (addr - start()) : addr; load_sym_table(); @@ -190,16 +217,34 @@ sym->offset = offset; auto it = std::upper_bound(syms_.begin(), syms_.end(), Symbol(nullptr, offset, 0)); - if (it != syms_.begin()) - --it; - else - it = syms_.end(); + if (it == syms_.begin()) + return false; - if (it != syms_.end() - && offset >= it->start && offset < it->start + it->size) { - sym->name = it->name->c_str(); - sym->offset = (offset - it->start); - return true; + // 'it' points to the symbol whose start address is strictly greater than + // the address we're looking for. Start stepping backwards as long as the + // current symbol is still below the desired address, and see if the end + // of the current symbol (start + size) is above the desired address. Once + // we have a matching symbol, return it. Note that simply looking at '--it' + // is not enough, because symbols can be nested. For example, we could be + // looking for offset 0x12 with the following symbols available: + // SYMBOL START SIZE END + // goo 0x0 0x6 0x0 + 0x6 = 0x6 + // foo 0x6 0x10 0x6 + 0x10 = 0x16 + // bar 0x8 0x4 0x8 + 0x4 = 0xc + // baz 0x16 0x10 0x16 + 0x10 = 0x26 + // The upper_bound lookup will return baz, and then going one symbol back + // brings us to bar, which does not contain offset 0x12 and is nested inside + // foo. Going back one more symbol brings us to foo, which contains 0x12 + // and is a match. + for (--it; offset >= it->start; --it) { + if (offset < it->start + it->size) { + sym->name = it->name->c_str(); + sym->offset = (offset - it->start); + return true; + } + // But don't step beyond begin()! + if (it == syms_.begin()) + break; } return false; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/export/helpers.h new/bcc-v0.3.0/src/cc/export/helpers.h --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/export/helpers.h 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/export/helpers.h 2017-03-10 03:07:20.000000000 +0100 @@ -468,6 +468,17 @@ #define PT_REGS_RC(ctx) ((ctx)->gpr[3]) #define PT_REGS_IP(ctx) ((ctx)->nip) #define PT_REGS_SP(ctx) ((ctx)->sp) +#elif defined(__s390x__) +#define PT_REGS_PARM1(x) ((x)->gprs[2]) +#define PT_REGS_PARM2(x) ((x)->gprs[3]) +#define PT_REGS_PARM3(x) ((x)->gprs[4]) +#define PT_REGS_PARM4(x) ((x)->gprs[5]) +#define PT_REGS_PARM5(x) ((x)->gprs[6]) +#define PT_REGS_RET(x) ((x)->gprs[14]) +#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->gprs[2]) +#define PT_REGS_SP(x) ((x)->gprs[15]) +#define PT_REGS_IP(x) ((x)->psw.addr) #elif defined(__x86_64__) #define PT_REGS_PARM1(ctx) ((ctx)->di) #define PT_REGS_PARM2(ctx) ((ctx)->si) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/b/CMakeLists.txt new/bcc-v0.3.0/src/cc/frontends/b/CMakeLists.txt --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/b/CMakeLists.txt 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/frontends/b/CMakeLists.txt 2017-03-10 03:07:20.000000000 +0100 @@ -11,5 +11,5 @@ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/lexer.ll.cc PROPERTIES COMPILE_FLAGS "-Wno-deprecated-register") endif() -add_library(b_frontend loader.cc codegen_llvm.cc node.cc parser.cc printer.cc +add_library(b_frontend STATIC loader.cc codegen_llvm.cc node.cc parser.cc printer.cc type_check.cc ${BISON_Parser_OUTPUTS} ${FLEX_Lexer_OUTPUTS}) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/CMakeLists.txt new/bcc-v0.3.0/src/cc/frontends/clang/CMakeLists.txt --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/CMakeLists.txt 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/frontends/clang/CMakeLists.txt 2017-03-10 03:07:20.000000000 +0100 @@ -2,4 +2,4 @@ # Licensed under the Apache License, Version 2.0 (the "License") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DKERNEL_MODULES_DIR='\"${BCC_KERNEL_MODULES_DIR}\"'") -add_library(clang_frontend loader.cc b_frontend_action.cc tp_frontend_action.cc kbuild_helper.cc ../../common.cc) +add_library(clang_frontend STATIC loader.cc b_frontend_action.cc tp_frontend_action.cc kbuild_helper.cc ../../common.cc) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/b_frontend_action.cc new/bcc-v0.3.0/src/cc/frontends/clang/b_frontend_action.cc --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/b_frontend_action.cc 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/frontends/clang/b_frontend_action.cc 2017-03-10 03:07:20.000000000 +0100 @@ -39,11 +39,17 @@ }; const char *calling_conv_regs_ppc[] = {"gpr[3]", "gpr[4]", "gpr[5]", "gpr[6]", "gpr[7]", "gpr[8]"}; + +const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]", + "gprs[5]", "gprs[6]" }; + const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]", "regs[3]", "regs[4]", "regs[5]"}; // todo: support more archs #if defined(__powerpc__) const char **calling_conv_regs = calling_conv_regs_ppc; +#elif defined(__s390x__) +const char **calling_conv_regs = calling_conv_regs_s390x; #elif defined(__aarch64__) const char **calling_conv_regs = calling_conv_regs_arm64; #else @@ -200,7 +206,7 @@ return true; } bool ProbeVisitor::VisitUnaryOperator(UnaryOperator *E) { - if (E->getOpcode() == UO_AddrOf) + if (E->getOpcode() != UO_Deref) return true; if (memb_visited_.find(E) != memb_visited_.end()) return true; @@ -521,7 +527,6 @@ if (!E->isAssignmentOp()) return true; Expr *LHS = E->getLHS()->IgnoreImplicit(); - Expr *RHS = E->getRHS()->IgnoreImplicit(); if (MemberExpr *Memb = dyn_cast<MemberExpr>(LHS)) { if (DeclRefExpr *Base = dyn_cast<DeclRefExpr>(Memb->getBase()->IgnoreImplicit())) { if (DeprecatedAttr *A = Base->getDecl()->getAttr<DeprecatedAttr>()) { @@ -534,10 +539,10 @@ uint64_t ofs = C.getFieldOffset(F); uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType()); string base = rewriter_.getRewrittenText(expansionRange(Base->getSourceRange())); - string rhs = rewriter_.getRewrittenText(expansionRange(RHS->getSourceRange())); string text = "bpf_dins_pkt(" + fn_args_[0]->getName().str() + ", (u64)" + base + "+" + to_string(ofs >> 3) - + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ", " + rhs + ")"; - rewriter_.ReplaceText(expansionRange(E->getSourceRange()), text); + + ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ","; + rewriter_.ReplaceText(expansionRange(SourceRange(E->getLocStart(), E->getOperatorLoc())), text); + rewriter_.InsertTextAfterToken(E->getLocEnd(), ")"); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/loader.cc new/bcc-v0.3.0/src/cc/frontends/clang/loader.cc --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/frontends/clang/loader.cc 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/frontends/clang/loader.cc 2017-03-10 03:07:20.000000000 +0100 @@ -172,6 +172,8 @@ #else driver::Driver drv("", "powerpc64-unknown-linux-gnu", diags); #endif +#elif defined(__s390x__) + driver::Driver drv("", "s390x-ibm-linux-gnu", diags); #elif defined(__aarch64__) driver::Driver drv("", "aarch64-unknown-linux-gnu", diags); #else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/libbpf.c new/bcc-v0.3.0/src/cc/libbpf.c --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/libbpf.c 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/libbpf.c 2017-03-10 03:07:20.000000000 +0100 @@ -46,6 +46,8 @@ #ifndef __NR_bpf #if defined(__powerpc64__) #define __NR_bpf 361 +#elif defined(__s390x__) +#define __NR_bpf 351 #elif defined(__aarch64__) #define __NR_bpf 280 #else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/syms.h new/bcc-v0.3.0/src/cc/syms.h --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/syms.h 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/syms.h 2017-03-10 03:07:20.000000000 +0100 @@ -79,15 +79,22 @@ }; struct Module { - Module(const char *name, uint64_t start, uint64_t end); + struct Range { + uint64_t start; + uint64_t end; + Range(uint64_t s, uint64_t e) : start(s), end(e) {} + }; + + Module(const char *name); std::string name_; - uint64_t start_; - uint64_t end_; + std::vector<Range> ranges_; bool is_so_; std::unordered_set<std::string> symnames_; std::vector<Symbol> syms_; void load_sym_table(); + bool contains(uint64_t addr) const; + uint64_t start() const { return ranges_.begin()->start; } bool find_addr(uint64_t addr, struct bcc_symbol *sym); bool find_name(const char *symname, uint64_t *addr); bool is_so() const { return is_so_; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.cc new/bcc-v0.3.0/src/cc/usdt.cc --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.cc 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/usdt.cc 2017-03-10 03:07:20.000000000 +0100 @@ -63,7 +63,7 @@ } bool Probe::add_to_semaphore(int16_t val) { - assert(pid_ && attached_semaphore_); + assert(pid_); if (!attached_semaphore_) { uint64_t addr; @@ -200,7 +200,13 @@ } int Context::_each_module(const char *modpath, uint64_t, uint64_t, void *p) { - bcc_elf_foreach_usdt(modpath, _each_probe, p); + Context *ctx = static_cast<Context *>(p); + // Modules may be reported multiple times if they contain more than one + // executable region. We are going to parse the ELF on disk anyway, so we + // don't need these duplicates. + if (ctx->modules_.insert(modpath).second /*inserted new?*/) { + bcc_elf_foreach_usdt(modpath, _each_probe, p); + } return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.h new/bcc-v0.3.0/src/cc/usdt.h --- old/bcc-v0.2.0+git1488325605.4d0d430/src/cc/usdt.h 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/cc/usdt.h 2017-03-10 03:07:20.000000000 +0100 @@ -191,6 +191,7 @@ class Context { std::vector<std::unique_ptr<Probe>> probes_; + std::unordered_set<std::string> modules_; optional<int> pid_; optional<ProcStat> pid_stat_; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/__init__.py new/bcc-v0.3.0/src/python/bcc/__init__.py --- old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/__init__.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/python/bcc/__init__.py 2017-03-10 03:07:20.000000000 +0100 @@ -118,6 +118,12 @@ XDP = 6 PERF_EVENT = 7 + # from xdp_action uapi/linux/bpf.h + XDP_ABORTED = 0 + XDP_DROP = 1 + XDP_PASS = 2 + XDP_TX = 3 + _probe_repl = re.compile("[^a-zA-Z0-9_]") _sym_caches = {} @@ -989,12 +995,12 @@ returned. When show_module is True, the module name is also included. When show_offset is True, the instruction offset as a hexadecimal number is also included in the string. - + A pid of less than zero will access the kernel symbol cache. Example output when both show_module and show_offset are True: "start_thread+0x202 [libpthread-2.24.so]" - + Example output when both show_module and show_offset are False: "start_thread" """ @@ -1002,7 +1008,8 @@ offset = "+0x%x" % offset if show_offset and name is not None else "" name = name or "[unknown]" name = name + offset - module = " [%s]" % os.path.basename(module) if show_module else "" + module = " [%s]" % os.path.basename(module) \ + if show_module and module is not None else "" return name + module @staticmethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/usdt.py new/bcc-v0.3.0/src/python/bcc/usdt.py --- old/bcc-v0.2.0+git1488325605.4d0d430/src/python/bcc/usdt.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/src/python/bcc/usdt.py 2017-03-10 03:07:20.000000000 +0100 @@ -130,7 +130,7 @@ raise USDTException("USDT failed to instrument PID %d" % pid) elif path: self.path = path - self.context = lib.bcc_usdt_new_frompath(path) + self.context = lib.bcc_usdt_new_frompath(path.encode('ascii')) if self.context == None: raise USDTException("USDT failed to instrument path %s" % path) else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tests/python/test_clang.py new/bcc-v0.3.0/tests/python/test_clang.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tests/python/test_clang.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tests/python/test_clang.py 2017-03-10 03:07:20.000000000 +0100 @@ -392,5 +392,35 @@ t = b["act"] self.assertEquals(len(t), 32); + def test_bpf_dins_pkt_rewrite(self): + text = """ +#include <bcc/proto.h> +int dns_test(struct __sk_buff *skb) { + u8 *cursor = 0; + struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet)); + if(ethernet->type == ETH_P_IP) { + struct ip_t *ip = cursor_advance(cursor, sizeof(*ip)); + ip->src = ip->dst; + return 0; + } + return -1; +} + """ + b = BPF(text=text) + + def test_unary_operator(self): + text = """ +#include <linux/fs.h> +#include <uapi/linux/ptrace.h> +int trace_read_entry(struct pt_regs *ctx, struct file *file) { + return !file->f_op->read_iter; +} + """ + b = BPF(text=text) + b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry") + if __name__ == "__main__": main() + + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/argdist.py new/bcc-v0.3.0/tools/argdist.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/argdist.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/argdist.py 2017-03-10 03:07:20.000000000 +0100 @@ -200,7 +200,7 @@ elif self.probe_type == "u": self.library = parts[1] self.probe_func_name = self._make_valid_identifier( - "%s_probe%d" % \ + "%s_probe%d" % (self.function, Probe.next_probe_index)) self._enable_usdt_probe() else: @@ -238,10 +238,10 @@ (any(map(check, self.exprs)) or check(self.filter)) self.probe_func_name = self._make_valid_identifier( - "%s_probe%d" % \ + "%s_probe%d" % (self.function, Probe.next_probe_index)) self.probe_hash_name = self._make_valid_identifier( - "%s_hash%d" % \ + "%s_hash%d" % (self.function, Probe.next_probe_index)) Probe.next_probe_index += 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/cpuunclaimed.py new/bcc-v0.3.0/tools/cpuunclaimed.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/cpuunclaimed.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/cpuunclaimed.py 2017-03-10 03:07:20.000000000 +0100 @@ -169,10 +169,10 @@ if args.timestamp: print("TIME", end=",") print("TIMESTAMP_ns", end=",") - print(",".join("CPU" + str(c) for c in xrange(ncpu)), end="") + print(",".join("CPU" + str(c) for c in range(ncpu)), end="") if args.fullcsv: print(",", end="") - print(",".join("OFFSET_ns_CPU" + str(c) for c in xrange(ncpu)), end="") + print(",".join("OFFSET_ns_CPU" + str(c) for c in range(ncpu)), end="") print() else: print(("Sampling run queues... Output every %s seconds. " + @@ -255,10 +255,10 @@ if args.timestamp: print("%-8s" % strftime("%H:%M:%S"), end=",") print("%d" % g_time, end=",") - print(",".join(str(lens[c]) for c in xrange(ncpu)), end="") + print(",".join(str(lens[c]) for c in range(ncpu)), end="") if args.fullcsv: print(",", end="") - print(",".join(str(offs[c]) for c in xrange(ncpu))) + print(",".join(str(offs[c]) for c in range(ncpu))) else: print() else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbslower.py new/bcc-v0.3.0/tools/dbslower.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbslower.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/dbslower.py 2017-03-10 03:07:20.000000000 +0100 @@ -13,7 +13,7 @@ # # Strongly inspired by Brendan Gregg's work on the mysqld_qslower script. # -# Copyright 2017, Sasha Goldshtein +# Copyright 2017, Sasha Goldshtein # Licensed under the Apache License, Version 2.0 # # 15-Feb-2017 Sasha Goldshtein Created this. @@ -27,7 +27,7 @@ dbslower postgres # trace PostgreSQL queries slower than 1ms dbslower postgres -p 188 322 # trace specific PostgreSQL processes dbslower mysql -p 480 -m 30 # trace MySQL queries slower than 30ms - dbslower mysql -p 480 -v # trace MySQL queries and print the BPF program + dbslower mysql -p 480 -v # trace MySQL queries & print the BPF program """ parser = argparse.ArgumentParser( description="", @@ -134,4 +134,3 @@ bpf["events"].open_perf_buffer(print_event, page_cnt=64) while True: bpf.kprobe_poll() - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbstat.py new/bcc-v0.3.0/tools/dbstat.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/dbstat.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/dbstat.py 2017-03-10 03:07:20.000000000 +0100 @@ -8,7 +8,7 @@ # This tool uses USDT probes, which means it needs MySQL and PostgreSQL built # with USDT (DTrace) support. # -# Copyright 2017, Sasha Goldshtein +# Copyright 2017, Sasha Goldshtein # Licensed under the Apache License, Version 2.0 # # 15-Feb-2017 Sasha Goldshtein Created this. @@ -80,7 +80,7 @@ } """ program = program.replace("SCALE", str(1000 if args.microseconds else 1000000)) -program = program.replace("FILTER", "" if args.threshold == 0 else \ +program = program.replace("FILTER", "" if args.threshold == 0 else "if (delta / 1000000 < %d) { return 0; }" % args.threshold) usdts = map(lambda pid: USDT(pid=pid), args.pids) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop.py new/bcc-v0.3.0/tools/filetop.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/filetop.py 2017-03-10 03:07:20.000000000 +0100 @@ -38,6 +38,9 @@ help="don't clear the screen") parser.add_argument("-r", "--maxrows", default=20, help="maximum rows to print, default 20") +parser.add_argument("-s", "--sort", default="rbytes", + choices=["reads", "writes", "rbytes", "wbytes"], + help="sort column, default rbytes") parser.add_argument("-p", "--pid", type=int, metavar="PID", dest="tgid", help="trace this PID only") parser.add_argument("interval", nargs="?", default=1, @@ -184,7 +187,8 @@ counts = b.get_table("counts") line = 0 for k, v in reversed(sorted(counts.items(), - key=lambda counts: counts[1].rbytes)): + key=lambda counts: + getattr(counts[1], args.sort))): name = k.name.decode() if k.name_len > DNAME_INLINE_LEN: name = name[:-3] + "..." diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop_example.txt new/bcc-v0.3.0/tools/filetop_example.txt --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/filetop_example.txt 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/filetop_example.txt 2017-03-10 03:07:20.000000000 +0100 @@ -29,10 +29,11 @@ 26628 ld 12 0 52 0 R swap.o [...] -This shows various files read and written during a Linux kernel build. The -output is sorted by the total read size in Kbytes (R_Kb). This is instrumenting -at the VFS interface, so this is reads and writes that may return entirely -from the file system cache (page cache). +This shows various files read and written during a Linux kernel build. By +default the output is sorted by the total read size in Kbytes (R_Kb). Sorting +order can be changed via -s option. This is instrumenting at the VFS interface, +so this is reads and writes that may return entirely from the file system cache +(page cache). While not printed, the average read and write size can be calculated by dividing R_Kb by READS, and the same for writes. @@ -146,6 +147,8 @@ -C, --noclear don't clear the screen -r MAXROWS, --maxrows MAXROWS maximum rows to print, default 20 + -s {reads,writes,rbytes,wbytes}, --sort {reads,writes,rbytes,wbytes} + sort column, default rbytes -p PID, --pid PID trace this PID only examples: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/funclatency.py new/bcc-v0.3.0/tools/funclatency.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/funclatency.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/funclatency.py 2017-03-10 03:07:20.000000000 +0100 @@ -90,7 +90,6 @@ # define BPF program bpf_text = """ #include <uapi/linux/ptrace.h> -#include <linux/blkdev.h> typedef struct ip_pid { u64 ip; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/memleak.py new/bcc-v0.3.0/tools/old/memleak.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/memleak.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/old/memleak.py 2017-03-10 03:07:20.000000000 +0100 @@ -186,8 +186,9 @@ allocs.update(&address, &info); if (SHOULD_PRINT) { - bpf_trace_printk("alloc exited, size = %lu, result = %lx, frames = %d\\n", - info.size, address, info.num_frames); + bpf_trace_printk("alloc exited, size = %lu, result = %lx," + "frames = %d\\n", info.size, address, + info.num_frames); } return 0; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/offwaketime.py new/bcc-v0.3.0/tools/old/offwaketime.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/old/offwaketime.py 1970-01-01 01:00:00.000000000 +0100 +++ new/bcc-v0.3.0/tools/old/offwaketime.py 2017-03-10 03:07:20.000000000 +0100 @@ -0,0 +1,284 @@ +#!/usr/bin/python +# +# offwaketime Summarize blocked time by kernel off-CPU stack + waker stack +# For Linux, uses BCC, eBPF. +# +# USAGE: offwaketime [-h] [-u] [-p PID] [-T] [duration] +# +# The current implementation uses an unrolled loop for x86_64, and was written +# as a proof of concept. This implementation should be replaced in the future +# with an appropriate bpf_ call, when available. +# +# The Off-CPU stack is currently limited to a stack trace depth of 20 +# (maxtdepth), and the waker stack limited to 10 (maxwdepth). This is also +# limited to kernel stacks, and x86_64 only. Check for future versions, where +# these limitations should be removed. +# +# Copyright 2016 Netflix, Inc. +# Licensed under the Apache License, Version 2.0 (the "License") +# +# 20-Jan-2016 Brendan Gregg Created this. + +from __future__ import print_function +from bcc import BPF +from time import sleep +import argparse +import signal + +# arguments +examples = """examples: + ./offwaketime # trace off-CPU + waker stack time until Ctrl-C + ./offwaketime 5 # trace for 5 seconds only + ./offwaketime -f 5 # 5 seconds, and output in folded format + ./offwaketime -u # don't include kernel threads (user only) + ./offwaketime -p 185 # trace fo PID 185 only +""" +parser = argparse.ArgumentParser( + description="Summarize blocked time by kernel stack trace + waker stack", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=examples) +parser.add_argument("-u", "--useronly", action="store_true", + help="user threads only (no kernel threads)") +parser.add_argument("-p", "--pid", + help="trace this PID only") +parser.add_argument("-v", "--verbose", action="store_true", + help="show raw addresses") +parser.add_argument("-f", "--folded", action="store_true", + help="output folded format") +parser.add_argument("duration", nargs="?", default=99999999, + help="duration of trace, in seconds") +args = parser.parse_args() +folded = args.folded +duration = int(args.duration) +debug = 0 +maxwdepth = 10 # and MAXWDEPTH +maxtdepth = 20 # and MAXTDEPTH +if args.pid and args.useronly: + print("ERROR: use either -p or -u.") + exit() + +# signal handler +def signal_ignore(signal, frame): + print() + +# define BPF program +bpf_text = """ +#include <uapi/linux/ptrace.h> +#include <linux/sched.h> + +#define MAXWDEPTH 10 +#define MAXTDEPTH 20 +#define MINBLOCK_US 1 + +struct key_t { + char waker[TASK_COMM_LEN]; + char target[TASK_COMM_LEN]; + u64 wret[MAXWDEPTH]; + u64 tret[MAXTDEPTH]; +}; +BPF_HASH(counts, struct key_t); +BPF_HASH(start, u32); +struct wokeby_t { + char name[TASK_COMM_LEN]; + u64 ret[MAXWDEPTH]; +}; +BPF_HASH(wokeby, u32, struct wokeby_t); + +static u64 get_frame(u64 *bp) { + if (*bp) { + // The following stack walker is x86_64 specific + u64 ret = 0; + if (bpf_probe_read(&ret, sizeof(ret), (void *)(*bp+8))) + return 0; + if (bpf_probe_read(bp, sizeof(*bp), (void *)*bp)) + *bp = 0; + if (ret < __START_KERNEL_map) + return 0; + return ret; + } + return 0; +} + +int waker(struct pt_regs *ctx, struct task_struct *p) { + u32 pid = p->pid; + + if (!(FILTER)) + return 0; + + u64 bp = 0; + struct wokeby_t woke = {}; + int depth = 0; + bpf_get_current_comm(&woke.name, sizeof(woke.name)); + bp = ctx->bp; + + // unrolled loop (MAXWDEPTH): + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + if (!(woke.ret[depth++] = get_frame(&bp))) goto out; + woke.ret[depth] = get_frame(&bp); + +out: + wokeby.update(&pid, &woke); + return 0; +} + +int oncpu(struct pt_regs *ctx, struct task_struct *p) { + u32 pid = p->pid; + u64 ts, *tsp; + + // record previous thread sleep time + if (FILTER) { + ts = bpf_ktime_get_ns(); + start.update(&pid, &ts); + } + + // calculate current thread's delta time + pid = bpf_get_current_pid_tgid(); + tsp = start.lookup(&pid); + if (tsp == 0) + return 0; // missed start or filtered + u64 delta = bpf_ktime_get_ns() - *tsp; + start.delete(&pid); + delta = delta / 1000; + if (delta < MINBLOCK_US) + return 0; + + // create map key + u64 zero = 0, *val, bp = 0; + int depth = 0; + struct key_t key = {}; + struct wokeby_t *woke; + bpf_get_current_comm(&key.target, sizeof(key.target)); + bp = ctx->bp; + + // unrolled loop (MAXTDEPTH): + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + if (!(key.tret[depth++] = get_frame(&bp))) goto out; + key.tret[depth] = get_frame(&bp); + +out: + woke = wokeby.lookup(&pid); + if (woke) { + __builtin_memcpy(&key.wret, woke->ret, sizeof(key.wret)); + __builtin_memcpy(&key.waker, woke->name, TASK_COMM_LEN); + wokeby.delete(&pid); + } + + val = counts.lookup_or_init(&key, &zero); + (*val) += delta; + return 0; +} +""" +if args.pid: + filter = 'pid == %s' % args.pid +elif args.useronly: + filter = '!(p->flags & PF_KTHREAD)' +else: + filter = '1' +bpf_text = bpf_text.replace('FILTER', filter) +if debug: + print(bpf_text) + +# initialize BPF +b = BPF(text=bpf_text) +b.attach_kprobe(event="finish_task_switch", fn_name="oncpu") +b.attach_kprobe(event="try_to_wake_up", fn_name="waker") +matched = b.num_open_kprobes() +if matched == 0: + print("0 functions traced. Exiting.") + exit() + +# header +if not folded: + print("Tracing blocked time (us) by kernel off-CPU and waker stack", + end="") + if duration < 99999999: + print(" for %d secs." % duration) + else: + print("... Hit Ctrl-C to end.") + +# output +while (1): + try: + sleep(duration) + except KeyboardInterrupt: + # as cleanup can take many seconds, trap Ctrl-C: + signal.signal(signal.SIGINT, signal_ignore) + + if not folded: + print() + counts = b.get_table("counts") + for k, v in sorted(counts.items(), key=lambda counts: counts[1].value): + if folded: + # fold target stack + line = k.target + ";" + for i in reversed(range(0, maxtdepth)): + if k.tret[i] == 0: + continue + line = line + b.ksym(k.tret[i]) + if i != 0: + line = line + ";" + + # add delimiter + line = line + ";-" + + # fold waker stack + for i in range(0, maxwdepth): + line = line + ";" + if k.wret[i] == 0: + break + line = line + b.ksym(k.wret[i]) + if i != 0: + line = line + ";" + k.waker + + # print as a line + print("%s %d" % (line, v.value)) + else: + # print wakeup name then stack in reverse order + print(" %-16s %s" % ("waker:", k.waker)) + for i in reversed(range(0, maxwdepth)): + if k.wret[i] == 0: + continue + print(" %-16x %s" % (k.wret[i], + b.ksym(k.wret[i]))) + + # print delimiter + print(" %-16s %s" % ("-", "-")) + + # print default multi-line stack output + for i in range(0, maxtdepth): + if k.tret[i] == 0: + break + print(" %-16x %s" % (k.tret[i], + b.ksym(k.tret[i]))) + print(" %-16s %s" % ("target:", k.target)) + print(" %d\n" % v.value) + counts.clear() + + if not folded: + print("Detaching...") + exit() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/syscount.py new/bcc-v0.3.0/tools/syscount.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/syscount.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/syscount.py 2017-03-10 03:07:20.000000000 +0100 @@ -23,7 +23,8 @@ # cat syscallent.h | awk -F, '{ gsub(/[ \t"}]/, "", $4); # gsub(/[ \t/*]/, "", $5); # print " "$5": \""$4"\","; } -# BEGIN { print "syscalls = {" } END { print "}" }' +# BEGIN { print "syscalls = {" } +# END { print "}" }' # syscalls = { 0: "read", @@ -459,7 +460,7 @@ def agg_colval(key): if args.process: - return "%-6d %-15s" % (key.value, comm_for_pid(key.value)) + return "%-6d %-15s" % (key.value, comm_for_pid(key.value)) else: return syscalls.get(key.value, "[unknown: %d]" % key.value) @@ -478,7 +479,8 @@ data = bpf["data"] print("[%s]" % strftime("%H:%M:%S")) print("%-22s %8s %16s" % (agg_colname, "COUNT", time_colname)) - for k, v in sorted(data.items(), key=lambda kv: -kv[1].total_ns)[:args.top]: + for k, v in sorted(data.items(), + key=lambda kv: -kv[1].total_ns)[:args.top]: if k.value == 0xFFFFFFFF: continue # happens occasionally, we don't need it print(("%-22s %8d " + ("%16.6f" if args.milliseconds else "%16.3f")) % @@ -497,4 +499,3 @@ if not args.interval: print_stats() break - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/tplist.py new/bcc-v0.3.0/tools/tplist.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/tplist.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/tplist.py 2017-03-10 03:07:20.000000000 +0100 @@ -64,17 +64,17 @@ print_tpoint(category, event) def print_usdt_argument_details(location): - for idx in xrange(0, location.num_arguments): + for idx in range(0, location.num_arguments): arg = location.get_argument(idx) - print(" argument #%d %s" % (idx+1, arg)) + print(" argument #%d %s" % (idx + 1, arg)) def print_usdt_details(probe): if args.verbosity > 0: print(probe) if args.verbosity > 1: - for idx in xrange(0, probe.num_locations): + for idx in range(0, probe.num_locations): loc = probe.get_location(idx) - print(" location #%d %s" % (idx+1, loc)) + print(" location #%d %s" % (idx + 1, loc)) print_usdt_argument_details(loc) else: print(" %d location(s)" % probe.num_locations) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/trace.py new/bcc-v0.3.0/tools/trace.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/trace.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/trace.py 2017-03-10 03:07:20.000000000 +0100 @@ -53,7 +53,8 @@ self.probe_num = Probe.probe_count self.probe_name = "probe_%s_%d" % \ (self._display_function(), self.probe_num) - self.probe_name = re.sub(r'[^A-Za-z0-9_]', '_', self.probe_name) + self.probe_name = re.sub(r'[^A-Za-z0-9_]', '_', + self.probe_name) def __str__(self): return "%s:%s:%s FLT=%s ACT=%s/%s" % (self.probe_type, @@ -81,7 +82,8 @@ text).groups() self._parse_spec(spec) - self.signature = sig[1:-1] if sig else None # remove the parens + # Remove the parens + self.signature = sig[1:-1] if sig else None if self.signature and self.probe_type in ['u', 't']: self._bail("USDT and tracepoint probes can't have " + "a function signature; use arg1, arg2, " + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/ucalls.py new/bcc-v0.3.0/tools/ucalls.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/ucalls.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/ucalls.py 2017-03-10 03:07:20.000000000 +0100 @@ -257,7 +257,8 @@ bpf["systimes"].items()) data.extend(syscalls) else: - syscalls = map(lambda kv: (bpf.ksym(kv[0].value), (kv[1].value, 0)), + syscalls = map(lambda kv: (bpf.ksym(kv[0].value), + (kv[1].value, 0)), bpf["syscounts"].items()) data.extend(syscalls) @@ -294,8 +295,8 @@ data = data[-args.top:] for key, value in data: if args.latency: - time = value[1]/1000000.0 if args.milliseconds else \ - value[1]/1000.0 + time = value[1] / 1000000.0 if args.milliseconds else \ + value[1] / 1000.0 print("%-50s %8d %6.2f" % (key, value[0], time)) else: print("%-50s %8d" % (key, value[0])) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/uflow.py new/bcc-v0.3.0/tools/uflow.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/uflow.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/uflow.py 2017-03-10 03:07:20.000000000 +0100 @@ -97,7 +97,7 @@ def enable_probe(probe_name, func_name, read_class, read_method, is_return): global program, trace_template, usdt depth = "*depth + 1" if not is_return else "*depth | (1ULL << 63)" - update = "++(*depth);" if not is_return else "if (*depth) --(*depth);" + update = "++(*depth);" if not is_return else "if (*depth) --(*depth);" filter_class = "if (!prefix_class(data.clazz)) { return 0; }" \ if args.clazz else "" filter_method = "if (!prefix_method(data.method)) { return 0; }" \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/ugc.py new/bcc-v0.3.0/tools/ugc.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/ugc.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/ugc.py 2017-03-10 03:07:20.000000000 +0100 @@ -134,8 +134,10 @@ bpf_probe_read(&event.string1, sizeof(event.string1), (void *)manager); bpf_probe_read(&event.string2, sizeof(event.string2), (void *)pool); """ - formatter = lambda e: "%s %s used=%d->%d max=%d->%d" % \ - (e.string1, e.string2, e.field1, e.field3, e.field2, e.field4) + + def formatter(e): + "%s %s used=%d->%d max=%d->%d" % \ + (e.string1, e.string2, e.field1, e.field3, e.field2, e.field4) probes.append(Probe("mem__pool__gc__begin", "mem__pool__gc__end", begin_save, end_save, formatter)) probes.append(Probe("gc__begin", "gc__end", @@ -155,8 +157,10 @@ event.field1 = e->field1; event.field2 = objs; """ - formatter = lambda event: "gen %d GC collected %d objects" % \ - (event.field1, event.field2) + + def formatter(event): + "gen %d GC collected %d objects" % \ + (event.field1, event.field2) probes.append(Probe("gc__start", "gc__done", begin_save, end_save, formatter)) # @@ -214,10 +218,10 @@ def print_event(cpu, data, size): event = ct.cast(data, ct.POINTER(GCEvent)).contents - elapsed = event.elapsed_ns/1000000 if args.milliseconds else \ - event.elapsed_ns/1000 + elapsed = event.elapsed_ns / 1000000 if args.milliseconds else \ + event.elapsed_ns / 1000 description = probes[event.probe_index].format(event) - if args.filter and not args.filter in description: + if args.filter and args.filter not in description: return print("%-8.3f %-8.2f %s" % (time.time() - start_ts, elapsed, description)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/uobjnew.py new/bcc-v0.3.0/tools/uobjnew.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/uobjnew.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/uobjnew.py 2017-03-10 03:07:20.000000000 +0100 @@ -110,7 +110,8 @@ usdt.enable_probe_or_bail("object__create", "object_alloc_entry") for thing in ["string", "hash", "array"]: program += create_template.replace("THETHING", thing) - usdt.enable_probe_or_bail("%s__create" % thing, "%s_alloc_entry" % thing) + usdt.enable_probe_or_bail("%s__create" % thing, + "%s_alloc_entry" % thing) # # C # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bcc-v0.2.0+git1488325605.4d0d430/tools/ustat.py new/bcc-v0.3.0/tools/ustat.py --- old/bcc-v0.2.0+git1488325605.4d0d430/tools/ustat.py 2017-03-01 00:46:45.000000000 +0100 +++ new/bcc-v0.3.0/tools/ustat.py 2017-03-10 03:07:20.000000000 +0100 @@ -244,8 +244,9 @@ counts.update(probe.get_counts(self.bpf)) targets.update(probe.targets) if self.args.sort: - counts = sorted(counts.items(), key=lambda kv: - -kv[1].get(self.args.sort.upper(), 0)) + sort_field = self.args.sort.upper() + counts = sorted(counts.items(), + key=lambda kv: -kv[1].get(sort_field, 0)) else: counts = sorted(counts.items(), key=lambda kv: kv[0]) for pid, stats in counts:
