tools: continue adding --ebpf support (#1986)

Use argparse in cachestat, add --ebpf support.

Add --ebpf support for u* tools, finalize language sorting.

Remove sole --ebpf string on usage line in tcpsubnet.
diff --git a/tools/lib/ucalls.py b/tools/lib/ucalls.py
index b2d165c..1a0fe21 100755
--- a/tools/lib/ucalls.py
+++ b/tools/lib/ucalls.py
@@ -49,6 +49,8 @@
     help="verbose mode: print the BPF program (for debugging purposes)")
 parser.add_argument("-m", "--milliseconds", action="store_true",
     help="report times in milliseconds (default is microseconds)")
+parser.add_argument("--ebpf", action="store_true",
+    help=argparse.SUPPRESS)
 args = parser.parse_args()
 
 language = args.language
@@ -243,10 +245,12 @@
 else:
     usdt = None
 
-if args.verbose:
-    if usdt:
+if args.ebpf or args.verbose:
+    if args.verbose and usdt:
         print(usdt.get_text())
     print(program)
+    if args.ebpf:
+        exit()
 
 bpf = BPF(text=program, usdt_contexts=[usdt] if usdt else [])
 if args.syscalls:
diff --git a/tools/lib/uflow.py b/tools/lib/uflow.py
index 8419c88..fb306e3 100755
--- a/tools/lib/uflow.py
+++ b/tools/lib/uflow.py
@@ -39,6 +39,8 @@
     help="trace only calls to classes starting with this prefix")
 parser.add_argument("-v", "--verbose", action="store_true",
     help="verbose mode: print the BPF program (for debugging purposes)")
+parser.add_argument("--ebpf", action="store_true",
+    help=argparse.SUPPRESS)
 args = parser.parse_args()
 
 usdt = USDT(pid=args.pid)
@@ -165,9 +167,12 @@
     print("No language detected; use -l to trace a language.")
     exit(1)
 
-if args.verbose:
-    print(usdt.get_text())
+if args.ebpf or args.verbose:
+    if args.verbose:
+        print(usdt.get_text())
     print(program)
+    if args.ebpf:
+        exit()
 
 bpf = BPF(text=program, usdt_contexts=[usdt])
 print("Tracing method calls in %s process %d... Ctrl-C to quit." %
diff --git a/tools/lib/ugc.py b/tools/lib/ugc.py
index 9f4d258..8288910 100755
--- a/tools/lib/ugc.py
+++ b/tools/lib/ugc.py
@@ -4,7 +4,7 @@
 # ugc  Summarize garbage collection events in high-level languages.
 #      For Linux, uses BCC, eBPF.
 #
-# USAGE: ugc [-v] [-m] [-M MSEC] [-F FILTER] {java,python,ruby,node} pid
+# USAGE: ugc [-v] [-m] [-M MSEC] [-F FILTER] {java,node,python,ruby} pid
 #
 # Copyright 2016 Sasha Goldshtein
 # Licensed under the Apache License, Version 2.0 (the "License")
@@ -18,7 +18,7 @@
 import time
 import os
 
-languages = ["java", "python", "ruby", "node"]
+languages = ["java", "node", "python", "ruby"]
 
 examples = """examples:
     ./ugc -l java 185        # trace Java GCs in process 185
@@ -40,6 +40,8 @@
     help="display only GCs longer than this many milliseconds")
 parser.add_argument("-F", "--filter", type=str,
     help="display only GCs whose description contains this text")
+parser.add_argument("--ebpf", action="store_true",
+    help=argparse.SUPPRESS)
 args = parser.parse_args()
 
 usdt = USDT(pid=args.pid)
@@ -150,6 +152,21 @@
     probes.append(Probe("gc__begin", "gc__end",
                         "", "", lambda _: "no additional info available"))
 #
+# Node
+#
+elif language == "node":
+    end_save = """
+    u32 gc_type = 0;
+    bpf_usdt_readarg(1, ctx, &gc_type);
+    event.field1 = gc_type;
+    """
+    descs = {"GC scavenge": 1, "GC mark-sweep-compact": 2,
+             "GC incremental mark": 4, "GC weak callbacks": 8}
+    probes.append(Probe("gc__start", "gc__done", "", end_save,
+                  lambda e: str.join(", ",
+                                     [desc for desc, val in descs.items()
+                                      if e.field1 & val != 0])))
+#
 # Python
 #
 elif language == "python":
@@ -179,21 +196,6 @@
                         "", "", lambda _: "GC mark stage"))
     probes.append(Probe("gc__sweep__begin", "gc__sweep__end",
                         "", "", lambda _: "GC sweep stage"))
-#
-# Node
-#
-elif language == "node":
-    end_save = """
-    u32 gc_type = 0;
-    bpf_usdt_readarg(1, ctx, &gc_type);
-    event.field1 = gc_type;
-    """
-    descs = {"GC scavenge": 1, "GC mark-sweep-compact": 2,
-             "GC incremental mark": 4, "GC weak callbacks": 8}
-    probes.append(Probe("gc__start", "gc__done", "", end_save,
-                  lambda e: str.join(", ",
-                                     [desc for desc, val in descs.items()
-                                      if e.field1 & val != 0])))
 
 else:
     print("No language detected; use -l to trace a language.")
@@ -204,9 +206,12 @@
     program += probe.generate()
     probe.attach()
 
-if args.verbose:
-    print(usdt.get_text())
+if args.ebpf or args.verbose:
+    if args.verbose:
+        print(usdt.get_text())
     print(program)
+    if args.ebpf:
+        exit()
 
 bpf = BPF(text=program, usdt_contexts=[usdt])
 print("Tracing garbage collections in %s process %d... Ctrl-C to quit." %
diff --git a/tools/lib/uobjnew.py b/tools/lib/uobjnew.py
index bcd69b4..e3b61ff 100755
--- a/tools/lib/uobjnew.py
+++ b/tools/lib/uobjnew.py
@@ -4,7 +4,7 @@
 # uobjnew  Summarize object allocations in high-level languages.
 #          For Linux, uses BCC, eBPF.
 #
-# USAGE: uobjnew [-h] [-T TOP] [-v] {java,ruby,c} pid [interval]
+# USAGE: uobjnew [-h] [-T TOP] [-v] {c,java,ruby} pid [interval]
 #
 # Copyright 2016 Sasha Goldshtein
 # Licensed under the Apache License, Version 2.0 (the "License")
@@ -18,7 +18,7 @@
 import os
 
 # C needs to be the last language.
-languages = ["java", "ruby", "c"]
+languages = ["c", "java", "ruby"]
 
 examples = """examples:
     ./uobjnew -l java 145         # summarize Java allocations in process 145
@@ -41,6 +41,8 @@
     help="number of largest types by allocated bytes to print")
 parser.add_argument("-v", "--verbose", action="store_true",
     help="verbose mode: print the BPF program (for debugging purposes)")
