Soft Patch Panel
 help / color / mirror / Atom feed
* [spp] [PATCH 0/8] Add launch command to spp_primary
@ 2019-01-29 12:21 ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 1/8] shared: add func for getting dirname of secondary ogawa.yasufumi
                   ` (7 more replies)
  0 siblings, 8 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

This series of patches is to add `launch` command which is used to
launch secondary process from spp_primary. For this update, spp-ctl and
SPP CLI are also update to support the command.

Spp_primary receives the command via tcp port 5555 and launches
requested secondary process by running `sec_launcher.py` script. The
reason of calling from the script is to avoid secondary be child
process.

Spp-ctl has REST API of PUT method for launch commnad. Request body
consists of client ID, process name and options of the secondary.
Here is an example.

  # request body params for launching spp_nfv with sec ID 1
  {
    "client_id": 1,
    "proc_name": "spp_nfv",
    "eal": {
      "-l": "1-2", "-m": 512, ...
    },
    "app": {
      "-n": 1, "-s": "127.0.0.1:6666"
    }
  }

You can try to launch it from spp-ctl with curl command.

  $ curl -X PUT -d '{"client_id":1,"proc_name":"spp_nfv",...}' \
    http://127.0.0.1:7777/v1/primary/launch

SPP CLI supports launch command more easy way to use. You notice that
some of mandatory options such as `--proc-type` are missing. These
options are completed in SPP CLI before sending the request. This
comamnd also supporting TAB completion as same as other commands.

  spp > pri; launch nfv 1 -l 1-2 -m 512 -- -n 1 -s ...


Yasufumi Ogawa (8):
  shared: add func for getting dirname of secondary
  spp_priamry: add launch command
  spp-ctl: add launch command support for REST API
  controller: add launch sub command in pri
  spp_primary: change launching sec to use python
  tools/helpers: add sec launcher script
  controller: revise completion of launch command
  tools/helpers: move cpu_layout script to helpers

 log/README.txt                     |   8 ++
 src/controller/commands/pri.py     | 211 +++++++++++++++++++++++++++++++++++--
 src/controller/commands/server.py  |   4 +
 src/controller/shell.py            |   3 +
 src/controller/shell_lib/common.py |   8 +-
 src/controller/spp_common.py       |   4 +
 src/primary/main.c                 | 174 ++++++++++++++++++++++++++++--
 src/shared/common.c                |  26 +++++
 src/shared/common.h                |   5 +-
 src/spp-ctl/spp_proc.py            | 113 ++++++++++++++++++++
 src/spp-ctl/spp_webapi.py          |  11 ++
 tools/cpu_layout.py                | 144 -------------------------
 tools/helpers/cpu_layout.py        | 144 +++++++++++++++++++++++++
 tools/helpers/sec_launcher.py      |  10 ++
 14 files changed, 704 insertions(+), 161 deletions(-)
 create mode 100644 log/README.txt
 delete mode 100755 tools/cpu_layout.py
 create mode 100755 tools/helpers/cpu_layout.py
 create mode 100755 tools/helpers/sec_launcher.py

-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 1/8] shared: add func for getting dirname of secondary
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
@ 2019-01-29 12:21 ` ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 2/8] spp_priamry: add launch command ogawa.yasufumi
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

To inspect the name of directory of secondary from process name, add
function `get_sec_dir()`. It is used to find the path of exec file of
secondary process.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/shared/common.c | 26 ++++++++++++++++++++++++++
 src/shared/common.h |  3 +++
 2 files changed, 29 insertions(+)

diff --git a/src/shared/common.c b/src/shared/common.c
index 0943dd3..9c244e5 100644
--- a/src/shared/common.c
+++ b/src/shared/common.c
@@ -89,3 +89,29 @@ parse_server(char **server_ip, int *server_port, char *server_addr)
 	*server_port = atoi(token);
 	return 0;
 }
+
+/* Get directory name of given proc_name */
+int get_sec_dir(char *proc_name, char *dir_name)
+{
+	if (!strcmp(proc_name, "spp_nfv")) {
+		sprintf(dir_name, "%s", "nfv");
+		RTE_LOG(DEBUG, SHARED, "Found dir 'nfv' for '%s'.\n",
+				proc_name);
+	} else if (!strcmp(proc_name, "spp_vf")) {
+		sprintf(dir_name, "%s", "vf");
+		RTE_LOG(DEBUG, SHARED, "Found dir 'vf' for '%s'.\n",
+				proc_name);
+	} else if (!strcmp(proc_name, "spp_mirror")) {
+		sprintf(dir_name, "%s", "mirror");
+		RTE_LOG(DEBUG, SHARED, "Found dir 'mirror' for '%s'.\n",
+				proc_name);
+	} else if (!strcmp(proc_name, "spp_pcap")) {
+		sprintf(dir_name, "%s", "pcap");
+		RTE_LOG(DEBUG, SHARED, "Found dir 'pcap' for '%s'.\n",
+				proc_name);
+	} else {
+		RTE_LOG(DEBUG, SHARED, "No dir found for '%s'.\n",
+				proc_name);
+	}
+	return 0;
+}
diff --git a/src/shared/common.h b/src/shared/common.h
index d5c62bd..75e9576 100644
--- a/src/shared/common.h
+++ b/src/shared/common.h
@@ -127,6 +127,9 @@ int set_user_log_debug(int num_user_log);
 int parse_num_clients(uint16_t *num_clients, const char *clients);
 int parse_server(char **server_ip, int *server_port, char *server_addr);
 
