[systemd-devel] [PATCH 2/2] systemd-analyze: --type cpuacct option for blame
Umut Tezduyar
umut at tezduyar.com
Sun Mar 24 11:23:53 PDT 2013
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
More information about the systemd-devel
mailing list