diff options
Diffstat (limited to 'cpufreq/src/cpufreq-monitor-procfs.c')
-rw-r--r-- | cpufreq/src/cpufreq-monitor-procfs.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/cpufreq/src/cpufreq-monitor-procfs.c b/cpufreq/src/cpufreq-monitor-procfs.c new file mode 100644 index 00000000..97c635ba --- /dev/null +++ b/cpufreq/src/cpufreq-monitor-procfs.c @@ -0,0 +1,221 @@ +/* + * MATE CPUFreq Applet + * Copyright (C) 2004 Carlos Garcia Campos <[email protected]> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Authors : Carlos Garc�a Campos <[email protected]> + */ + +#include <glib.h> +#include <glib/gi18n.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "cpufreq-monitor-procfs.h" +#include "cpufreq-utils.h" + +static void cpufreq_monitor_procfs_class_init (CPUFreqMonitorProcfsClass *klass); + +static gboolean cpufreq_monitor_procfs_run (CPUFreqMonitor *monitor); +static GList *cpufreq_monitor_procfs_get_available_frequencies (CPUFreqMonitor *monitor); + +G_DEFINE_TYPE (CPUFreqMonitorProcfs, cpufreq_monitor_procfs, CPUFREQ_TYPE_MONITOR) + +static void +cpufreq_monitor_procfs_init (CPUFreqMonitorProcfs *monitor) +{ +} + +static void +cpufreq_monitor_procfs_class_init (CPUFreqMonitorProcfsClass *klass) +{ + CPUFreqMonitorClass *monitor_class = CPUFREQ_MONITOR_CLASS (klass); + + monitor_class->run = cpufreq_monitor_procfs_run; + monitor_class->get_available_frequencies = cpufreq_monitor_procfs_get_available_frequencies; +} + +CPUFreqMonitor * +cpufreq_monitor_procfs_new (guint cpu) +{ + CPUFreqMonitorProcfs *monitor; + + monitor = g_object_new (TYPE_CPUFREQ_MONITOR_PROCFS, "cpu", cpu, NULL); + + return CPUFREQ_MONITOR (monitor); +} + +static gint +cpufreq_monitor_procfs_get_freq_from_userspace (guint cpu) +{ + gchar *buffer = NULL; + gchar *path; + gchar *p; + gchar *frequency; + gint freq; + gint len; + GError *error = NULL; + + path = g_strdup_printf ("/proc/sys/cpu/%u/speed", cpu); + + if (!cpufreq_file_get_contents (path, &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + g_free (path); + + return -1; + } + + g_free (path); + + /* Try to remove the '\n' */ + p = g_strrstr (buffer, "\n"); + len = strlen (buffer); + if (p) + len -= strlen (p); + + frequency = g_strndup (buffer, len); + g_free (buffer); + + freq = atoi (frequency); + g_free (frequency); + + return freq; +} + +static gboolean +cpufreq_monitor_procfs_parse (CPUFreqMonitorProcfs *monitor, + gint *cpu, + gint *fmax, + gint *pmin, + gint *pmax, + gint *fmin, + gchar *mode) +{ + gchar **lines; + gchar *buffer = NULL; + gint i, count; + guint mon_cpu; + GError *error = NULL; + + if (!cpufreq_file_get_contents ("/proc/cpufreq", &buffer, NULL, &error)) { + g_warning ("%s", error->message); + g_error_free (error); + + return FALSE; + } + + g_object_get (G_OBJECT (monitor), + "cpu", &mon_cpu, NULL); + + count = 0; + lines = g_strsplit (buffer, "\n", -1); + for (i = 0; lines[i]; i++) { + if (g_ascii_strncasecmp (lines[i], "CPU", 3) == 0) { + /* CPU 0 650000 kHz ( 81 %) - 800000 kHz (100 %) - powersave */ + count = sscanf (lines[i], "CPU %d %d kHz (%d %%) - %d kHz (%d %%) - %20s", + cpu, fmin, pmin, fmax, pmax, mode); + + if ((guint)(*cpu) == mon_cpu) + break; + } + } + + g_strfreev (lines); + g_free (buffer); + + return (count == 6); +} + +static gboolean +cpufreq_procfs_cpu_is_online (void) +{ + return g_file_test ("/proc/cpufreq", + G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR); +} + +static gboolean +cpufreq_monitor_procfs_run (CPUFreqMonitor *monitor) +{ + gint fmax, fmin, cpu; + gint pmin, pmax; + gchar mode[21]; + gint cur_freq, max_freq; + gchar *governor; + + if (!cpufreq_monitor_procfs_parse (CPUFREQ_MONITOR_PROCFS (monitor), + &cpu, &fmax, &pmin, &pmax, &fmin, mode)) { + /* Check whether it failed because + * cpu is not online. + */ + if (!cpufreq_procfs_cpu_is_online ()) { + g_object_set (G_OBJECT (monitor), "online", FALSE, NULL); + return TRUE; + } + return FALSE; + } + + governor = mode; + max_freq = fmax; + + if (g_ascii_strcasecmp (governor, "powersave") == 0) { + cur_freq = fmin; + } else if (g_ascii_strcasecmp (governor, "performance") == 0) { + cur_freq = fmax; + } else if (g_ascii_strcasecmp (governor, "userspace") == 0) { + cur_freq = cpufreq_monitor_procfs_get_freq_from_userspace (cpu); + } else { + cur_freq = fmax; + } + + g_object_set (G_OBJECT (monitor), + "online", TRUE, + "governor", governor, + "frequency", cur_freq, + "max-frequency", max_freq, + NULL); + + return TRUE; +} + +static GList * +cpufreq_monitor_procfs_get_available_frequencies (CPUFreqMonitor *monitor) +{ + gint fmax, fmin, cpu, freq; + gint pmin, pmax; + gchar mode[21]; + GList *list = NULL; + + if (!cpufreq_monitor_procfs_parse (CPUFREQ_MONITOR_PROCFS (monitor), &cpu, + &fmax, &pmin, &pmax, &fmin, mode)) { + return NULL; + } + + if ((pmax > 0) && (pmax != 100)) { + freq = (fmax * 100) / pmax; + list = g_list_prepend (list, g_strdup_printf ("%d", freq)); + } + + list = g_list_prepend (list, g_strdup_printf ("%d", fmax)); + if (fmax != fmin) + list = g_list_prepend (list, g_strdup_printf ("%d", fmin)); + + return g_list_reverse (list); +} + |