+/* Get directory name of given proc_name */
+int get_sec_dir(char *proc_name, char *dir_name);
+
 extern uint8_t lcore_id_used[RTE_MAX_LCORE];
 
 #endif
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 2/8] spp_priamry: add launch command
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 1/8] shared: add func for getting dirname of secondary ogawa.yasufumi
@ 2019-01-29 12:21 ` ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 3/8] spp-ctl: add launch command support for REST API ogawa.yasufumi
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

To launch secondary process from spp_primary, add `launch` command.

Spp_primary accepts a request consists of lcore_id, process name and
options for the process. Here is an example of spp_nfv with lcore_id 1.

  launch 1 spp_nfv -l 1-2 --proc-type secondary ... -- -n 1 ...

Options are exactly same as command line options of secondary process
and lcore_id should be same as sec ID indicated with `-n` option.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 log/README.txt      |   8 ++++
 src/primary/main.c  | 125 ++++++++++++++++++++++++++++++++++++++++++++++++----
 src/shared/common.h |   2 +-
 3 files changed, 126 insertions(+), 9 deletions(-)
 create mode 100644 log/README.txt

diff --git a/log/README.txt b/log/README.txt
new file mode 100644
index 0000000..3c274b1
--- /dev/null
+++ b/log/README.txt
@@ -0,0 +1,8 @@
+Log directory for SPP processes.
+
+The name of log file of secondary process is decided with a combination
+of process name and secondary ID. For example, name of log of `nfv:1` is
+`spp_nfv-1.log`, or `vf:2` is `spp_vf-2.log`.
+
+The name of log of primary process is simply `spp_primary.log` because
+it has no process ID.
diff --git a/src/primary/main.c b/src/primary/main.c
index a039b3f..c4ad33a 100644
--- a/src/primary/main.c
+++ b/src/primary/main.c
@@ -7,19 +7,24 @@
 #include <arpa/inet.h>
 #include <inttypes.h>
 #include <poll.h>
+#include <fcntl.h>
 
 #include <rte_atomic.h>
 #include <rte_eth_ring.h>
 
+#include "shared/common.h"
 #include "args.h"
-#include "common.h"
 #include "init.h"
 #include "primary.h"
 
-/* Buffer sizes of status message of primary. Total must be equal to MSG_SIZE */
+/*
+ * Buffer sizes of status message of primary. Total number of size
+ * must be equal to MSG_SIZE 2048 defined in `shared/common.h`.
+ */
 #define PRI_BUF_SIZE_PHY 512
 #define PRI_BUF_SIZE_RING 1512
 
+#define SPP_PATH_LEN 1024  /* seems enough for path of spp procs */
 #define POLL_TIMEOUT_MS 100
 
 static sig_atomic_t on = 1;
@@ -161,6 +166,91 @@ do_send(int *connected, int *sock, char *str)
 	return 0;
 }
 
+/*
+ * Launch secondary process of given name and ID.
+ *
+ * This function finds the path of secondary by using the path of spp_primary
+ * itself and given proc name.
+ *
+ * Output of launched proc is sent to logfile located in `log` directory in
+ * the project root, and the name of logfile is a combination of proc name
+ * and ID, such as `spp_nfv-1.log`.
+ */
+static int
+launch_sec_proc(char *sec_name, int sec_id, char **sec_args)
+{
+	char path_spp_pri[SPP_PATH_LEN];
+	char path_spp_sec[SPP_PATH_LEN];
+	char path_spp_log[SPP_PATH_LEN];
+	char *token_list[48] = {NULL};  /* contains elems of path_spp_pri */
+	int num_token = 0;
+	int i = 0;
+	char sec_dirname[16];
+	int fd;
+
+	/* Get path of spp_primary to be used to find secondary */
+	if (readlink("/proc/self/exe",
+				path_spp_pri, sizeof(path_spp_pri)) == -1)
+		RTE_LOG(INFO, PRIMARY,
+				"Failed to find exec file of spp_primary.\n");
+	else {
+		/* Tokenize path of spp_primary */
+		token_list[i] = strtok(path_spp_pri, "/");
+		while (token_list[i] != NULL) {
+			// RTE_LOG(DEBUG, PRIMARY, "token: %s\n",
+			//		token_list[i]);
+			i++;
+			num_token++;
+			token_list[i] = strtok(NULL, "/");
+		}
+
+		/* Get src dir */
+		for (i = 0; i < num_token - 3; i++) {
+			if (i == 0)
+				sprintf(path_spp_sec, "/%s/", token_list[i]);
+			else
+				sprintf(path_spp_sec + strlen(path_spp_sec),
+						"%s/", token_list[i]);
+		}
+
+		/* logfile is located in the parent dir of src */
+		sprintf(path_spp_log, "%s../log/%s-%d.log",
+				path_spp_sec, sec_name, sec_id);
+
+		/* path of sec proc */
+		get_sec_dir(sec_name, sec_dirname);
+		sprintf(path_spp_sec + strlen(path_spp_sec), "%s/%s/%s",
+				sec_dirname, token_list[num_token-2],
+				sec_name);
+
+		RTE_LOG(DEBUG, PRIMARY, "sec_cmd: '%s'.\n", path_spp_sec);
+		RTE_LOG(DEBUG, PRIMARY, "sec_log: '%s'.\n", path_spp_log);
+
+		pid_t pid;
+		pid = fork();
+		if (pid < 0)
+			RTE_LOG(ERR, PRIMARY,
+					"Failed to open secondary proc.\n");
+		else if (pid == 0) {
+			/* Open log file with permission `0664` */
+			fd = open(path_spp_log, O_RDWR | O_CREAT, 0664);
+
+			/* change to output of stdout and stderr to logfile */
+			dup2(fd, 1);
+			dup2(fd, 2);
+			close(fd);
+
+			if (execv(path_spp_sec, sec_args) != 0)
+				RTE_LOG(ERR, PRIMARY,
+					"Failed to open child proc!\n");
+		} else
+			RTE_LOG(INFO, PRIMARY, "Launched '%s' with ID %d.\n",
+					path_spp_sec, sec_id);
+	}
+
+	return 0;
+}
+
 /**
  * Retrieve all of statu of ports as JSON format managed by primary.
  *
@@ -280,26 +370,45 @@ static int
 parse_command(char *str)
 {
 	char *token_list[MAX_PARAMETER] = {NULL};
+	char sec_name[16];
+	char *sec_args[48] = {NULL};
+	int num_args = 0;
 	int ret = 0;
 	int i = 0;
 
+	memset(sec_name, '\0', 16);
+
 	/* tokenize the user commands from controller */
 	token_list[i] = strtok(str, " ");
 	while (token_list[i] != NULL) {
-		RTE_LOG(DEBUG, PRIMARY, "token %d = %s\n", i, token_list[i]);
+		RTE_LOG(DEBUG, PRIMARY,
+				"parse_command: received token %d = %s\n",
+				i, token_list[i]);
+		if (i == 2)
+			sprintf(sec_name, "%s", token_list[i]);
+		else if (i > 2)
+			sec_args[i-3] = token_list[i];
+			num_args++;
 		i++;
 		token_list[i] = strtok(NULL, " ");
 	}
 
 	if (!strcmp(token_list[0], "status")) {
-		RTE_LOG(DEBUG, PRIMARY, "status\n");
+		RTE_LOG(DEBUG, PRIMARY, "'status' command received.\n");
 
+		/* Clear str and token_list nouse already */
 		memset(str, '\0', MSG_SIZE);
 		ret = get_status_json(str);
 
+	} else if (!strcmp(token_list[0], "launch")) {
+		RTE_LOG(DEBUG, PRIMARY, "'%s' command received.\n",
+				token_list[0]);
+
+		ret = launch_sec_proc(sec_name,
+				strtod(token_list[1], NULL), sec_args);
+
 	} else if (!strcmp(token_list[0], "exit")) {
-		RTE_LOG(DEBUG, PRIMARY, "exit\n");
-		RTE_LOG(DEBUG, PRIMARY, "stop\n");
+		RTE_LOG(DEBUG, PRIMARY, "'exit' command received.\n");
 		cmd = STOP;
 		ret = -1;
 
@@ -395,6 +504,8 @@ main(int argc, char *argv[])
 	int flg_exit;  // used as res of parse_command() to exit if -1
 	int ret;
 
+	set_user_log_debug(1);
+
 	/* Register signals */
 	signal(SIGINT, turn_off);
 
@@ -402,8 +513,6 @@ main(int argc, char *argv[])
 	if (init(argc, argv) < 0)
 		return -1;
 
-	set_user_log_debug(1);
-
 	RTE_LOG(INFO, PRIMARY, "Finished Process Init.\n");
 
 	/* clear statistics */
diff --git a/src/shared/common.h b/src/shared/common.h
index 75e9576..9b8d897 100644
--- a/src/shared/common.h
+++ b/src/shared/common.h
@@ -19,7 +19,7 @@
 #define MAX_CLIENT  99
 
 // The number of tokens in a command line.
-#define MAX_PARAMETER 10
+#define MAX_PARAMETER 48
 
 #define NO_FLAGS 0
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 3/8] spp-ctl: add launch command support for REST API
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 1/8] shared: add func for getting dirname of secondary ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 2/8] spp_priamry: add launch command ogawa.yasufumi
@ 2019-01-29 12:21 ` ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 4/8] controller: add launch sub command in pri ogawa.yasufumi
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

