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 <[email protected]> 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, ×); > + n = acquire_stat_data(bus, TYPE_TIME, ×); > if (n <= 0) > return n; > > @@ -559,20 +648,31 @@ static int analyze_blame(DBusConnection *bus) { > unsigned i; > int n; > > - n = acquire_stat_data(bus, ×); > + if (arg_type == TYPE_CPUACCT) > + n = acquire_stat_data(bus, TYPE_CPUACCT, ×); > + else > + n = acquire_stat_data(bus, TYPE_TIME, ×); > + > 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 > >
_______________________________________________ systemd-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/systemd-devel