+parser.add_argument("--ebpf", action="store_true",
+    help=argparse.SUPPRESS)
 args = parser.parse_args()
 
 language = args.language
@@ -69,9 +71,24 @@
 usdt = USDT(pid=args.pid)
 
 #
+# C
+#
+if language == "c":
+    program += """
+int alloc_entry(struct pt_regs *ctx, size_t size) {
+    struct key_t key = {};
+    struct val_t *valp, zero = {};
+    key.size = size;
+    valp = allocs.lookup_or_init(&key, &zero);
+    valp->total_size += size;
+    valp->num_allocs += 1;
+    return 0;
+}
+    """
+#
 # Java
 #
-if language == "java":
+elif language == "java":
     program += """
 int alloc_entry(struct pt_regs *ctx) {
     struct key_t key = {};
@@ -120,30 +137,18 @@
         program += create_template.replace("THETHING", thing)
         usdt.enable_probe_or_bail("%s__create" % thing,
                                   "%s_alloc_entry" % thing)
-#
-# C
-#
-elif language == "c":
-    program += """
-int alloc_entry(struct pt_regs *ctx, size_t size) {
-    struct key_t key = {};
-    struct val_t *valp, zero = {};
-    key.size = size;
-    valp = allocs.lookup_or_init(&key, &zero);
-    valp->total_size += size;
-    valp->num_allocs += 1;
-    return 0;
-}
-    """
 
 else:
     print("No language detected; use -l to trace a language.")
     exit(1)
 
 
-if args.verbose:
-    print(usdt.get_text())
+if args.ebpf or args.verbose:
+    if args.verbose:
+        print(usdt.get_text())
     print(program)
+    if args.ebpf:
+        exit()
 
 bpf = BPF(text=program, usdt_contexts=[usdt])
 if language == "c":
diff --git a/tools/lib/ustat.py b/tools/lib/ustat.py
index 8b2f80f..7ac0967 100755
--- a/tools/lib/ustat.py
+++ b/tools/lib/ustat.py
@@ -147,6 +147,8 @@
             help="output interval, in seconds")
         parser.add_argument("count", nargs="?", default=99999999, type=int,
             help="number of outputs")
+        parser.add_argument("--ebpf", action="store_true",
+            help=argparse.SUPPRESS)
         self.args = parser.parse_args()
 
     def _create_probes(self):
@@ -197,8 +199,10 @@
 
     def _attach_probes(self):
         program = str.join('\n', [p.get_program() for p in self.probes])
-        if self.args.debug:
+        if self.args.debug or self.args.ebpf:
             print(program)
+            if self.args.ebpf:
+                exit()
             for probe in self.probes:
                 print("Attached to %s processes:" % probe.language,
                         str.join(', ', map(str, probe.targets)))
diff --git a/tools/lib/uthreads.py b/tools/lib/uthreads.py
index a96750f..fb54599 100755
--- a/tools/lib/uthreads.py
+++ b/tools/lib/uthreads.py
@@ -34,6 +34,8 @@
 parser.add_argument("pid", type=int, help="process id to attach to")
 parser.add_argument("-v", "--verbose", action="store_true",
     help="verbose mode: print the BPF program (for debugging purposes)")
+parser.add_argument("--ebpf", action="store_true",
+    help=argparse.SUPPRESS)
 args = parser.parse_args()
 
 usdt = USDT(pid=args.pid)
@@ -88,9 +90,12 @@
     usdt.enable_probe_or_bail("thread__start", "trace_start")
     usdt.enable_probe_or_bail("thread__stop", "trace_stop")
 
-if args.verbose:
-    print(usdt.get_text())
+if args.ebpf or args.verbose:
+    if args.verbose:
+        print(usdt.get_text())
     print(program)
+    if args.ebpf:
+        exit()
 
 bpf = BPF(text=program, usdt_contexts=[usdt])
 print("Tracing thread events in process %d (language: %s)... Ctrl-C to quit." %