This update is to add REST API support of launch command for
spp_primary. This launch API of PUT accepts a name of secondary
process, secondary ID and all args of the application. Here is an
example.

  $ curl -X PUT -d '{"client_id":1,"proc_name":"spp_nfv","eal":...}' \
    http://127.0.0.1:7777/v1/primary/launch

This launch API supports only spp_nfv currently. Other secondaries can
be launched, but have no components and do not work correctly.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/spp-ctl/spp_proc.py   | 113 ++++++++++++++++++++++++++++++++++++++++++++++
 src/spp-ctl/spp_webapi.py |  11 +++++
 2 files changed, 124 insertions(+)

diff --git a/src/spp-ctl/spp_proc.py b/src/spp-ctl/spp_proc.py
index 19a5e53..a2d2adf 100644
--- a/src/spp-ctl/spp_proc.py
+++ b/src/spp-ctl/spp_proc.py
@@ -18,6 +18,76 @@ TYPE_NFV = "nfv"
 TYPE_MIRROR = "mirror"
 TYPE_PCAP = "pcap"
 
+EAL_OPTS = [
+        # Lcore-related options
+        '-c',  # core mask
+        '-l',  # core list
+        '--lcores',  # core map
+        '--master-lcore',  # is used as master
+        '-s',  # Hex bitmask of cores used as service cores
+        # Device-related options
+        '-b', '--pci-blacklist',  # Blacklist of PCI devs
+        '-w', '--pci-whitelist',  # Blacklist of PCI devs
+        '--vdev',  # Add a virtual device
+        '-d',  # Load external drivers
+        '--no-pci',  # Disable PCI bus.
+        # Multiprocessing-related options
+        '--proc-type',  # primamry, secondary or auto
+        # Memory-related options
+        '-n',  # number of memory channels
+        '-r',  # number of memory ranks
+        '-m',  # Amount of memory to preallocate at startup
+        '--in-memory',  # not create shared data and run entirely in memory
+        '--iova-mode',  # Force IOVA mode to a specific value
+        # Debugging options
+        '--no-shconf',  # No shared files created (no sec)
+        '--no-huge',  # Use anonymous memory instead of hugepages (no sec)
+        '--log-level',   # Specify log level, e.g. '--log-level eal:8'
+        '--file-prefix',  # Use different shared file prefix for a DPDK process
+        # Linux-specific EAL parameters
+        '--create-uio-dev',  # Create /dev/uioX bound to igb_uio
+        '--vmware-tsc-map',  # Use VMware TSC map instead of native RDTSC
+        '--no-hpet',  # Do not use the HPET timer
+        '--vfio-intr',  # Use specified interrupt mode for devs bound to VFIO
+        '--base-virtaddr',  # use different addr for all memmaps of primary
+        '--legacy-mem',  # Use legacy DPDK memory allocation mode
+        '--socket-mem',  # Preallocate memory per socket
+        '--socket-limit',  # Place a per-socket upper limit on memory
+        '--single-file-segments',  # Create fewer files in hugetlbfs
+        '--huge-dir',  # Use specified hugetlbfs instead of autodetected
+        '--huge-unlink',  # Unlink hugepage files after creating
+        '--match-allocations',  # Free hugepages back as original
+        '--syslog'  # syslog facility
+        ]
+
+APP_OPTS = {
+        'spp_nfv':
+        [
+            '-n',  # sec ID
+            '-s',  # address and port
+            '--vhost-client'  # enable client mode
+            ],
+        'spp_vf':
+        [
+            '--client-id',  # sec ID
+            '-s',  # address nd port
+            '--vhost-client'  # enable client mode
+            ],
+        'spp_mirror':
+        [
+            '--client-id',  # sec ID
+            '-s',  # address nd port
+            '--vhost-client'  # enable client mode
+            ],
+        'spp_pcap':
+        [
+            '--client-id',  # sec ID
+            '-s',  # address nd port
+            '-i',
+            '--output',
+            '--limit_file_size'
+            ]}
+
 
 def exec_command(func):
     """Decorator for Sending command and receiving reply.
@@ -227,6 +297,49 @@ class PrimaryProc(SppProc):
         return "clear"
 
     @exec_command
+    def do_launch_sec_proc(self, args):
+        proc_name = args['proc_name']
+        sec_id = args['client_id']
+
+        eal_opts = []
+        app_opts = []
+
+        # EAL options
+        # Check mandatory options
+        mandatory = False
+        for key in ['-c', '-l', '--lcores']:
+            if key in args['eal'].keys():
+                mandatory = True
+                break
+        if mandatory is False:
+            return None
+
+        if '--proc-type' not in args['eal'].keys():
+            return None
+
+        for opt in EAL_OPTS:
+            if opt in args['eal'].keys():
+                eal_opts.append(opt)
+                val = args['eal'][opt]
+                if (val is not None) and (val != ''):
+                    eal_opts.append(str(val))
+
+        if proc_name in APP_OPTS.keys():
+            for opt in APP_OPTS[proc_name]:
+                if opt in args['app'].keys():
+                    app_opts.append(opt)
+                    val = args['app'][opt]
+                    if (val is not None) and (val != ''):
+                        app_opts.append(str(val))
+
+        query = "launch {} {} {} -- {}".format(
+                sec_id, proc_name, ' '.join(eal_opts), ' '.join(app_opts))
+
+        LOG.info("Query: {}".format(query))
+
+        return query
+
+    @exec_command
     def do_exit(self):
         return "exit"
 
diff --git a/src/spp-ctl/spp_webapi.py b/src/spp-ctl/spp_webapi.py
index 0fd2f2a..10b4098 100644
--- a/src/spp-ctl/spp_webapi.py
+++ b/src/spp-ctl/spp_webapi.py
@@ -436,10 +436,13 @@ class V1PrimaryHandler(BaseHandler):
         self.set_route()
 
         self.install(self.make_response)
+        self.install(self.get_body)
 
     def set_route(self):
         self.route('/status', 'GET', callback=self.get_status)
         self.route('/status', 'DELETE', callback=self.clear_status)
+        self.route('/launch', 'PUT',
+                   callback=self.launch_sec_proc)
         self.route('/', 'DELETE', callback=self.pri_exit)
 
     def _get_proc(self):
@@ -464,6 +467,14 @@ class V1PrimaryHandler(BaseHandler):
         proc = self._get_proc()
         proc.clear()
 
+    def launch_sec_proc(self, body):  # the arg should be "body"
+        for key in ['client_id', 'proc_name', 'eal', 'app']:
+            if key not in body:
+                raise KeyRequired(key)
+
+        proc = self._get_proc()
+        proc.do_launch_sec_proc(body)
+
     def pri_exit(self):
         proc = self._get_proc()
         self.ctrl.do_exit(proc.type, proc.id)
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 4/8] controller: add launch sub command in pri
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
                   ` (2 preceding siblings ...)
  2019-01-29 12:21 ` [spp] [PATCH 3/8] spp-ctl: add launch command support for REST API ogawa.yasufumi
@ 2019-01-29 12:21 ` ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 5/8] spp_primary: change launching sec to use python ogawa.yasufumi
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

As launch is supported in spp_primary and spp-ctl, add `launch` in
`pri` command. It takes type of secondary process, ID and arguments
of launching the process. Here is an example.

  spp > pri; launch nfv 1 -l 1,2 -m 512 -- -n 1 -s 192.168.1.100:7777

You notice that secondary ID is used two times. The reason is it is used
for completion. If you specify secondary ID, it completes typical
arguments. You just correct a few params of command line.

  spp > pri; launch  # press TAB
  mirror  nfv     pcap     nfv
  spp > pri; launch nfv  # press TAB
  1 10 11 12 2 3 4 ...
  spp > pri; launch nfv 1  # press TAB and correct some params
  spp > pri; launch nfv 1 -l 1,2 -m 512 -- -n 1 -s 192.168.1.100:7777

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/controller/commands/pri.py     | 190 +++++++++++++++++++++++++++++++++++--
 src/controller/commands/server.py  |   4 +
 src/controller/shell.py            |   3 +
 src/controller/shell_lib/common.py |   8 +-
 src/controller/spp_common.py       |   4 +
 5 files changed, 201 insertions(+), 8 deletions(-)

diff --git a/src/controller/commands/pri.py b/src/controller/commands/pri.py
index 750d355..577952c 100644
--- a/src/controller/commands/pri.py
+++ b/src/controller/commands/pri.py
@@ -1,6 +1,10 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2018 Nippon Telegraph and Telephone Corporation
 
+from __future__ import absolute_import
+
+from .. import spp_common
+from ..shell_lib import common
 
 class SppPrimary(object):
     """Exec SPP primary command.
