From d1f9a992190921783337b71103d3525c3381bedf Mon Sep 17 00:00:00 2001 From: lifeng68 Date: Tue, 15 Dec 2020 17:30:01 +0800 Subject: [PATCH 14/14] api: add get container metrics api Signed-off-by: lifeng68 --- src/lxc/lxccontainer.c | 174 +++++++++++++++++++++++++++++++++++++++++ src/lxc/lxccontainer.h | 42 ++++++++++ 2 files changed, 216 insertions(+) diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c index cbb67f321..9202b73ff 100644 --- a/src/lxc/lxccontainer.c +++ b/src/lxc/lxccontainer.c @@ -5752,6 +5752,179 @@ static bool do_lxcapi_set_start_timeout(struct lxc_container *c, unsigned int s WRAP_API_1(bool, lxcapi_set_start_timeout, unsigned int) +static uint64_t metrics_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item) +{ + char buf[80] = {0}; + int len = 0; + uint64_t val = 0; + + len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path); + if (len <= 0) { + DEBUG("unable to read cgroup item %s", item); + return 0; + } + + val = strtoull(buf, NULL, 0); + return val; +} + +static inline bool is_blk_metrics_read(const char *value) +{ + return strcmp(value, "Read") == 0; +} + +static inline bool is_blk_metrics_write(const char *value) +{ + return strcmp(value, "Write") == 0; +} + +static inline bool is_blk_metrics_total(const char *value) +{ + return strcmp(value, "Total") == 0; +} + +static void metrics_get_blk_stats(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, struct lxc_blkio_metrics *stats) +{ +#define BUFSIZE 4096 + char buf[BUFSIZE] = {0}; + int i = 0; + int len = 0; + char **lines = NULL; + char **cols = NULL; + + len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path); + if (len <= 0) { + DEBUG("unable to read cgroup item %s", item); + return; + } + + lines = lxc_string_split_and_trim(buf, '\n'); + if (lines == NULL) { + return; + } + + (void)memset(stats, 0, sizeof(struct lxc_blkio_metrics)); + + for (i = 0; lines[i]; i++) { + cols = lxc_string_split_and_trim(lines[i], ' '); + if (cols == NULL) { + goto err_out; + } + if (is_blk_metrics_read(cols[1])) { + stats->read += strtoull(cols[2], NULL, 0); + } else if (is_blk_metrics_write(cols[1])) { + stats->write += strtoull(cols[2], NULL, 0); + } + if (is_blk_metrics_total(cols[0])) { + stats->total = strtoull(cols[1], NULL, 0); + } + + lxc_free_array((void **)cols, free); + } +err_out: + lxc_free_array((void **)lines, free); + return; +} + +static uint64_t metrics_match_get_ull(struct lxc_container *c, struct cgroup_ops *cgroup_ops, const char *item, const char *match, int column) +{ +#define BUFSIZE 4096 + char buf[BUFSIZE] = {0}; + int i = 0; + int j = 0; + int len = 0; + uint64_t val = 0; + char **lines = NULL; + char **cols = NULL; + size_t matchlen = 0; + + len = cgroup_ops->get(cgroup_ops, item, buf, sizeof(buf), c->name, c->config_path); + if (len <= 0) { + DEBUG("unable to read cgroup item %s", item); + goto err_out; + } + + lines = lxc_string_split_and_trim(buf, '\n'); + if (lines == NULL) { + goto err_out; + } + + matchlen = strlen(match); + for (i = 0; lines[i]; i++) { + if (strncmp(lines[i], match, matchlen) != 0) { + continue; + } + + cols = lxc_string_split_and_trim(lines[i], ' '); + if (cols == NULL) { + goto err1; + } + for (j = 0; cols[j]; j++) { + if (j == column) { + val = strtoull(cols[j], NULL, 0); + break; + } + } + lxc_free_array((void **)cols, free); + break; + } +err1: + lxc_free_array((void **)lines, free); +err_out: + return val; +} + +/* isulad add get container metrics */ +static bool do_lxcapi_get_container_metrics(struct lxc_container *c, struct lxc_container_metrics *metrics) +{ + call_cleaner(cgroup_exit) struct cgroup_ops *cgroup_ops = NULL; + const char *state = NULL; + if (c == NULL || c->lxc_conf == NULL || metrics == NULL) { + return false; + } + + state = c->state(c); + metrics->state = state; + + if (!is_stopped(c)) { + metrics->init = c->init_pid(c); + } else { + metrics->init = -1; + } + + cgroup_ops = cgroup_init(c->lxc_conf); + if (cgroup_ops == NULL) { + return false; + } + + metrics->cpu_use_nanos = metrics_get_ull(c, cgroup_ops, "cpuacct.usage"); + metrics->pids_current = metrics_get_ull(c, cgroup_ops, "pids.current"); + + metrics->cpu_use_user = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "user", 1); + metrics->cpu_use_sys = metrics_match_get_ull(c, cgroup_ops, "cpuacct.stat", "system", 1); + + // Try to read CFQ stats available on all CFQ enabled kernels first + metrics_get_blk_stats(c, cgroup_ops, "blkio.io_serviced_recursive", &metrics->io_serviced); + if (metrics->io_serviced.read == 0 && metrics->io_serviced.write == 0 && metrics->io_serviced.total == 0) { + metrics_get_blk_stats(c, cgroup_ops, "blkio.throttle.io_service_bytes", &metrics->io_service_bytes); + metrics_get_blk_stats(c, cgroup_ops, "blkio.throttle.io_serviced", &metrics->io_serviced); + } else { + metrics_get_blk_stats(c, cgroup_ops, "blkio.io_service_bytes_recursive", &metrics->io_service_bytes); + } + + metrics->mem_used = metrics_get_ull(c, cgroup_ops, "memory.usage_in_bytes"); + metrics->mem_limit = metrics_get_ull(c, cgroup_ops, "memory.limit_in_bytes"); + metrics->kmem_used = metrics_get_ull(c, cgroup_ops, "memory.kmem.usage_in_bytes"); + metrics->kmem_limit = metrics_get_ull(c, cgroup_ops, "memory.kmem.limit_in_bytes"); + + metrics->cache = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "cache", 1); + metrics->cache_total = metrics_match_get_ull(c, cgroup_ops, "memory.stat", "total_cache", 1); + + return true; +} + +WRAP_API_1(bool, lxcapi_get_container_metrics, struct lxc_container_metrics *) + #endif #ifdef HAVE_ISULAD @@ -5924,6 +6097,7 @@ struct lxc_container *lxc_container_new(const char *name, const char *configpath c->clean_container_resource = lxcapi_clean_container_resource; c->get_container_pids = lxcapi_get_container_pids; c->set_start_timeout = lxcapi_set_start_timeout; + c->get_container_metrics = lxcapi_get_container_metrics; #endif return c; diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h index 2951ac7b4..e30bf6161 100644 --- a/src/lxc/lxccontainer.h +++ b/src/lxc/lxccontainer.h @@ -40,6 +40,37 @@ struct lxc_mount { int version; }; +struct lxc_blkio_metrics { + uint64_t read; + uint64_t write; + uint64_t total; +}; + +struct lxc_container_metrics { + /* State of container */ + const char *state; + /* The process ID of the init container */ + pid_t init; + /* Current pids */ + uint64_t pids_current; + /* CPU usage */ + uint64_t cpu_use_nanos; + uint64_t cpu_use_user; + uint64_t cpu_use_sys; + /* BlkIO usage */ + struct lxc_blkio_metrics io_service_bytes; + struct lxc_blkio_metrics io_serviced; + /* Memory usage */ + uint64_t mem_used; + uint64_t mem_limit; + /* Kernel Memory usage */ + uint64_t kmem_used; + uint64_t kmem_limit; + /* Cache usage */ + uint64_t cache; + uint64_t cache_total; +}; + /*! * An LXC container. * @@ -976,6 +1007,17 @@ struct lxc_container { * \return \c true on success, else \c false. */ bool (*set_start_timeout)(struct lxc_container *c, unsigned int start_timeout); + + /*! isulad add + * \brief An API call to set start timeout + * + * \param c Container. + * \param start_timeout Value of start timeout. + * + * \return \c true on success, else \c false. + */ + bool (*get_container_metrics)(struct lxc_container *c, struct lxc_container_metrics *metrics); + }; /*! -- 2.25.1