/* * MATE CPUFreq Applet * Copyright (C) 2004 Carlos Garcia Campos * * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * Authors : Carlos García Campos */ #include #include #include #include #include "cpufreq-monitor-sysfs.h" #include "cpufreq-utils.h" enum { SCALING_MAX, SCALING_MIN, GOVERNOR, CPUINFO_MAX, SCALING_SETSPEED, SCALING_CUR_FREQ, N_FILES }; static gboolean cpufreq_monitor_sysfs_run (CPUFreqMonitor *monitor); static GList *cpufreq_monitor_sysfs_get_available_frequencies (CPUFreqMonitor *monitor); static GList *cpufreq_monitor_sysfs_get_available_governors (CPUFreqMonitor *monitor); static gchar *cpufreq_sysfs_read (const gchar *path, GError **error); /* /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_max_freq * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_min_freq * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_governor * /sys/devices/system/cpu/cpu[0]/cpufreq/cpuinfo_max_freq * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_setspeed (userspace) * /sys/devices/system/cpu/cpu[0]/cpufreq/scaling_cur_freq (new governors) */ const gchar *monitor_sysfs_files[] = { "scaling_max_freq", "scaling_min_freq", "scaling_governor", "cpuinfo_max_freq", "scaling_setspeed", "scaling_cur_freq", NULL }; #define CPUFREQ_SYSFS_BASE_PATH "/sys/devices/system/cpu/cpu%u/cpufreq/%s" G_DEFINE_TYPE (CPUFreqMonitorSysfs, cpufreq_monitor_sysfs, CPUFREQ_TYPE_MONITOR) static void cpufreq_monitor_sysfs_init (CPUFreqMonitorSysfs *monitor) { } static GObject * cpufreq_monitor_sysfs_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params) { GObject *object; gchar *path; gchar *frequency; gint max_freq; guint cpu; GError *error = NULL; object = G_OBJECT_CLASS ( cpufreq_monitor_sysfs_parent_class)->constructor (type, n_construct_properties, construct_params); g_object_get (G_OBJECT (object), "cpu", &cpu, NULL); path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, monitor_sysfs_files[CPUINFO_MAX]); frequency = cpufreq_sysfs_read (path, &error); if (!frequency) { g_warning ("%s", error->message); g_error_free (error); max_freq = -1; } else { max_freq = atoi (frequency); } g_free (path); g_free (frequency); g_object_set (G_OBJECT (object), "max-frequency", max_freq, NULL); return object; } static void cpufreq_monitor_sysfs_class_init (CPUFreqMonitorSysfsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CPUFreqMonitorClass *monitor_class = CPUFREQ_MONITOR_CLASS (klass); object_class->constructor = cpufreq_monitor_sysfs_constructor; monitor_class->run = cpufreq_monitor_sysfs_run; monitor_class->get_available_frequencies = cpufreq_monitor_sysfs_get_available_frequencies; monitor_class->get_available_governors = cpufreq_monitor_sysfs_get_available_governors; } CPUFreqMonitor * cpufreq_monitor_sysfs_new (guint cpu) { CPUFreqMonitorSysfs *monitor; monitor = g_object_new (CPUFREQ_TYPE_MONITOR_SYSFS, "cpu", cpu, NULL); return CPUFREQ_MONITOR (monitor); } static gchar * cpufreq_sysfs_read (const gchar *path, GError **error) { gchar *buffer = NULL; if (!cpufreq_file_get_contents (path, &buffer, NULL, error)) { return NULL; } return g_strchomp (buffer); } static gboolean cpufreq_sysfs_cpu_is_online (guint cpu) { gchar *path; gboolean retval; path = g_strdup_printf ("/sys/devices/system/cpu/cpu%u/", cpu); retval = g_file_test (path, G_FILE_TEST_IS_DIR); g_free (path); return retval; } static gboolean cpufreq_monitor_sysfs_run (CPUFreqMonitor *monitor) { guint cpu; gchar *frequency; gchar *governor; gchar *path; GError *error = NULL; g_object_get (G_OBJECT (monitor), "cpu", &cpu, NULL); path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, monitor_sysfs_files[GOVERNOR]); governor = cpufreq_sysfs_read (path, &error); if (!governor) { gboolean retval = FALSE; /* Check whether it failed because * cpu is not online. */ if (!cpufreq_sysfs_cpu_is_online (cpu)) { g_object_set (G_OBJECT (monitor), "online", FALSE, NULL); retval = TRUE; } else { g_warning ("%s", error->message); } g_error_free (error); g_free (path); return retval; } g_free (path); if (g_ascii_strcasecmp (governor, "userspace") == 0) { path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, monitor_sysfs_files[SCALING_SETSPEED]); } else if (g_ascii_strcasecmp (governor, "powersave") == 0) { path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, monitor_sysfs_files[SCALING_MIN]); } else if (g_ascii_strcasecmp (governor, "performance") == 0) { path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, monitor_sysfs_files[SCALING_MAX]); } else { /* Ondemand, Conservative, ... */ path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, monitor_sysfs_files[SCALING_CUR_FREQ]); } frequency = cpufreq_sysfs_read (path, &error); if (!frequency) { g_warning ("%s", error->message); g_error_free (error); g_free (path); g_free (governor); return FALSE; } g_free (path); g_object_set (G_OBJECT (monitor), "online", TRUE, "governor", governor, "frequency", atoi (frequency), NULL); g_free (governor); g_free (frequency); return TRUE; } static gint compare (gconstpointer a, gconstpointer b) { gint aa, bb; aa = atoi ((gchar *) a); bb = atoi ((gchar *) b); if (aa == bb) return 0; else if (aa > bb) return -1; else return 1; } static GList * cpufreq_monitor_sysfs_get_available_frequencies (CPUFreqMonitor *monitor) { gchar *path; GList *list = NULL; gchar **frequencies = NULL; gint i; guint cpu; gchar *buffer = NULL; GError *error = NULL; g_object_get (G_OBJECT (monitor), "cpu", &cpu, NULL); path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, "scaling_available_frequencies"); if (!cpufreq_file_get_contents (path, &buffer, NULL, &error)) { g_warning ("%s", error->message); g_error_free (error); g_free (path); return NULL; } g_free (path); buffer = g_strchomp (buffer); frequencies = g_strsplit (buffer, " ", -1); i = 0; while (frequencies[i]) { if (!g_list_find_custom (list, frequencies[i], compare)) list = g_list_prepend (list, g_strdup (frequencies[i])); i++; } g_strfreev (frequencies); g_free (buffer); return g_list_sort (list, compare); } static GList * cpufreq_monitor_sysfs_get_available_governors (CPUFreqMonitor *monitor) { gchar *path; GList *list = NULL; gchar **governors = NULL; gint i; guint cpu; gchar *buffer = NULL; GError *error = NULL; g_object_get (G_OBJECT (monitor), "cpu", &cpu, NULL); path = g_strdup_printf (CPUFREQ_SYSFS_BASE_PATH, cpu, "scaling_available_governors"); if (!cpufreq_file_get_contents (path, &buffer, NULL, &error)) { g_warning ("%s", error->message); g_error_free (error); g_free (path); return NULL; } g_free (path); buffer = g_strchomp (buffer); governors = g_strsplit (buffer, " ", -1); i = 0; while (governors[i] != NULL) { list = g_list_prepend (list, g_strdup (governors[i])); i++; } g_strfreev (governors); g_free (buffer); return list; }