@@ -13,7 +17,7 @@ class SppPrimary(object):
     """
 
     # All of primary commands used for validation and completion.
-    PRI_CMDS = ['status', 'clear']
+    PRI_CMDS = ['status', 'launch', 'clear']
 
     def __init__(self, spp_ctl_cli):
         self.spp_ctl_cli = spp_ctl_cli
@@ -21,11 +25,15 @@ class SppPrimary(object):
     def run(self, cmd):
         """Called from do_pri() to Send command to primary process."""
 
-        if not (cmd in self.PRI_CMDS):
-            print("Invalid pri command: '%s'" % cmd)
+        tmpary = cmd.split(' ')
+        subcmd = tmpary[0]
+        params = tmpary[1:]
+
+        if not (subcmd in self.PRI_CMDS):
+            print("Invalid pri command: '%s'" % subcmd)
             return None
 
-        if cmd == 'status':
+        if subcmd == 'status':
             res = self.spp_ctl_cli.get('primary/status')
             if res is not None:
                 if res.status_code == 200:
@@ -36,7 +44,10 @@ class SppPrimary(object):
                 else:
                     print('Error: unknown response.')
 
-        elif cmd == 'clear':
+        elif subcmd == 'launch':
+            self._run_launch(params)
+
+        elif subcmd == 'clear':
             res = self.spp_ctl_cli.delete('primary/status')
             if res is not None:
                 if res.status_code == 204:
@@ -122,10 +133,175 @@ class SppPrimary(object):
         Called from complete_pri() to complete primary command.
         """
 
+        candidates = []
+        tokens = line.split(' ')
+
+        mytemplate = "-l 1,2 -m 512 -- -n {} -s {}"
+
+        # Show sub commands
+        if len(tokens) == 2:
+            # Add sub commands
+            candidates = candidates + self.PRI_CMDS[:]
+
+        # Show args of `launch` sub command.
+        elif len(tokens) == 3 and tokens[1] == 'launch':
+            for pt in spp_common.SEC_TYPES:
+                candidates.append('{}'.format(pt))
+
+        elif len(tokens) == 4 and tokens[1] == 'launch':
+            if tokens[2] in spp_common.SEC_TYPES:
+                candidates = [
+                        str(i+1) for i in range(spp_common.MAX_SECONDARY)]
+
+        elif len(tokens) == 5 and tokens[1] == 'launch':
+            if (tokens[2] in spp_common.SEC_TYPES) and \
+                    (int(tokens[3])-1 in range(spp_common.MAX_SECONDARY)):
+                sid = tokens[3]
+                candidates = [mytemplate.format(sid, common.current_server_addr())]
+
         if not text:
-            completions = self.PRI_CMDS[:]
+            completions = candidates
         else:
