diff options
author | infirit <[email protected]> | 2014-12-18 20:58:16 +0100 |
---|---|---|
committer | infirit <[email protected]> | 2014-12-18 21:04:53 +0100 |
commit | 76eff089e1ba541cece59f6d2f5847f349448f89 (patch) | |
tree | a45acda13ac9ff08b898a9f98638a1ee4edcaf45 | |
parent | 396b01dc3e3a704c0015874002b76a5ccda0678a (diff) | |
download | mate-system-monitor-76eff089e1ba541cece59f6d2f5847f349448f89.tar.bz2 mate-system-monitor-76eff089e1ba541cece59f6d2f5847f349448f89.tar.xz |
Add cgroup support in the process view
Add a new 'Control Group' column to the process view tab.
The format for the column is:
<path name> (controller name), <path name> (controller name)...
Processes that share the same path name across controllers
are colesced. For example if a process is in the /foo cgroup
for both the memory and cpu controllers, it would display as:
/foo (memory,cpu), ...
Taken from GSM commits:
2d33adcbc4347c112d57082956b4e199ff7132db Add cgroup support in the process view
645d38a218fedcbf9c7b674740bf213e02933820 Optimize cgroup updating
From: Jason Baron <[email protected]>
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/cgroups.cpp | 186 | ||||
-rw-r--r-- | src/cgroups.h | 14 | ||||
-rw-r--r-- | src/org.mate.system-monitor.gschema.xml.in.in | 8 | ||||
-rw-r--r-- | src/procdialogs.cpp | 6 | ||||
-rw-r--r-- | src/procman.h | 1 | ||||
-rw-r--r-- | src/proctable.cpp | 21 | ||||
-rw-r--r-- | src/proctable.h | 1 |
8 files changed, 236 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index efea297..ff9f2a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,6 +25,7 @@ mate_system_monitor_SOURCES = \ defaulttable.h \ disks.cpp disks.h \ selinux.h selinux.cpp \ + cgroups.h cgroups.cpp \ procman_matesu.h procman_matesu.cpp \ procman_gksu.h procman_gksu.cpp \ sysinfo.cpp sysinfo.h \ diff --git a/src/cgroups.cpp b/src/cgroups.cpp new file mode 100644 index 0000000..eafa1e3 --- /dev/null +++ b/src/cgroups.cpp @@ -0,0 +1,186 @@ +#include <config.h> + +#include <glib.h> +#include <glib/gi18n.h> + +#include "procman.h" +#include "util.h" + +gboolean +cgroups_enabled(void) +{ + static gboolean initialized = FALSE; + static gboolean has_cgroups; + + if (!initialized) { + initialized = TRUE; + has_cgroups = g_file_test("/proc/cgroups", G_FILE_TEST_EXISTS); + } + + return has_cgroups; +} + +void +append_cgroup_name(char *line, gchar **current_cgroup_name) +{ + gchar *controller, *path, *tmp, *path_plus_space; + int paren_offset, off, tmp_size; + + controller = g_strstr_len(line, -1, ":") + 1; + if (!controller) + return; + + path = g_strstr_len(controller, -1, ":") + 1; + if (!path) + return; + + *(path - 1) = '\0'; + g_strdelimit(controller, ",", '/'); + + if ((std::strcmp(path, "/") == 0) || (std::strncmp(controller, "name=", 5) == 0)) + return; + + if (*current_cgroup_name == NULL) { + *current_cgroup_name = g_strdup_printf("%s (%s)", path, controller); + return; + } + + /* add a space to the end of the path string */ + path_plus_space = g_strdup_printf("%s ", path); + + if ((tmp = g_strstr_len(*current_cgroup_name, -1, path_plus_space))) { + tmp_size = strlen(*current_cgroup_name) + strlen(controller) + 1; + paren_offset = g_strstr_len(tmp + strlen(path), -1, ")") - *current_cgroup_name; + *(*current_cgroup_name + paren_offset) = '\0'; + tmp = (gchar *)g_strnfill(tmp_size, '\0'); + off = g_strlcat(tmp, *current_cgroup_name, tmp_size); + *(tmp + off) = '/'; + off++; + off += g_strlcat(tmp + off, controller, tmp_size); + *(tmp + off) = ')'; + off++; + g_strlcat(tmp + off, *current_cgroup_name + paren_offset + 1, tmp_size); + } else + tmp = g_strdup_printf("%s, %s(%s)", *current_cgroup_name, path_plus_space, controller); + + g_free(path_plus_space); + g_free(*current_cgroup_name); + *current_cgroup_name = tmp; +} + +int +check_cgroup_changed(gchar *line, gchar *current_cgroup_set) +{ + /* check if line is contained in current_cgroup_set */ + gchar *controller, *path, *tmp, *found, *close_paren, *open_paren; + int ret = 0; + + controller = g_strstr_len(line, -1, ":") + 1; + if (!controller) + return 1; + + path = g_strstr_len(controller, -1, ":") + 1; + if (!path) + return 1; + + *(path - 1) = '\0'; + + if (std::strncmp(controller, "name=", 5) == 0) + goto out; + + /* if there are multiple controllers just report string has changed */ + if (g_strstr_len(controller, -1, ",")) { + ret = 1; + goto out; + } + + if (!current_cgroup_set) { + if (std::strcmp(path, "/") != 0) + ret = 1; + goto out; + } + + /* special case for root cgroup */ + tmp = current_cgroup_set; + if (std::strcmp(path, "/") == 0) { + while ((found = g_strstr_len(tmp, -1, controller))) { + close_paren = g_strstr_len(found, -1, ")"); + open_paren = g_strstr_len(found, -1, "("); + if (close_paren) { + if (!open_paren || (close_paren < open_paren)) { + ret = 1; + goto out; + } + } + tmp = found + strlen(controller); + } + goto out; + } + + tmp = current_cgroup_set; + while ((found = g_strstr_len(tmp, -1, path))) { + found = found + strlen(path); + close_paren = g_strstr_len(found, -1, ")"); + if (*found == ' ') { + if (g_strstr_len(found + 1, close_paren - found, controller)) + goto out; + } + tmp = close_paren + 1; + } + ret = 1; +out: + *(path - 1) = ':'; + return ret; +} + +void +get_process_cgroup_info(ProcInfo *info) +{ + gchar *path; + gchar *cgroup_name = NULL; + int cgroups_changed = 0; + gchar *text; + char **lines; + int i; + + if (!cgroups_enabled()) + return; + + /* read out of /proc/pid/cgroup */ + path = g_strdup_printf("/proc/%d/cgroup", info->pid); + if (!path) + return; + if(!g_file_get_contents(path, &text, NULL, NULL)) + goto out; + lines = g_strsplit(text, "\n", -1); + g_free(text); + if (!lines) + goto out; + + for (i = 0; lines[i] != NULL; i++) { + if (lines[i][0] == '\0') + continue; + if (check_cgroup_changed(lines[i], info->cgroup_name)) { + cgroups_changed = 1; + break; + } + } + + if (cgroups_changed) { + for (i = 0; lines[i] != NULL; i++) { + if (lines[i][0] == '\0') + continue; + append_cgroup_name(lines[i], &cgroup_name); + } + if (info->cgroup_name) + g_free(info->cgroup_name); + if (!cgroup_name) + info->cgroup_name = g_strdup(""); + else + info->cgroup_name = cgroup_name; + } + + g_strfreev(lines); +out: + g_free(path); +} diff --git a/src/cgroups.h b/src/cgroups.h new file mode 100644 index 0000000..8c42f6f --- /dev/null +++ b/src/cgroups.h @@ -0,0 +1,14 @@ +#ifndef PROCMAN_CGROUP_H_20111103 +#define PROCMAN_CGROUP_H_20111103 + +#include <glib.h> + +#include "procman.h" + +void +get_process_cgroup_info (ProcInfo *info); + +gboolean +cgroups_enabled (void); + +#endif /* PROCMAN_CGROUP_H_20111103 */ diff --git a/src/org.mate.system-monitor.gschema.xml.in.in b/src/org.mate.system-monitor.gschema.xml.in.in index 7abcd11..39f4f09 100644 --- a/src/org.mate.system-monitor.gschema.xml.in.in +++ b/src/org.mate.system-monitor.gschema.xml.in.in @@ -287,6 +287,14 @@ <default>true</default> <_summary>Show process 'Waiting Channel' column on startup</_summary> </key> + <key name="col-17-width" type="i"> + <default>48</default> + <_summary>Width of process 'Control Group' column</_summary> + </key> + <key name="col-17-visible" type="b"> + <default>false</default> + <_summary>Show process 'Control Group' column on startup</_summary> + </key> </schema> <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.mate.system-monitor.disktreenew" path="/org/mate/system-monitor/disktreenew/"> <key name="sort-col" type="i"> diff --git a/src/procdialogs.cpp b/src/procdialogs.cpp index 449679d..d129bd9 100644 --- a/src/procdialogs.cpp +++ b/src/procdialogs.cpp @@ -34,6 +34,7 @@ #include "settings-keys.h" #include "procman_matesu.h" #include "procman_gksu.h" +#include "cgroups.h" static GtkWidget *renice_dialog = NULL; static GtkWidget *prefs_dialog = NULL; @@ -470,11 +471,16 @@ create_field_page(GtkWidget *tree, const char* text) GtkTreeIter iter; const gchar *title; gboolean visible; + gint column_id; title = gtk_tree_view_column_get_title (column); if (!title) title = _("Icon"); + column_id = gtk_tree_view_column_get_sort_column_id(column); + if ((column_id == COL_CGROUP) && (!cgroups_enabled())) + continue; + visible = gtk_tree_view_column_get_visible (column); gtk_list_store_append (model, &iter); diff --git a/src/procman.h b/src/procman.h index f359667..2adfb7d 100644 --- a/src/procman.h +++ b/src/procman.h @@ -126,6 +126,7 @@ MutableProcInfo() guint status; guint pcpu; gint nice; + gchar *cgroup_name; }; diff --git a/src/proctable.cpp b/src/proctable.cpp index 6824124..13a4fa4 100644 --- a/src/proctable.cpp +++ b/src/proctable.cpp @@ -52,6 +52,7 @@ #include "util.h" #include "interface.h" #include "selinux.h" +#include "cgroups.h" ProcInfo::UserMap ProcInfo::users; @@ -258,6 +259,7 @@ proctable_new (ProcData * const procdata) N_("Memory"), /* xgettext: wchan, see ps(1) or top(1) */ N_("Waiting Channel"), + N_("Control Group"), NULL, "POINTER" }; @@ -287,6 +289,7 @@ proctable_new (ProcData * const procdata) G_TYPE_STRING, /* Arguments */ G_TYPE_ULONG, /* Memory */ G_TYPE_STRING, /* wchan */ + G_TYPE_STRING, /* Cgroup */ GDK_TYPE_PIXBUF, /* Icon */ G_TYPE_POINTER, /* ProcInfo */ G_TYPE_STRING /* Sexy tooltip */ @@ -330,7 +333,7 @@ proctable_new (ProcData * const procdata) gtk_tree_view_set_expander_column (GTK_TREE_VIEW (proctree), column); - for (i = COL_USER; i <= COL_WCHAN; i++) { + for (i = COL_USER; i <= COL_CGROUP; i++) { GtkCellRenderer *cell; GtkTreeViewColumn *col; @@ -435,6 +438,14 @@ proctable_new (ProcData * const procdata) gtk_tree_view_column_set_visible (column, FALSE); } + if (!cgroups_enabled()) { + GtkTreeViewColumn *column; + + column = my_gtk_tree_view_get_column_with_sort_column_id(GTK_TREE_VIEW(proctree), COL_CGROUP); + gtk_tree_view_column_set_visible(column, FALSE); + } + + g_signal_connect (G_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (proctree))), "changed", G_CALLBACK (cb_row_selected), procdata); @@ -459,6 +470,7 @@ ProcInfo::~ProcInfo() g_free(this->tooltip); g_free(this->arguments); g_free(this->security_context); + g_free(this->cgroup_name); } @@ -544,7 +556,6 @@ static void get_process_memory_writable(ProcInfo *info) g_free(maps); } - static void get_process_memory_info(ProcInfo *info) { @@ -593,6 +604,7 @@ update_info_mutable_cols(ProcInfo *info) tree_store_update(model, &info->node, COL_NICE, info->nice); tree_store_update(model, &info->node, COL_MEM, info->mem); tree_store_update(model, &info->node, COL_WCHAN, info->wchan); + tree_store_update(model, &info->node, COL_CGROUP, info->cgroup_name); } @@ -709,6 +721,9 @@ update_info (ProcData *procdata, ProcInfo *info) ProcInfo::cpu_times[info->pid] = info->cpu_time = proctime.rtime; info->nice = procuid.nice; info->ppid = procuid.ppid; + + /* get cgroup data */ + get_process_cgroup_info(info); } @@ -753,6 +768,8 @@ ProcInfo::ProcInfo(pid_t pid) info->start_time = proctime.start_time; get_process_selinux_context (info); + info->cgroup_name = NULL; + get_process_cgroup_info(info); } diff --git a/src/proctable.h b/src/proctable.h index 9c90669..0811c61 100644 --- a/src/proctable.h +++ b/src/proctable.h @@ -43,6 +43,7 @@ enum COL_ARGS, COL_MEM, COL_WCHAN, + COL_CGROUP, COL_PIXBUF, COL_POINTER, COL_TOOLTIP, |