[lxc-devel] [PATCH 2/2] add statistics to lxc-info
Dwight Engen
dwight.engen at oracle.com
Tue Nov 5 13:12:29 UTC 2013
On Mon, 4 Nov 2013 18:12:15 -0500
Stéphane Graber <stgraber at ubuntu.com> wrote:
> On Mon, Nov 04, 2013 at 05:35:19PM -0500, Dwight Engen wrote:
> > - added list_all_containers() which returns both defined and
> > active containers.
> >
> > - allow lxc-info to show more than one container, using regex for
> > the name
> >
>
> Wouldn't it be better to have list_all_containers be similar to
> list_(active|running)_containers and allow the caller to choose
> whether it wants to get a list of names or a list of lxc_container?
Hi Stéphane, yes I think it would be good to have them consistent. I
looked at that briefly, but the existing routines for building the
array might need refactoring or at least another parameter, and I
didn't need the "list" of containers in my use case. Let me look into it
a bit more, I'm sure it can be done :)
> > Signed-off-by: Dwight Engen <dwight.engen at oracle.com>
> > ---
> > doc/lxc-info.sgml.in | 65 ++++++++++++-
> > src/lxc/lxc_info.c | 257
> > +++++++++++++++++++++++++++++++++++++++++++++----
> > src/lxc/lxccontainer.c | 47 +++++++++ src/lxc/lxccontainer.h | 2
> > + 4 files changed, 349 insertions(+), 22 deletions(-)
> >
> > diff --git a/doc/lxc-info.sgml.in b/doc/lxc-info.sgml.in
> > index 819d5ca..791d780 100644
> > --- a/doc/lxc-info.sgml.in
> > +++ b/doc/lxc-info.sgml.in
> > @@ -47,20 +47,22 @@ Foundation, Inc., 51 Franklin Street, Fifth
> > Floor, Boston, MA 02110-1301 USA <refsynopsisdiv>
> > <cmdsynopsis>
> > <command>lxc-info</command>
> > - <arg choice="req">-n <replaceable>name</replaceable></arg>
> > + <arg choice="opt">-n <replaceable>name</replaceable></arg>
> > <arg choice="opt">-c <replaceable>KEY</replaceable></arg>
> > <arg choice="opt">-s</arg>
> > <arg choice="opt">-p</arg>
> > <arg choice="opt">-i</arg>
> > <arg choice="opt">-t <replaceable>state</replaceable></arg>
> > + <arg choice="opt">-S</arg>
> > + <arg choice="opt">-H</arg>
> > </cmdsynopsis>
> > </refsynopsisdiv>
> >
> > <refsect1>
> > <title>Description</title>
> > <para>
> > - <command>lxc-info</command> queries and shows information
> > about a
> > - container.
> > + <command>lxc-info</command> queries and shows information
> > about
> > + containers.
> > </para>
> > </refsect1>
> >
> > @@ -70,11 +72,20 @@ Foundation, Inc., 51 Franklin Street, Fifth
> > Floor, Boston, MA 02110-1301 USA
> > <varlistentry>
> > <term>
> > - <option>-n <replaceable>name</replaceable></option>
> > + <option><optional>-n
> > <replaceable>name</replaceable></optional></option> </term>
> > <listitem>
> > <para>
> > - The container name.
> > + The container name. It is interpreted as a regular
> > expression,
> > + so it is possible to get information on all
> > containers, several
> > + of them or just one. See
> > + <citerefentry>
> > +
> > <refentrytitle><command>regex</command></refentrytitle>
> > + <manvolnum>7</manvolnum>
> > + </citerefentry> for regular expression syntax. If not
> > specified,
> > + <replaceable>name</replaceable> will default to '.*'
> > which
> > + will give information on all containers in
> > + <command>lxcpath</command>.
> > </para>
> > </listitem>
> > </varlistentry>
> > @@ -126,6 +137,41 @@ Foundation, Inc., 51 Franklin Street, Fifth
> > Floor, Boston, MA 02110-1301 USA
> > <varlistentry>
> > <term>
> > + <option><optional>-S</optional></option>
> > + </term>
> > + <listitem>
> > + <para>
> > + Just print the container's statistics.
> > + Note that for performance reasons the kernel does not
> > account
> > + kernel memory use unless a kernel memory limit is set.
> > If a limit
> > + is not set, <command>lxc-info</command> will display
> > kernel memory
> > + use as 0. A limit can be set by specifying
> > + <programlisting>
> > + lxc.cgroup.memory.kmem.limit_in_bytes =
> > <replaceable>number</replaceable>
> > + </programlisting>
> > + in your container configuration file, see
> > + <citerefentry>
> > + <refentrytitle>lxc.conf</refentrytitle>
> > + <manvolnum>5</manvolnum>
> > + </citerefentry>.
> > + </para>
> > + </listitem>
> > + </varlistentry>
> > +
> > + <varlistentry>
> > + <term>
> > + <option><optional>-H</optional></option>
> > + </term>
> > + <listitem>
> > + <para>
> > + Print the container's statistics in raw, non-humanized
> > form. The
> > + default is to print statistics in humanized form.
> > + </para>
> > + </listitem>
> > + </varlistentry>
> > +
> > + <varlistentry>
> > + <term>
> > <option><optional>-t
> > <replaceable>state</replaceable></optional></option> </term>
> > <listitem>
> > @@ -152,6 +198,15 @@ Foundation, Inc., 51 Franklin Street, Fifth
> > Floor, Boston, MA 02110-1301 USA </varlistentry>
> >
> > <varlistentry>
> > + <term>lxc-info -n 'ubuntu.*'</term>
> > + <listitem>
> > + <para>
> > + Show information for all containers whose name starts
> > with ubuntu.
> > + </para>
> > + </listitem>
> > + </varlistentry>
> > +
> > + <varlistentry>
> > <term>lxc-info -n foo -t RUNNING</term>
> > <listitem>
> > <para>
> > diff --git a/src/lxc/lxc_info.c b/src/lxc/lxc_info.c
> > index aeaf9a8..a05d610 100644
> > --- a/src/lxc/lxc_info.c
> > +++ b/src/lxc/lxc_info.c
> > @@ -25,11 +25,14 @@
> > #include <stdbool.h>
> > #include <stdlib.h>
> > #include <unistd.h>
> > +#include <regex.h>
> > +#include <limits.h>
> > #include <libgen.h>
> > #include <sys/types.h>
> >
> > #include <lxc/lxc.h>
> > #include <lxc/log.h>
> > +#include <lxc/utils.h>
> > #include <lxc/lxccontainer.h>
> >
> > #include "commands.h"
> > @@ -38,6 +41,8 @@
> > static bool ips;
> > static bool state;
> > static bool pid;
> > +static bool stats;
> > +static bool humanize = true;
> > static char *test_state = NULL;
> > static char **key = NULL;
> > static int keys = 0;
> > @@ -53,6 +58,8 @@ static int my_parser(struct lxc_arguments* args,
> > int c, char* arg) case 'i': ips = true; break;
> > case 's': state = true; break;
> > case 'p': pid = true; break;
> > + case 'S': stats = true; break;
> > + case 'H': humanize = false; break;
> > case 't': test_state = arg; break;
> > }
> > return 0;
> > @@ -63,6 +70,8 @@ static const struct option my_longopts[] = {
> > {"ips", no_argument, 0, 'i'},
> > {"state", no_argument, 0, 's'},
> > {"pid", no_argument, 0, 'p'},
> > + {"stats", no_argument, 0, 'S'},
> > + {"no-humanize", no_argument, 0, 'H'},
> > {"state-is", required_argument, 0, 't'},
> > LXC_COMMON_OPTIONS,
> > };
> > @@ -79,33 +88,177 @@ Options :\n\
> > -c, --config=KEY show configuration variable KEY from
> > running container\n\ -i, --ips shows the IP addresses\n\
> > -p, --pid shows the process id of the init
> > container\n\
> > + -S, --stats shows usage stats\n\
> > + -H, --no-humanize shows stats as raw numbers, not
> > humanized\n\ -s, --state shows the state of the
> > container\n\ -t, --state-is=STATE test if current state is STATE\n\
> > returns success if it matches, false
> > otherwise\n",
> > + .name = ".*",
> > .options = my_longopts,
> > .parser = my_parser,
> > .checker = NULL,
> > };
> >
> > -int main(int argc, char *argv[])
> > +static void str_chomp(char *buf)
> > {
> > - struct lxc_container *c;
> > + char *ch;
> >
> > - int i;
> > + /* remove trailing whitespace from buf */
> > + for(ch = &buf[strlen(buf)-1];
> > + ch >= buf && (*ch == '\t' || *ch == '\n' || *ch == '
> > ');
> > + ch--)
> > + *ch = '\0';
> > +}
> >
> > - if (lxc_arguments_parse(&my_args, argc, argv))
> > - return -1;
> > +static void size_humanize(unsigned long long val, char *buf,
> > size_t bufsz) +{
> > + if (val > 1 << 30) {
> > + snprintf(buf, bufsz, "%u.%2.2u GiB",
> > + (int)(val >> 30),
> > + (int)(val & ((1 << 30) - 1)) /
> > 10737419);
> > + } else if (val > 1 << 20) {
> > + int x = val + 5243; /* for rounding */
> > + snprintf(buf, bufsz, "%u.%2.2u MiB",
> > + x >> 20, ((x & ((1 << 20) - 1)) * 100)
> > >> 20);
> > + } else if (val > 1 << 10) {
> > + int x = val + 5; /* for rounding */
> > + snprintf(buf, bufsz, "%u.%2.2u KiB",
> > + x >> 10, ((x & ((1 << 10) - 1)) * 100)
> > >> 10);
> > + } else {
> > + snprintf(buf, bufsz, "%u bytes", (int)val);
> > + }
> > +}
> >
> > - if (!my_args.log_file)
> > - my_args.log_file = "none";
> > +static unsigned long long str_size_humanize(char *iobuf, size_t
> > iobufsz) +{
> > + unsigned long long val;
> > + char *end = NULL;
> >
> > - if (lxc_log_init(my_args.name, my_args.log_file,
> > my_args.log_priority,
> > - my_args.progname, my_args.quiet,
> > my_args.lxcpath[0]))
> > - return -1;
> > + val = strtoull(iobuf, &end, 0);
> > + if (humanize) {
> > + if (*end == '\0' || *end == '\n')
> > + size_humanize(val, iobuf, iobufsz);
> > + else
> > + *iobuf = '\0';
> > + }
> > + return val;
> > +}
> > +
> > +static void print_net_stats(const char *name, const char *lxcpath)
> > +{
> > + int rc,netnr;
> > + unsigned long long rx_bytes = 0, tx_bytes = 0;
> > + char *ifname, *type;
> > + char path[PATH_MAX];
> > + char buf[256];
> > +
> > + for(netnr = 0; ;netnr++) {
> > + sprintf(buf, "lxc.network.%d.type", netnr);
> > + type = lxc_cmd_get_config_item(name, buf, lxcpath);
> > + if (!type)
> > + break;
> >
> > - c = lxc_container_new(my_args.name, my_args.lxcpath[0]);
> > - if (!c)
> > + if (!strcmp(type, "veth")) {
> > + sprintf(buf, "lxc.network.%d.veth.pair",
> > netnr);
> > + } else {
> > + sprintf(buf, "lxc.network.%d.link", netnr);
> > + }
> > + free(type);
> > + ifname = lxc_cmd_get_config_item(name, buf,
> > lxcpath);
> > + if (!ifname)
> > + return;
> > + printf("%-15s %s\n", "Link:", ifname);
> > +
> > + /* XXX: tx and rx are reversed from the host vs
> > container
> > + * perspective, print them from the container
> > perspective
> > + */
> > + snprintf(path, sizeof(path),
> > "/sys/class/net/%s/statistics/rx_bytes", ifname);
> > + rc = lxc_read_from_file(path, buf, sizeof(buf));
> > + if (rc > 0) {
> > + str_chomp(buf);
> > + rx_bytes = str_size_humanize(buf,
> > sizeof(buf));
> > + printf("%-15s %s\n", " TX bytes:", buf);
> > + }
> > +
> > + snprintf(path, sizeof(path),
> > "/sys/class/net/%s/statistics/tx_bytes", ifname);
> > + rc = lxc_read_from_file(path, buf, sizeof(buf));
> > + if (rc > 0) {
> > + str_chomp(buf);
> > + tx_bytes = str_size_humanize(buf,
> > sizeof(buf));
> > + printf("%-15s %s\n", " RX bytes:", buf);
> > + }
> > +
> > + sprintf(buf, "%llu", rx_bytes + tx_bytes);
> > + str_size_humanize(buf, sizeof(buf));
> > + printf("%-15s %s\n", " Total bytes:", buf);
> > + free(ifname);
> > + }
> > +}
> > +
> > +static void print_stats(struct lxc_container *c)
> > +{
> > + int i, ret;
> > + char buf[256];
> > +
> > + ret = c->get_cgroup_item(c, "cpuacct.usage", buf,
> > sizeof(buf));
> > + if (ret > 0 && ret < sizeof(buf)) {
> > + str_chomp(buf);
> > + if (humanize) {
> > + float seconds = strtof(buf, NULL) /
> > 1000000000.0;
> > + printf("%-15s %.2f seconds\n", "CPU use:",
> > seconds);
> > + } else {
> > + printf("%-15s %s\n", "CPU use:", buf);
> > + }
> > + }
> > +
> > + ret = c->get_cgroup_item(c,
> > "blkio.throttle.io_service_bytes", buf, sizeof(buf));
> > + if (ret > 0 && ret < sizeof(buf)) {
> > + char *ch;
> > +
> > + /* put ch on last "Total" line */
> > + str_chomp(buf);
> > + for(ch = &buf[strlen(buf)-1]; ch > buf && *ch !=
> > '\n'; ch--)
> > + ;
> > + if (*ch == '\n')
> > + ch++;
> > +
> > + if (strncmp(ch, "Total", 5) == 0) {
> > + ch += 6;
> > + memmove(buf, ch, strlen(ch)+1);
> > + str_size_humanize(buf, sizeof(buf));
> > + printf("%-15s %s\n", "BlkIO use:", buf);
> > + }
> > + }
> > +
> > + static const struct {
> > + const char *name;
> > + const char *file;
> > + } lxstat[] = {
> > + { "Memory use:", "memory.usage_in_bytes" },
> > + { "KMem use:", "memory.kmem.usage_in_bytes" },
> > + { NULL, NULL },
> > + };
> > +
> > + for (i = 0; lxstat[i].name; i++) {
> > + ret = c->get_cgroup_item(c, lxstat[i].file, buf,
> > sizeof(buf));
> > + if (ret > 0 && ret < sizeof(buf)) {
> > + str_chomp(buf);
> > + str_size_humanize(buf, sizeof(buf));
> > + printf("%-15s %s\n", lxstat[i].name, buf);
> > + }
> > + }
> > +}
> > +
> > +static int print_info(const char *name, const char *lxcpath)
> > +{
> > + int i;
> > + struct lxc_container *c;
> > +
> > + c = lxc_container_new(name, lxcpath);
> > + if (!c) {
> > + fprintf(stderr, "Insufficent privileges to control
> > %s\n", c->name); return -1;
> > + }
> >
> > if (!c->may_control(c)) {
> > fprintf(stderr, "Insufficent privileges to control
> > %s\n", c->name); @@ -113,14 +266,16 @@ int main(int argc, char
> > *argv[]) return -1;
> > }
> >
> > - if (!state && !pid && !ips && keys <= 0)
> > - state = pid = ips = true;
> > + if (!state && !pid && !ips && !stats && keys <= 0)
> > + state = pid = ips = stats = true;
> > +
> > + printf("%-15s %s\n", "Name:", c->name);
> >
> > if (state || test_state) {
> > if (test_state)
> > return strcmp(c->state(c), test_state) !=
> > 0;
> > - printf("state: \t%s\n", c->state(c));
> > + printf("%-15s %s\n", "State:", c->state(c));
> > }
> >
> > if (pid) {
> > @@ -128,7 +283,7 @@ int main(int argc, char *argv[])
> >
> > initpid = c->init_pid(c);
> > if (initpid >= 0)
> > - printf("pid: \t%d\n", initpid);
> > + printf("%-15s %d\n", "Pid:", initpid);
> > }
> >
> > if (ips) {
> > @@ -138,12 +293,17 @@ int main(int argc, char *argv[])
> > i = 0;
> > while (addresses[i]) {
> > address = addresses[i];
> > - printf("ip: \t%s\n", address);
> > + printf("%-15s %s\n", "IP:",
> > address); i++;
> > }
> > }
> > }
> >
> > + if (stats) {
> > + print_stats(c);
> > + print_net_stats(name, lxcpath);
> > + }
> > +
> > for(i = 0; i < keys; i++) {
> > int len = c->get_config_item(c, key[i], NULL, 0);
> >
> > @@ -164,3 +324,66 @@ int main(int argc, char *argv[])
> > lxc_container_put(c);
> > return 0;
> > }
> > +
> > +int main(int argc, char *argv[])
> > +{
> > + int rc, i, len, ret = EXIT_FAILURE;
> > + char *regexp;
> > + regex_t preg;
> > + int ct_cnt;
> > + char **ct_name;
> > + bool printed;
> > +
> > + if (lxc_arguments_parse(&my_args, argc, argv))
> > + goto err1;
> > +
> > + if (!my_args.log_file)
> > + my_args.log_file = "none";
> > +
> > + if (lxc_log_init(my_args.name, my_args.log_file,
> > my_args.log_priority,
> > + my_args.progname, my_args.quiet,
> > my_args.lxcpath[0]))
> > + goto err1;
> > +
> > + len = strlen(my_args.name) + 3;
> > + regexp = malloc(len + 3);
> > + if (!regexp) {
> > + fprintf(stderr, "failed to allocate memory");
> > + goto err1;
> > + }
> > + rc = snprintf(regexp, len, "^%s$", my_args.name);
> > + if (rc < 0 || rc >= len) {
> > + fprintf(stderr, "Name too long");
> > + goto err2;
> > + }
> > +
> > + if (regcomp(&preg, regexp, REG_NOSUB|REG_EXTENDED)) {
> > + fprintf(stderr, "failed to compile the regex
> > '%s'", my_args.name);
> > + goto err2;
> > + }
> > +
> > + printed = false;
> > + ct_cnt = list_all_containers(my_args.lxcpath[0], &ct_name);
> > + if (ct_cnt < 0)
> > + goto err3;
> > +
> > + for (i = 0; i < ct_cnt; i++) {
> > + if (regexec(&preg, ct_name[i], 0, NULL, 0) == 0)
> > + {
> > + if (printed)
> > + printf("\n");
> > + print_info(ct_name[i], my_args.lxcpath[0]);
> > + printed = true;
> > + }
> > + free(ct_name[i]);
> > + }
> > + if (ct_name)
> > + free(ct_name);
> > + ret = EXIT_SUCCESS;
> > +
> > +err3:
> > + regfree(&preg);
> > +err2:
> > + free(regexp);
> > +err1:
> > + return ret;
> > +}
> > diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> > index 89b45ed..f16c032 100644
> > --- a/src/lxc/lxccontainer.c
> > +++ b/src/lxc/lxccontainer.c
> > @@ -3206,3 +3206,50 @@ free_bad:
> > process_unlock();
> > return -1;
> > }
> > +
> > +int list_all_containers(const char *lxcpath, char ***names)
> > +{
> > + int all_cnt, active_cnt, i, ret;
> > + char **all_name;
> > + char **active_name;
> > +
> > + all_cnt = list_defined_containers(lxcpath, &all_name,
> > NULL);
> > + if (all_cnt < 0)
> > + return all_cnt;
> > +
> > + active_cnt = list_active_containers(lxcpath, &active_name,
> > NULL);
> > + if (active_cnt < 0) {
> > + ret = active_cnt;
> > + goto free_all;
> > + }
> > +
> > + for (i = 0; i < active_cnt; i++) {
> > + if (!array_contains(&all_name, active_name[i],
> > all_cnt)) {
> > + if (!add_to_array(&all_name,
> > active_name[i], all_cnt)) {
> > + ret = -1;
> > + goto free_active;
> > + }
> > + all_cnt++;
> > + }
> > + free(active_name[i]);
> > + active_name[i] = NULL;
> > + }
> > + free(active_name);
> > +
> > + *names = all_name;
> > + return all_cnt;
> > +
> > +free_active:
> > + for (i = 0; i < active_cnt; i++) {
> > + if (active_name[i])
> > + free(active_name[i]);
> > + }
> > + free(active_name);
> > +
> > +free_all:
> > + for (i = 0; i < all_cnt; i++) {
> > + free(all_name[i]);
> > + }
> > + free(all_name);
> > + return ret;
> > +}
> > diff --git a/src/lxc/lxccontainer.h b/src/lxc/lxccontainer.h
> > index 762e1b0..d83202b 100644
> > --- a/src/lxc/lxccontainer.h
> > +++ b/src/lxc/lxccontainer.h
> > @@ -277,6 +277,8 @@ int list_defined_containers(const char
> > *lxcpath, char ***names, struct lxc_conta */
> > int list_active_containers(const char *lxcpath, char ***names,
> > struct lxc_container ***cret);
> > +int list_all_containers(const char *lxcpath, char ***names);
> > +
> > #if 0
> > char ** lxc_get_valid_keys();
> > char ** lxc_get_valid_values(char *key);
> > --
> > 1.8.3.1
> >
> >
> > ------------------------------------------------------------------------------
> > November Webinars for C, C++, Fortran Developers
> > Accelerate application performance with scalable programming
> > models. Explore techniques for threading, error checking, porting,
> > and tuning. Get the most from the latest Intel processors and
> > coprocessors. See abstracts and register
> > http://pubads.g.doubleclick.net/gampad/clk?id=60136231&iu=/4140/ostg.clktrk
> > _______________________________________________ Lxc-devel mailing
> > list Lxc-devel at lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/lxc-devel
>
More information about the lxc-devel
mailing list