<div dir="ltr"><div style>Hi</div>-Feel free to change --type to something else<div style>-Feel free to change cpuacct to cpuacct.usage</div><div style>-Can be extended to collect other cgroup information like memory usage</div>

<div style>-Would be nice to have "systemd-analyze plot --type cpuacct" to draw a pie diagram.</div><div style>Thanks</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Sun, Mar 24, 2013 at 7:23 PM, Umut Tezduyar <span dir="ltr"><<a href="mailto:umut@tezduyar.com" target="_blank">umut@tezduyar.com</a>></span> wrote:<br>

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