/*
* This file is part of Cockpit.
*
* Copyright (C) 2014 Red Hat, Inc.
*
* Cockpit is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* Cockpit is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cockpit; If not, see .
*/
#include "config.h"
#include "cockpitcgroupsamples.h"
#include
#include
#include
#include
const gchar *cockpit_cgroup_memory_root = "/sys/fs/cgroup/memory";
const gchar *cockpit_cgroup_cpuacct_root = "/sys/fs/cgroup/cpuacct";
static double
read_double (const gchar *prefix,
const gchar *suffix)
{
gchar *path = NULL;
gchar *file_contents = NULL;
GError *error = NULL;
double ret;
gsize len;
path = g_build_filename (prefix, suffix, NULL);
if (!g_file_get_contents (path, &file_contents, &len, &error))
{
if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) ||
g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV))
g_debug ("samples file not found: %s", path);
else
g_message ("error loading file: %s: %s", path, error->message);
g_error_free (error);
ret = -1;
}
else
{
ret = g_ascii_strtod (file_contents, NULL);
}
g_free (file_contents);
g_free (path);
return ret;
}
static void
collect_memory (CockpitSamples *samples,
const gchar *path,
const gchar *cgroup)
{
double mem_usage_in_bytes;
double mem_limit_in_bytes;
double memsw_usage_in_bytes;
double memsw_limit_in_bytes;
if (access (path, F_OK) == 0)
{
mem_usage_in_bytes = read_double (path, "memory.usage_in_bytes");
mem_limit_in_bytes = read_double (path, "memory.limit_in_bytes");
memsw_usage_in_bytes = read_double (path, "memory.memsw.usage_in_bytes");
memsw_limit_in_bytes = read_double (path, "memory.memsw.limit_in_bytes");
/* If at max for arch, then unlimited => zero */
if (mem_limit_in_bytes >= (double)G_MAXSIZE ||
mem_limit_in_bytes >= (double)G_MAXSSIZE)
mem_limit_in_bytes = 0;
if (memsw_limit_in_bytes >= (double)G_MAXSIZE ||
memsw_limit_in_bytes >= (double)G_MAXSSIZE)
memsw_limit_in_bytes = 0;
cockpit_samples_sample (samples, "cgroup.memory.usage", cgroup, mem_usage_in_bytes);
cockpit_samples_sample (samples, "cgroup.memory.limit", cgroup, mem_limit_in_bytes);
cockpit_samples_sample (samples, "cgroup.memory.sw-usage", cgroup, memsw_usage_in_bytes);
cockpit_samples_sample (samples, "cgroup.memory.sw-limit", cgroup, memsw_limit_in_bytes);
}
}
static void
collect_cpu (CockpitSamples *samples,
const gchar *path,
const gchar *cgroup)
{
double cpuacct_usage;
double cpu_shares;
if (access (path, F_OK) == 0)
{
cpuacct_usage = read_double (path, "cpuacct.usage");
cpu_shares = read_double (path, "cpu.shares");
cockpit_samples_sample (samples, "cgroup.cpu.usage", cgroup, cpuacct_usage/1000000);
cockpit_samples_sample (samples, "cgroup.cpu.shares", cgroup, cpu_shares);
}
}
static void
notice_cgroups_in_hierarchy (CockpitSamples *samples,
const gchar *prefix,
void (* collect) (CockpitSamples *, const gchar *, const gchar *))
{
const gchar *paths[] = { prefix, NULL };
gsize prefix_len;
FTSENT *ent;
FTS *fs;
prefix_len = strlen (prefix);
fs = fts_open ((gchar **)paths, FTS_NOCHDIR | FTS_COMFOLLOW, NULL);
if (fs)
{
while((ent = fts_read (fs)) != NULL)
{
if (ent->fts_info == FTS_D)
{
const char *f = ent->fts_path + prefix_len;
if (*f == '/')
f++;
collect (samples, ent->fts_path, f);
}
}
fts_close (fs);
}
}
void
cockpit_cgroup_samples (CockpitSamples *samples)
{
/* We are looking for files like
/sys/fs/cgroup/memory/.../memory.usage_in_bytes
/sys/fs/cgroup/memory/.../memory.limit_in_bytes
/sys/fs/cgroup/cpuacct/.../cpuacct.usage
*/
notice_cgroups_in_hierarchy (samples, cockpit_cgroup_memory_root, collect_memory);
notice_cgroups_in_hierarchy (samples, cockpit_cgroup_cpuacct_root, collect_cpu);
}