-            completions = [p for p in self.PRI_CMDS
+            completions = [p for p in candidates
                            if p.startswith(text)
                            ]
+
+        #completions.append("nof_tokens:{}".format(len(tokens)))
+
         return completions
+
+    def _get_sec_ids(self):
+        sec_ids = []
+        res = self.spp_ctl_cli.get('processes')
+        if res is not None:
+            if res.status_code == 200:
+                for proc in res.json():
+                    if proc['type'] != 'primary':
+                        sec_ids.append(proc['client-id'])
+            elif res.status_code in self.rest_common_error_codes:
+                # Print default error message
+                pass
+            else:
+                print('Error: unknown response.')
+        return sec_ids
+
+    def _setup_opts_dict(self, opts_list):
+        """Setup options for sending to spp-ctl as a request body.
+
+        Options is setup from given list. If option has no value, None is
+        assgined for the value. For example,
+          ['-l', '1-2', --no-pci, '-m', '512', ...]
+          => {'-l':'1-2', '--no-pci':None, '-m':'512', ...}
+        """
+        prekey = None
+        opts_dict = {}
+        for opt in opts_list:
+            if opt.startswith('-'):
+                opts_dict[opt] = None
+                prekey = opt
+            else:
+                if prekey is not None:
+                    opts_dict[prekey] = opt
+                    prekey = None
+        return opts_dict
+
+    def _run_launch(self, params):
+        """Launch secondary process.
+
+        Parse `launch` command and send request to spp-ctl. Params of the
+        consists of proc type, sec ID and arguments. It allows to skip some
+        params which are completed. All of examples here are same.
+
+        spp > lanuch nfv -l 1-2 ... -- -n 1 ...  # sec ID '1' is skipped
+        spp > lanuch spp_nfv -l 1-2 ... -- -n 1 ...  # use 'spp_nfv' insteads
+        """
+
+        # Check params
+        if len(params) < 2:
+            print('Invalid syntax! Proc type, ID and options are required.')
+            print('E.g. "nfv 1 -l 1-2 -m 512 -- -n 1 -s 192.168.1.100:6666"')
+            return None
+
+        proc_type = params[0]
+        if params[1].startswith('-'):
+            sec_id = None  # should be found later, or failed
+            args = params[1:]
+        else:
+            sec_id = params[1]
+            args = params[2:]
+
+        if proc_type.startswith('spp_') is not True:
+            proc_name = 'spp_' + proc_type
+        else:
+            proc_name = proc_type
+            proc_type = proc_name[len('spp_'):]
+
+        if proc_type not in spp_common.SEC_TYPES:
+            print("'{}' is not supported in launch cmd.".format(proc_type))
+            return None
+
+        if '--' not in args:
+            print('Arguments should include separator "--".')
+            return None
+
+        # Setup options of JSON sent to spp-ctl. Here is an example for
+        # launching spp_nfv.
+        #   {
+        #      'client_id': '1',
+        #      'proc_name': 'spp_nfv',
+        #      'eal': {'-l': '1-2', '-m': '1024', ...},
+        #      'app': {'-n': '1', '-s': '192.168.1.100:6666'}
+        #   }
+        idx_separator = args.index('--')
+        eal_opts = args[:idx_separator]
+        app_opts = args[(idx_separator+1):]
+
+        if '--proc-type' not in args:
+            eal_opts.append('--proc-type')
+            eal_opts.append('secondary')
+
+        opts = {'proc_name': proc_name}
+        opts['eal'] = self._setup_opts_dict(eal_opts)
+        opts['app'] = self._setup_opts_dict(app_opts)
+
+        # Try to find sec_id from app options.
+        if sec_id is None:
+            if (proc_type == 'nfv') and ('-n' in opts['app']):
+                sec_id = opts['app']['-n']
+            elif ('--client-id' in opts['app']):  # vf, mirror or pcap
+                sec_id = opts['app']['--client-id']
+            else:
+                print('Secondary ID is required!')
+                return None
+
+        if sec_id in self._get_sec_ids():
+            print("Cannot add '{}' already used.".format(sec_id))
+            return None
+
+        opts['client_id'] = sec_id
+
+        # Complete or correct sec_id.
+        if proc_name == 'spp_nfv':
+            if '-n' in opts['app'].keys():
+                if (opts['app']['-n'] != sec_id):
+                    opts['app']['-n'] = sec_id
+            else:
+                opts['app']['-n'] = sec_id
+        else:  # vf, mirror or pcap
+            if '--client-id' in opts['app'].keys():
+                if (opts['app']['--client-id'] != sec_id):
+                    opts['app']['--client-id'] = sec_id
+            else:
+                opts['app']['--client-id'] = sec_id
+
+        # Send request for launch secondary.
+        res = self.spp_ctl_cli.put('primary/launch', opts)
+        if res is not None:
+            error_codes = self.spp_ctl_cli.rest_common_error_codes
+            if res.status_code == 204:
+                print('Succeeded to launch {}:{}.'.format(
+                    proc_type, sec_id))
+            elif res.status_code in error_codes:
+                pass
+            else:
+                print('Error: unknown response.')
diff --git a/src/controller/commands/server.py b/src/controller/commands/server.py
index eece1f6..c2bda9d 100644
--- a/src/controller/commands/server.py
+++ b/src/controller/commands/server.py
@@ -123,6 +123,10 @@ class SppCtlServer(object):
         if len(self.spp_cli_objs) > idx:
             self.current_idx = idx
             cli_obj = self.spp_cli_objs[self.current_idx]
+
+            common.set_current_server_addr(
+                 cli_obj.ip_addr, cli_obj.port)
+
             print('Switch spp-ctl to "{}: {}:{}".'.format(
                  idx+1, cli_obj.ip_addr, cli_obj.port))
         else:
diff --git a/src/controller/shell.py b/src/controller/shell.py
index 6dc6514..1fb9867 100644
--- a/src/controller/shell.py
+++ b/src/controller/shell.py
@@ -47,6 +47,9 @@ class Shell(cmd.Cmd, object):
         self.init_spp_procs()
         self.spp_topo = topo.SppTopo(self.spp_ctl_cli, {}, self.topo_size)
 
+        common.set_current_server_addr(
+                self.spp_ctl_cli.ip_addr, self.spp_ctl_cli.port)
+
     def init_spp_procs(self):
         """Initialize delegators of SPP processes.
 
diff --git a/src/controller/shell_lib/common.py b/src/controller/shell_lib/common.py
index 3c59cca..87263d0 100644
--- a/src/controller/shell_lib/common.py
+++ b/src/controller/shell_lib/common.py
@@ -3,7 +3,7 @@
 # Copyright(c) 2017-2018 Nippon Telegraph and Telephone Corporation
 
 import os
-
+from .. import spp_common
 
 def decorate_dir(curdir, filelist):
     """Add '/' the end of dirname for path completion
@@ -122,3 +122,9 @@ def is_valid_port(port_num):
         return False
 
     return True
+
+def current_server_addr():
+    return spp_common.cur_server_addr
+
+def set_current_server_addr(ipaddr, port):
+    spp_common.cur_server_addr = '{}:{}'.format(ipaddr, port)
diff --git a/src/controller/spp_common.py b/src/controller/spp_common.py
index 1a15bcc..c94d175 100644
--- a/src/controller/spp_common.py
+++ b/src/controller/spp_common.py
@@ -7,6 +7,10 @@ import os
 
 PORT_TYPES = ['phy', 'ring', 'vhost', 'pcap', 'nullpmd']
 
+SEC_TYPES = ['nfv', 'vf', 'mirror', 'pcap']
+
+cur_server_addr = None
+
 # Maximum num of sock queues for secondaries
 MAX_SECONDARY = 16
 
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 5/8] spp_primary: change launching sec to use python
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
                   ` (3 preceding siblings ...)
  2019-01-29 12:21 ` [spp] [PATCH 4/8] controller: add launch sub command in pri ogawa.yasufumi
@ 2019-01-29 12:21 ` ogawa.yasufumi
  2019-01-29 12:21 ` [spp] [PATCH 6/8] tools/helpers: add sec launcher script ogawa.yasufumi
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

Spp_primary launches secondary directly from execv() and makes it a
child process. However, it cannot launch other than spp_nfv in healthly.

This patch is to change launching secondary via python script
`sec_launcher.py` placed in `tools/helpers/` to avoid this issue.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/primary/main.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 56 insertions(+), 7 deletions(-)

