[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, ×);
> + 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
>
>
-------------- 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