[systemd-devel] [PATCH 2/2] systemd-analyze: --type cpuacct option for blame

Umut Tezduyar umut at tezduyar.com
Sun Mar 24 11:28:55 PDT 2013


Hi
-Feel free to change --type to something else
-Feel free to change cpuacct to cpuacct.usage
-Can be extended to collect other cgroup information like memory usage
-Would be nice to have "systemd-analyze plot --type cpuacct" to draw a pie
diagram.
Thanks


On Sun, Mar 24, 2013 at 7:23 PM, Umut Tezduyar <umut at tezduyar.com> wrote:

> systemd-analyze blame --type cpuacct displays cpu time
> usage information of the cgroup. The information displayed
> is cpuacct.usage.
>
> ControlGroup=cpuacct:/foo/bar for a service would work.
> ControlGroupPersistent=yes for a oneshot service keeps
> cpuacct around so blame can retrieve it.
> DefaultControllers=cpuacct on system.conf can be set
> to have cpuacct same as systemd cgroup.
> ---
>  src/analyze/systemd-analyze.c |  131
> +++++++++++++++++++++++++++++++++++++----
>  1 files changed, 119 insertions(+), 12 deletions(-)
>
> diff --git a/src/analyze/systemd-analyze.c b/src/analyze/systemd-analyze.c
> index 3dcde30..062bf31 100644
> --- a/src/analyze/systemd-analyze.c
> +++ b/src/analyze/systemd-analyze.c
> @@ -61,6 +61,11 @@ static enum dot {
>          DEP_REQUIRE
>  } arg_dot = DEP_ALL;
>
> +static enum type {
> +        TYPE_TIME,
> +        TYPE_CPUACCT,
> +} arg_type = TYPE_TIME;
> +
>  struct boot_times {
>          usec_t firmware_time;
>          usec_t loader_time;
> @@ -77,6 +82,7 @@ struct unit_stat {
>          usec_t axt;
>          usec_t aet;
>          usec_t time;
> +        usec_t cpuacct;
>  };
>
>  static int bus_get_uint64_property(DBusConnection *bus, const char *path,
> const char *interface, const char *property, uint64_t *val) {
> @@ -146,6 +152,83 @@ static int aquire_time_data (DBusConnection *bus,
> struct unit_info *u, struct un
>          return 0;
>  }
>
> +static void aquire_cpuacct_data (char *s, struct unit_stat *t) {
> +        uint64_t cpuacct;
> +        char *p, *v = NULL;
> +        int r;
> +
> +        if (!startswith(s, "cpuacct:/"))
> +                return;
> +        if (cg_get_path("cpuacct", s+9, "cpuacct.usage", &p) >= 0 &&
> +            read_one_line_file(p, &v) >= 0 &&
> +            safe_atou64(v, &cpuacct) >= 0)
> +                t->cpuacct = cpuacct;
> +
> +        free(p);
> +        free(v);
> +}
> +
> +static int aquire_cgroup_data (DBusConnection *bus, struct unit_info *u,
> struct unit_stat *t) {
> +        _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
> +        DBusMessageIter iter, sub;
> +        const char *interface = "org.freedesktop.systemd1.Service";
> +        const char *property = "ControlGroups";
> +        int r;
> +
> +        t->cpuacct = 0;
> +
> +        /* Only interested in .service units */
> +        if (!endswith(u->unit_path, "service"))
> +                return 0;
> +
> +        r = bus_method_call_with_reply(
> +                        bus,
> +                        "org.freedesktop.systemd1",
> +                        u->unit_path,
> +                        "org.freedesktop.DBus.Properties",
> +                        "Get",
> +                        &reply,
> +                        NULL,
> +                        DBUS_TYPE_STRING, &interface,
> +                        DBUS_TYPE_STRING, &property,
> +                        DBUS_TYPE_INVALID);
> +        if (r < 0)
> +                return r;
> +
> +        if (!dbus_message_iter_init(reply, &iter) ||
> +            dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)  {
> +                log_error("Failed to parse reply.");
> +                return -EIO;
> +        }
> +
> +        dbus_message_iter_recurse(&iter, &sub);
> +
> +        if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY)  {
> +                log_error("Failed to parse reply.");
> +                return -EIO;
> +        }
> +
> +        if (dbus_message_iter_get_element_type(&sub) == DBUS_TYPE_STRING)
> {
> +
> +                DBusMessageIter sub1;
> +
> +                dbus_message_iter_recurse(&sub, &sub1);
> +                while (dbus_message_iter_get_arg_type(&sub1) ==
> DBUS_TYPE_STRING) {
> +                        const char *s;
> +                        dbus_message_iter_get_basic(&sub1, &s);
> +                        aquire_cpuacct_data (s, t);
> +                        dbus_message_iter_next(&sub1);
> +                }
> +        }
> +
> +        return 0;
> +}
> +
> +static int compare_unit_cpuacct(const void *a, const void *b) {
> +        return compare(((struct unit_stat *)b)->cpuacct,
> +                       ((struct unit_stat *)a)->cpuacct);
> +}
> +
>  static int compare_unit_time(const void *a, const void *b) {
>          return compare(((struct unit_stat *)b)->time,
>                         ((struct unit_stat *)a)->time);
> @@ -180,7 +263,7 @@ static void free_unit_stats(struct unit_stat *t,
> unsigned n) {
>          free(t);
>  }
>
> -static int acquire_stat_data(DBusConnection *bus, struct unit_stat **out)
> {
> +static int acquire_stat_data(DBusConnection *bus, enum type ty, struct
> unit_stat **out) {
>          _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
>          DBusMessageIter iter, sub;
>          int r, c = 0, n_units = 0;
> @@ -240,9 +323,15 @@ static int acquire_stat_data(DBusConnection *bus,
> struct unit_stat **out) {
>
>                  assert_cc(sizeof(usec_t) == sizeof(uint64_t));
>
> -                r = aquire_time_data (bus, &u, t);
> -                if (r < 0)
> -                        goto fail;
> +                if (ty == TYPE_CPUACCT) {
> +                        r = aquire_cgroup_data(bus, &u, t);
> +                        if (r < 0)
> +                                goto fail;
> +                } else {
> +                        r = aquire_time_data(bus, &u, t);
> +                        if (r < 0)
> +                                goto fail;
> +                }
>
>                  t->name = strdup(u.id);
>                  if (t->name == NULL) {
> @@ -400,7 +489,7 @@ static int analyze_plot(DBusConnection *bus) {
>          get_os_name(&osname);
>          assert_se(uname(&name) >= 0);
>
> -        n = acquire_stat_data(bus, &times);
> +        n = acquire_stat_data(bus, TYPE_TIME, &times);
>          if (n <= 0)
>                  return n;
>
> @@ -559,20 +648,31 @@ static int analyze_blame(DBusConnection *bus) {
>          unsigned i;
>          int n;
>
> -        n = acquire_stat_data(bus, &times);
> +        if (arg_type == TYPE_CPUACCT)
> +                n = acquire_stat_data(bus, TYPE_CPUACCT, &times);
> +        else
> +                n = acquire_stat_data(bus, TYPE_TIME, &times);
> +
>          if (n <= 0)
>                  return n;
>
> -        qsort(times, n, sizeof(struct unit_stat), compare_unit_time);
> +        if (arg_type == TYPE_CPUACCT)
> +                qsort(times, n, sizeof(struct unit_stat),
> compare_unit_cpuacct);
> +        else
> +                qsort(times, n, sizeof(struct unit_stat),
> compare_unit_time);
>
>          for (i = 0; i < (unsigned) n; i++) {
>                  char ts[FORMAT_TIMESPAN_MAX];
>
> -                if (times[i].ixt == 0)
> -                        continue;
> -
> -                if (times[i].time > 0)
> -                        printf("%16s %s\n", format_timespan(ts,
> sizeof(ts), times[i].time), times[i].name);
> +                if (arg_type == TYPE_CPUACCT) {
> +                        if (times[i].cpuacct > 0)
> +                                printf("%llu %s\n", times[i].cpuacct,
> times[i].name);
> +                } else {
> +                        if (times[i].ixt == 0)
> +                                continue;
> +                        if (times[i].time > 0)
> +                                printf("%16s %s\n", format_timespan(ts,
> sizeof(ts), times[i].time), times[i].name);
> +                }
>          }
>
>          free_unit_stats(times, (unsigned) n);
> @@ -759,6 +859,7 @@ static void analyze_help(void)
>                 "     --version        Show package version\n"
>                 "     --system         Connect to system manager\n"
>                 "     --user           Connect to user service manager\n"
> +               "     --type           Type of data (time or cpuacct) to
> display when using blame\n"
>                 "     --order          When generating a dependency graph,
> show only order\n"
>                 "     --require        When generating a dependency graph,
> show only requirement\n\n"
>                 "Commands:\n"
> @@ -786,6 +887,7 @@ static int parse_argv(int argc, char *argv[])
>                  { "require",   no_argument,       NULL, ARG_REQUIRE   },
>                  { "user",      no_argument,       NULL, ARG_USER      },
>                  { "system",    no_argument,       NULL, ARG_SYSTEM    },
> +                { "type",      required_argument, NULL, 't'           },
>                  { NULL,        0,                 NULL, 0             }
>          };
>
> @@ -819,6 +921,11 @@ static int parse_argv(int argc, char *argv[])
>                          arg_dot = DEP_REQUIRE;
>                          break;
>
> +                case 't':
> +                        if (strcmp(optarg, "cpuacct") == 0)
> +                                arg_type = TYPE_CPUACCT;
> +                        break;
> +
>                  case -1:
>                          return 1;
>
> --
> 1.7.2.5
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/systemd-devel/attachments/20130324/6968f887/attachment-0001.html>


More information about the systemd-devel mailing list