267 lines
7.8 KiB
Diff
267 lines
7.8 KiB
Diff
From d1f9a992190921783337b71103d3525c3381bedf Mon Sep 17 00:00:00 2001
|
|
From: lifeng68 <lifeng68@huawei.com>
|
|
Date: Tue, 15 Dec 2020 17:30:01 +0800
|
|
Subject: [PATCH 14/14] api: add get container metrics api
|
|
|
|
Signed-off-by: lifeng68 <lifeng68@huawei.com>
|
|
---
|
|
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
|
|
|