]> git.proxmox.com Git - mirror_frr.git/commitdiff
tests: add --perf and --perf-options for profiling daemons
authorChristian Hopps <chopps@labn.net>
Mon, 24 Apr 2023 01:53:44 +0000 (21:53 -0400)
committerChristian Hopps <chopps@labn.net>
Mon, 24 Apr 2023 01:53:44 +0000 (21:53 -0400)
Signed-off-by: Christian Hopps <chopps@labn.net>
tests/topotests/conftest.py
tests/topotests/lib/topotest.py

index 8e4d13df7d14826d2e6f71696e269474365eb670..2b33aa24b051a4aa5cfb34edb59a45bb7da17a98 100755 (executable)
@@ -66,8 +66,8 @@ def pytest_addoption(parser):
         action="append",
         metavar="DAEMON[,ROUTER[,...]",
         help=(
-            "Tail-F of DAEMON log file. Specify routers in comma-separated list after "
-            "daemon to limit to a subset of routers"
+            "Tail-F the DAEMON log file on all or a subset of ROUTERs."
+            " Option can be given multiple times."
         ),
     )
 
@@ -103,6 +103,23 @@ def pytest_addoption(parser):
         help="Comma-separated list of networks to capture packets on, or 'all'",
     )
 
+    parser.addoption(
+        "--perf",
+        action="append",
+        metavar="DAEMON[,ROUTER[,...]",
+        help=(
+            "Collect performance data from given DAEMON on all or a subset of ROUTERs."
+            " Option can be given multiple times."
+        ),
+    )
+
+    parser.addoption(
+        "--perf-options",
+        metavar="OPTS",
+        default="-g",
+        help="Options to pass to `perf record`.",
+    )
+
     rundir_help = "directory for running in and log files"
     parser.addini("rundir", rundir_help, default="/tmp/topotests")
     parser.addoption("--rundir", metavar="DIR", help=rundir_help)
index 93daf0bd8c78d667bdbfafc907dc295727e26e9b..967f09ecbd900e6e1fb2e4975c9fe573b4d5d4b2 100644 (file)
@@ -1184,10 +1184,9 @@ def rlimit_atleast(rname, min_value, raises=False):
 
 
 def fix_netns_limits(ns):
-
     # Maximum read and write socket buffer sizes
-    sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2 ** 20])
-    sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2 ** 20])
+    sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2**20])
+    sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2**20])
 
     sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0)
     sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0)
@@ -1246,8 +1245,8 @@ def fix_host_limits():
     sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024)
 
     # Maximum read and write socket buffer sizes
-    sysctl_atleast(None, "net.core.rmem_max", 16 * 2 ** 20)
-    sysctl_atleast(None, "net.core.wmem_max", 16 * 2 ** 20)
+    sysctl_atleast(None, "net.core.rmem_max", 16 * 2**20)
+    sysctl_atleast(None, "net.core.wmem_max", 16 * 2**20)
 
     # Garbage Collection Settings for ARP and Neighbors
     sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024)
@@ -1289,7 +1288,6 @@ class Router(Node):
     "A Node with IPv4/IPv6 forwarding enabled"
 
     def __init__(self, name, *posargs, **params):
-
         # Backward compatibility:
         #   Load configuration defaults like topogen.
         self.config_defaults = configparser.ConfigParser(
@@ -1305,6 +1303,8 @@ class Router(Node):
             os.path.join(os.path.dirname(os.path.realpath(__file__)), "../pytest.ini")
         )
 
+        self.perf_daemons = {}
+
         # If this topology is using old API and doesn't have logdir
         # specified, then attempt to generate an unique logdir.
         self.logdir = params.get("logdir")
@@ -1724,6 +1724,16 @@ class Router(Node):
             ).split()[2]
             logger.info("{}: running version: {}".format(self.name, self.version))
 
+        perfds = {}
+        perf_options = g_pytest_config.get_option("--perf-options", "-g")
+        for perf in g_pytest_config.get_option("--perf", []):
+            if "," in perf:
+                daemon, routers = perf.split(",", 1)
+                perfds[daemon] = routers.split(",")
+            else:
+                daemon = perf
+                perfds[daemon] = ["all"]
+
         logd_options = {}
         for logd in g_pytest_config.get_option("--logd", []):
             if "," in logd:
@@ -1805,7 +1815,6 @@ class Router(Node):
                         tail_log_files.append(
                             "{}/{}/{}.log".format(self.logdir, self.name, daemon)
                         )
-
             if extra_opts:
                 cmdopt += " " + extra_opts
 
@@ -1832,6 +1841,23 @@ class Router(Node):
                 logger.info(
                     "%s: %s %s launched in gdb window", self, self.routertype, daemon
                 )
+            elif daemon in perfds and (self.name in perfds[daemon] or "all" in perfds[daemon]):
+                cmdopt += rediropt
+                cmd = " ".join(["perf record {} --".format(perf_options), binary, cmdopt])
+                p = self.popen(cmd)
+                self.perf_daemons[daemon] = p
+                if p.poll() and p.returncode:
+                    self.logger.error(
+                        '%s: Failed to launch "%s" (%s) with perf using: %s',
+                        self,
+                        daemon,
+                        p.returncode,
+                        cmd,
+                    )
+                else:
+                    logger.debug(
+                        "%s: %s %s started with perf", self, self.routertype, daemon
+                    )
             else:
                 if daemon != "snmpd":
                     cmdopt += " -d "