diff --git a/src/primary/main.c b/src/primary/main.c
index c4ad33a..bb25c1b 100644
--- a/src/primary/main.c
+++ b/src/primary/main.c
@@ -25,6 +25,16 @@
 #define PRI_BUF_SIZE_RING 1512
 
 #define SPP_PATH_LEN 1024  /* seems enough for path of spp procs */
+#define NOF_TOKENS 48  /* seems enough to contain tokens */
+/* should be contain extra two tokens for `python` and path of launcher */
+#define NOF_CMD_LIST (NOF_TOKENS + 2)
+
+#define LAUNCH_CMD "python"
+#define LCMD_LEN 8
+
+#define LAUNCHER_NAME "sec_launcher.py"
+#define LAUNCHER_LEN 16
+
 #define POLL_TIMEOUT_MS 100
 
 static sig_atomic_t on = 1;
@@ -182,7 +192,17 @@ launch_sec_proc(char *sec_name, int sec_id, char **sec_args)
 	char path_spp_pri[SPP_PATH_LEN];
 	char path_spp_sec[SPP_PATH_LEN];
 	char path_spp_log[SPP_PATH_LEN];
-	char *token_list[48] = {NULL};  /* contains elems of path_spp_pri */
+
+	char cmd[LCMD_LEN];  /* Command for launcher */
+	char launcher[LAUNCHER_LEN];  /* Name of launcher script */
+	char path_launcher[SPP_PATH_LEN];
+
+	/* Contains elems of path_spp_pri */
+	char *token_list[NOF_TOKENS] = {NULL};
+
+	/* Contains cmd and args for execvp() */
+	char *cmd_list[NOF_CMD_LIST] = {NULL};
+
 	int num_token = 0;
 	int i = 0;
 	char sec_dirname[16];
@@ -204,7 +224,7 @@ launch_sec_proc(char *sec_name, int sec_id, char **sec_args)
 			token_list[i] = strtok(NULL, "/");
 		}
 
-		/* Get src dir */
+		/* Get path of `src` dir used as a basename */
 		for (i = 0; i < num_token - 3; i++) {
 			if (i == 0)
 				sprintf(path_spp_sec, "/%s/", token_list[i]);
@@ -213,17 +233,45 @@ launch_sec_proc(char *sec_name, int sec_id, char **sec_args)
 						"%s/", token_list[i]);
 		}
 
-		/* logfile is located in the parent dir of src */
+		/* Dir of logfile is located in the parent dir of src */
 		sprintf(path_spp_log, "%s../log/%s-%d.log",
 				path_spp_sec, sec_name, sec_id);
 
+		/* Setup cmd list */
+		memset(cmd, '\0', sizeof(cmd));
+		sprintf(cmd, "%s", LAUNCH_CMD);
+		cmd_list[0] = cmd;
+
+		/* Path of launcher is `spp/tools/helpers/sec_launcher.py` */
+		memset(launcher, '\0', sizeof(launcher));
+		sprintf(launcher, "%s", LAUNCHER_NAME);
+		memset(path_launcher, '\0', sizeof(path_launcher));
+		sprintf(path_launcher, "%s../tools/helpers/%s",
+				path_spp_sec, launcher);
+		cmd_list[1] = path_launcher;
+
 		/* path of sec proc */
 		get_sec_dir(sec_name, sec_dirname);
 		sprintf(path_spp_sec + strlen(path_spp_sec), "%s/%s/%s",
 				sec_dirname, token_list[num_token-2],
 				sec_name);
+		cmd_list[2] = path_spp_sec;
+
+		i = 0;
+		while (sec_args[i] != NULL) {
+			cmd_list[i+3] = sec_args[i];
+			i++;
+		}
+
+		/* Output debug log for checking tokens of cmd_list */
+		i = 0;
+		while (cmd_list[i] != NULL) {
+			RTE_LOG(DEBUG, PRIMARY, "launch, token[%2d] = %s\n",
+					i, cmd_list[i]);
+			i++;
+		}
 
-		RTE_LOG(DEBUG, PRIMARY, "sec_cmd: '%s'.\n", path_spp_sec);
+		RTE_LOG(DEBUG, PRIMARY, "sec_path: '%s'.\n", path_spp_sec);
 		RTE_LOG(DEBUG, PRIMARY, "sec_log: '%s'.\n", path_spp_log);
 
 		pid_t pid;
@@ -240,7 +288,8 @@ launch_sec_proc(char *sec_name, int sec_id, char **sec_args)
 			dup2(fd, 2);
 			close(fd);
 
-			if (execv(path_spp_sec, sec_args) != 0)
+			printf("%s\n", sec_args[0]);
+			if (execvp(cmd_list[0], cmd_list) != 0)
 				RTE_LOG(ERR, PRIMARY,
 					"Failed to open child proc!\n");
 		} else
