* [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).