@@ -371,7 +420,7 @@ parse_command(char *str)
 {
 	char *token_list[MAX_PARAMETER] = {NULL};
 	char sec_name[16];
-	char *sec_args[48] = {NULL};
+	char *sec_args[NOF_TOKENS] = {NULL};
 	int num_args = 0;
 	int ret = 0;
 	int i = 0;
@@ -382,7 +431,7 @@ parse_command(char *str)
 	token_list[i] = strtok(str, " ");
 	while (token_list[i] != NULL) {
 		RTE_LOG(DEBUG, PRIMARY,
-				"parse_command: received token %d = %s\n",
+				"parse command, token[%2d] = %s\n",
 				i, token_list[i]);
 		if (i == 2)
 			sprintf(sec_name, "%s", token_list[i]);
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 6/8] tools/helpers: add sec launcher script
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
                   ` (4 preceding siblings ...)
  2019-01-29 12:21 ` [spp] [PATCH 5/8] spp_primary: change launching sec to use python ogawa.yasufumi
@ 2019-01-29 12:21 ` ogawa.yasufumi
  2019-01-29 12:22 ` [spp] [PATCH 7/8] controller: revise completion of launch command ogawa.yasufumi
  2019-01-29 12:22 ` [spp] [PATCH 8/8] tools/helpers: move cpu_layout script to helpers ogawa.yasufumi
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:21 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

Add very simple script `sec_launcher.py` for launching secondary
process. This script is not specilized to launching and just checks
the number of args and run given command. Spp_primary responds to give
correct command line for launching.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 tools/helpers/sec_launcher.py | 10 ++++++++++
 1 file changed, 10 insertions(+)
 create mode 100755 tools/helpers/sec_launcher.py

diff --git a/tools/helpers/sec_launcher.py b/tools/helpers/sec_launcher.py
new file mode 100755
index 0000000..22399db
--- /dev/null
+++ b/tools/helpers/sec_launcher.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+# coding: utf-8
+"""SPP secondary launcher."""
+
+import sys
+import subprocess
+
+if len(sys.argv) > 1:
+    cmd = sys.argv[1:]
+    subprocess.call(cmd)
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 7/8] controller: revise completion of launch command
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
                   ` (5 preceding siblings ...)
  2019-01-29 12:21 ` [spp] [PATCH 6/8] tools/helpers: add sec launcher script ogawa.yasufumi
@ 2019-01-29 12:22 ` ogawa.yasufumi
  2019-01-29 12:22 ` [spp] [PATCH 8/8] tools/helpers: move cpu_layout script to helpers ogawa.yasufumi
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:22 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

To help users by reducing input of launch command, change to generate
options automatically from given secondary ID.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 src/controller/commands/pri.py | 31 ++++++++++++++++++++++++++-----
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/src/controller/commands/pri.py b/src/controller/commands/pri.py
index 577952c..7712ba2 100644
--- a/src/controller/commands/pri.py
+++ b/src/controller/commands/pri.py
@@ -136,7 +136,8 @@ class SppPrimary(object):
         candidates = []
         tokens = line.split(' ')
 
-        mytemplate = "-l 1,2 -m 512 -- -n {} -s {}"
+        base_core = 1  # shared among secondaries
+        mytemplate = "-l {},{} -m 512 -- {} {} -s {}"
 
         # Show sub commands
         if len(tokens) == 2:
@@ -156,8 +157,30 @@ class SppPrimary(object):
         elif len(tokens) == 5 and tokens[1] == 'launch':
             if (tokens[2] in spp_common.SEC_TYPES) and \
                     (int(tokens[3])-1 in range(spp_common.MAX_SECONDARY)):
+                ptype = tokens[2]
                 sid = tokens[3]
-                candidates = [mytemplate.format(sid, common.current_server_addr())]
+
+                if ptype == 'nfv':
+                    opt_sid = '-n'
+                else:
+                    opt_sid = '--client-id'
+
+                server_addr = common.current_server_addr()
+                server_addr = server_addr.replace('7777', '6666')
+
+                # Define rest of cores dynamically.
+                # TODO(yasufum) decide rest of cores considering used cores
+                if ptype == 'nfv':  # one core is enough
+                    rest_core = sid
+                elif ptype == 'vf':  # at least three cores
+                    rest_core = '{}-{}'.format(int(sid), int(sid)+2)
+                elif ptype == 'mirror':  # two cores
+                    rest_core = sid
+                elif ptype == 'pcap':  # at least two cores
+                    rest_core = '{}-{}'.format(int(sid), int(sid)+1)
+
+                candidates = [mytemplate.format(
+                    base_core, rest_core, opt_sid, sid, server_addr)]
 
         if not text:
             completions = candidates
@@ -166,8 +189,6 @@ class SppPrimary(object):
                            if p.startswith(text)
                            ]
 
-        #completions.append("nof_tokens:{}".format(len(tokens)))
-
         return completions
 
     def _get_sec_ids(self):
@@ -299,7 +320,7 @@ class SppPrimary(object):
         if res is not None:
             error_codes = self.spp_ctl_cli.rest_common_error_codes
             if res.status_code == 204:
-                print('Succeeded to launch {}:{}.'.format(
+                print('Send request to launch {}:{}.'.format(
                     proc_type, sec_id))
             elif res.status_code in error_codes:
                 pass
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [spp] [PATCH 8/8] tools/helpers: move cpu_layout script to helpers
  2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
                   ` (6 preceding siblings ...)
  2019-01-29 12:22 ` [spp] [PATCH 7/8] controller: revise completion of launch command ogawa.yasufumi
@ 2019-01-29 12:22 ` ogawa.yasufumi
  7 siblings, 0 replies; 9+ messages in thread
From: ogawa.yasufumi @ 2019-01-29 12:22 UTC (permalink / raw)
  To: ferruh.yigit, spp, ogawa.yasufumi

From: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>

Move `cpu_layout.py` to helpers for making clear the usage.

Signed-off-by: Yasufumi Ogawa <ogawa.yasufumi@lab.ntt.co.jp>
---
 tools/cpu_layout.py         | 144 --------------------------------------------
 tools/helpers/cpu_layout.py | 144 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+), 144 deletions(-)
 delete mode 100755 tools/cpu_layout.py
 create mode 100755 tools/helpers/cpu_layout.py

diff --git a/tools/cpu_layout.py b/tools/cpu_layout.py
deleted file mode 100755
index 58a2bd6..0000000
--- a/tools/cpu_layout.py
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/env python
-# SPDX-License-Identifier: BSD-3-Clause
-# Copyright(c) 2010-2014 Intel Corporation
-# Copyright(c) 2017 Cavium, Inc. All rights reserved.
-# Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
-
-from __future__ import print_function
-import argparse
-import json
-import sys
-try:
-    xrange  # Python 2
-except NameError:
-    xrange = range  # Python 3
-
-base_path = "/sys/devices/system/cpu"
-
-
-def parse_args():
-    parser = argparse.ArgumentParser(
-        description="Show CPU layout")
-
-    parser.add_argument(
-            "--json", action="store_true",
-            help="Output in JSON format")
-    return parser.parse_args()
-
-
-def get_max_cpus():
-    fd = open("{}/kernel_max".format(base_path))
-    max_cpus = int(fd.read())
-    fd.close()
-    return max_cpus
-
-
-def get_resource_info(max_cpus):
-    """Return a set of sockets, cores and core_map as a tuple."""
-    sockets = []
-    cores = []
-    core_map = {}
-
-    for cpu in xrange(max_cpus + 1):
-        try:
-            topo_path = "{}/cpu{}/topology".format(base_path, cpu)
-
-            # Get physical core ID.
-            fd = open("{}/core_id".format(topo_path))
-            core = int(fd.read())
-            fd.close()
-            if core not in cores:
-                cores.append(core)
-
-            fd = open("{}/physical_package_id".format(topo_path))
-            socket = int(fd.read())
-            fd.close()
-            if socket not in sockets:
-                sockets.append(socket)
-
-            key = (socket, core)
-            if key not in core_map:
-                core_map[key] = []
-            core_map[key].append(cpu)
-
-        except IOError:
-            continue
-
-        except Exception as e:
-            print(e)
-            break
-
-    return sockets, cores, core_map
-
-
-def print_header(cores, sockets):
-    print(format("=" * (47 + len(base_path))))
-    print("Core and Socket Information (as reported by '{}')".format(
-        base_path))
-    print("{}\n".format("=" * (47 + len(base_path))))
-    print("cores = ", cores)
-    print("sockets = ", sockets)
-    print("")
-
-
-def print_body(cores, sockets, core_map):
-    max_processor_len = len(str(len(cores) * len(sockets) * 2 - 1))
-    max_thread_count = len(list(core_map.values())[0])
-    max_core_map_len = (max_processor_len * max_thread_count) \
-        + len(", ") * (max_thread_count - 1) \
-        + len('[]') + len('Socket ')
-    max_core_id_len = len(str(max(cores)))
-
-    output = " ".ljust(max_core_id_len + len('Core '))
-    for s in sockets:
-        output += " Socket %s" % str(s).ljust(
-                max_core_map_len - len('Socket '))
-    print(output)
-
-    output = " ".ljust(max_core_id_len + len('Core '))
-    for s in sockets:
-        output += " --------".ljust(max_core_map_len)
-        output += " "
-    print(output)
-
-    for c in cores:
-        output = "Core %s" % str(c).ljust(max_core_id_len)
-        for s in sockets:
-            if (s, c) in core_map:
-                output += " " + str(core_map[(s, c)]).ljust(max_core_map_len)
-            else:
-                output += " " * (max_core_map_len + 1)
-        print(output)
-
-
-def core_map_to_json(core_map):
-    cpu_layout = []
-    cpu_sockets = {}
-    for (s, c), cpus in core_map.items():
-        if not (s in cpu_sockets):
-            cpu_sockets[s] = {}
-            cpu_sockets[s]["cores"] = []
-        cpu_sockets[s]["cores"].append({"core_id": c, "cpus": cpus})
-
-    for sid, val in cpu_sockets.items():
-        cpu_layout.append({"socket_id": sid, "cores": val["cores"]})
-
-    return json.dumps(cpu_layout)
-
-
-def main():
-    args = parse_args()
-
-    max_cpus = get_max_cpus()
-    sockets, cores, core_map = get_resource_info(max_cpus)
-
-    if args.json is True:
-        print(core_map_to_json(core_map))
-
-    else:
-        print_header(cores, sockets)
-        print_body(cores, sockets, core_map)
-
-
-if __name__ == '__main__':
-    main()
diff --git a/tools/helpers/cpu_layout.py b/tools/helpers/cpu_layout.py
new file mode 100755
index 0000000..58a2bd6
--- /dev/null
+++ b/tools/helpers/cpu_layout.py
@@ -0,0 +1,144 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2010-2014 Intel Corporation
+# Copyright(c) 2017 Cavium, Inc. All rights reserved.
+# Copyright(c) 2019 Nippon Telegraph and Telephone Corporation
+
+from __future__ import print_function
+import argparse
+import json
+import sys
+try:
+    xrange  # Python 2
+except NameError:
+    xrange = range  # Python 3
+
+base_path = "/sys/devices/system/cpu"
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(
+        description="Show CPU layout")
+
+    parser.add_argument(
+            "--json", action="store_true",
+            help="Output in JSON format")
+    return parser.parse_args()
+
+
+def get_max_cpus():
+    fd = open("{}/kernel_max".format(base_path))
+    max_cpus = int(fd.read())
+    fd.close()
+    return max_cpus
+
+
+def get_resource_info(max_cpus):
+    """Return a set of sockets, cores and core_map as a tuple."""
+    sockets = []
+    cores = []
+    core_map = {}
+
+    for cpu in xrange(max_cpus + 1):
+        try:
+            topo_path = "{}/cpu{}/topology".format(base_path, cpu)
+
+            # Get physical core ID.
+            fd = open("{}/core_id".format(topo_path))
+            core = int(fd.read())
+            fd.close()
+            if core not in cores:
+                cores.append(core)
+
+            fd = open("{}/physical_package_id".format(topo_path))
+            socket = int(fd.read())
+            fd.close()
+            if socket not in sockets:
+                sockets.append(socket)
+
+            key = (socket, core)
+            if key not in core_map:
+                core_map[key] = []
+            core_map[key].append(cpu)
+
+        except IOError:
+            continue
+
+        except Exception as e:
+            print(e)
+            break
+
+    return sockets, cores, core_map
+
+
+def print_header(cores, sockets):
+    print(format("=" * (47 + len(base_path))))
+    print("Core and Socket Information (as reported by '{}')".format(
+        base_path))
+    print("{}\n".format("=" * (47 + len(base_path))))
+    print("cores = ", cores)
+    print("sockets = ", sockets)
+    print("")
+
+
+def print_body(cores, sockets, core_map):
+    max_processor_len = len(str(len(cores) * len(sockets) * 2 - 1))
+    max_thread_count = len(list(core_map.values())[0])
+    max_core_map_len = (max_processor_len * max_thread_count) \
+        + len(", ") * (max_thread_count - 1) \
+        + len('[]') + len('Socket ')
+    max_core_id_len = len(str(max(cores)))
+
+    output = " ".ljust(max_core_id_len + len('Core '))
+    for s in sockets:
+        output += " Socket %s" % str(s).ljust(
+                max_core_map_len - len('Socket '))
+    print(output)
+
+    output = " ".ljust(max_core_id_len + len('Core '))
+    for s in sockets:
+        output += " --------".ljust(max_core_map_len)
+        output += " "
+    print(output)
+
+    for c in cores:
+        output = "Core %s" % str(c).ljust(max_core_id_len)
+        for s in sockets:
+            if (s, c) in core_map:
+                output += " " + str(core_map[(s, c)]).ljust(max_core_map_len)
+            else:
+                output += " " * (max_core_map_len + 1)
+        print(output)
+
+
+def core_map_to_json(core_map):
+    cpu_layout = []
+    cpu_sockets = {}
+    for (s, c), cpus in core_map.items():
+        if not (s in cpu_sockets):
+            cpu_sockets[s] = {}
+            cpu_sockets[s]["cores"] = []
+        cpu_sockets[s]["cores"].append({"core_id": c, "cpus": cpus})
+
+    for sid, val in cpu_sockets.items():
+        cpu_layout.append({"socket_id": sid, "cores": val["cores"]})
+
+    return json.dumps(cpu_layout)
+
+
+def main():
+    args = parse_args()
+
+    max_cpus = get_max_cpus()
+    sockets, cores, core_map = get_resource_info(max_cpus)
+
+    if args.json is True:
+        print(core_map_to_json(core_map))
+
+    else:
+        print_header(cores, sockets)
+        print_body(cores, sockets, core_map)
+
+
+if __name__ == '__main__':
+    main()
-- 
2.7.4

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-01-29 12:24 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-29 12:21 [spp] [PATCH 0/8] Add launch command to spp_primary ogawa.yasufumi
2019-01-29 12:21 ` [spp] [PATCH 1/8] shared: add func for getting dirname of secondary ogawa.yasufumi
2019-01-29 12:21 ` [spp] [PATCH 2/8] spp_priamry: add launch command ogawa.yasufumi
2019-01-29 12:21 ` [spp] [PATCH 3/8] spp-ctl: add launch command support for REST API ogawa.yasufumi
2019-01-29 12:21 ` [spp] [PATCH 4/8] controller: add launch sub command in pri ogawa.yasufumi
2019-01-29 12:21 ` [spp] [PATCH 5/8] spp_primary: change launching sec to use python ogawa.yasufumi
2019-01-29 12:21 ` [spp] [PATCH 6/8] tools/helpers: add sec launcher script ogawa.yasufumi
2019-01-29 12:22 ` [spp] [PATCH 7/8] controller: revise completion of launch command ogawa.yasufumi
2019-01-29 12:22 ` [spp] [PATCH 8/8] tools/helpers: move cpu_layout script to helpers ogawa.yasufumi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).