Minor cleanups
[meego-developer-tools:powertop.git] / ahci-alpm.c
1 /*
2  * Copyright 2009, Intel Corporation
3  *
4  * This file is part of PowerTOP
5  *
6  * This program file is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program in a file named COPYING; if not, write to the
17  * Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301 USA
20  *
21  * Authors:
22  *      Arjan van de Ven <arjan@linux.intel.com>
23  */
24
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdint.h>
30 #include <sys/types.h>
31 #include <dirent.h>
32 #include <assert.h>
33
34 #include "powertop.h"
35
36 struct device_data;
37
38 struct device_data {
39         struct device_data *next;
40         char pathname[4096];
41         char human_name[4096];
42         uint64_t active, partial, slumber, total;
43         uint64_t previous_active, previous_partial, previous_slumber, previous_total;
44 };
45
46
47 static struct device_data *devices;
48
49 static void cachunk_data(void)
50 {
51         struct device_data *ptr;
52         ptr = devices;
53         while (ptr) {
54                 ptr->previous_active = ptr->active;
55                 ptr->previous_partial = ptr->partial;
56                 ptr->previous_slumber = ptr->slumber;
57                 ptr->previous_total = ptr->total;
58                 ptr = ptr->next;
59         }
60 }
61
62 static char *disk_name(char *path, char *target, char *shortname)
63 {
64
65         DIR *dir;
66         struct dirent *dirent;
67         char pathname[PATH_MAX];
68
69         sprintf(pathname, "%s/%s", path, target);
70         dir = opendir(pathname);
71         if (!dir)
72                 return strdup(shortname);
73
74         while ((dirent = readdir(dir))) {
75                 char line[4096], *c;
76                 FILE *file;
77                 if (dirent->d_name[0]=='.')
78                         continue;
79
80                 if (!strchr(dirent->d_name, ':'))
81                         continue;
82
83                 sprintf(line, "%s/%s/model", pathname, dirent->d_name);
84                 file = fopen(line, "r");
85                 if (file) {
86                         if (fgets(line, 4096, file) == NULL)
87                                 return strdup(shortname);
88                         fclose(file);
89                         c = strchr(line, '\n');
90                         if (c)
91                                 *c = 0;
92                         return strdup(line);
93                 }
94         }
95         closedir(dir);
96
97         return strdup(shortname);
98 }
99
100 static char *model_name(char *path, char *shortname)
101 {
102
103         DIR *dir;
104         struct dirent *dirent;
105         char pathname[PATH_MAX];
106
107         sprintf(pathname, "%s/device", path);
108
109         dir = opendir(pathname);
110         if (!dir)
111                 return strdup(shortname);
112
113         while ((dirent = readdir(dir))) {
114                 if (dirent->d_name[0]=='.')
115                         continue;
116
117                 if (!strchr(dirent->d_name, ':'))
118                         continue;
119                 if (!strstr(dirent->d_name, "target"))
120                         continue;
121                 return disk_name(pathname, dirent->d_name, shortname);
122         }
123         closedir(dir);
124
125         return strdup(shortname);
126 }
127
128 static int first_time = 1;
129 static void update_ahci_device(char *path, char *shortname)
130 {
131         struct device_data *ptr;
132         FILE *file;
133         char fullpath[4096];
134         char name[4096], *c;
135         ptr = devices;
136
137         sprintf(fullpath, "%s/ahci_alpm_accounting", path);
138
139         if (access(fullpath, R_OK))
140                 return;
141
142         if (first_time) {
143                 file = fopen(fullpath, "w");
144                 if (file) fprintf(file, "1\n");
145                 if (file) fclose(file);
146         }
147
148         while (ptr) {
149                 if (strcmp(ptr->pathname, path)==0) {
150                         sprintf(fullpath, "%s/ahci_alpm_active", path);
151                         file = fopen(fullpath, "r");
152                         if (!file)
153                                 return;
154                         fgets(name, 4096, file);
155                         ptr->active = strtoull(name, NULL, 10);
156                         fclose(file);
157
158                         sprintf(fullpath, "%s/ahci_alpm_partial", path);
159                         file = fopen(fullpath, "r");
160                         if (!file)
161                                 return;
162                         fgets(name, 4096, file);
163                         ptr->partial = strtoull(name, NULL, 10);
164                         fclose(file);
165
166                         sprintf(fullpath, "%s/ahci_alpm_slumber", path);
167                         file = fopen(fullpath, "r");
168                         if (!file)
169                                 return;
170                         fgets(name, 4096, file);
171                         ptr->slumber = strtoull(name, NULL, 10);
172                         fclose(file);
173
174                         ptr->total = ptr->active + ptr->partial + ptr->slumber;
175                         return;
176                 }
177                 ptr = ptr->next;
178         }
179         /* no luck, new one */
180         ptr = malloc(sizeof(struct device_data));
181         assert(ptr!=0);
182         memset(ptr, 0, sizeof(struct device_data));
183         ptr->next = devices;
184         devices = ptr;
185         strcpy(ptr->pathname, path);
186         c = model_name(path, shortname);
187         strcpy(ptr->human_name, c);
188         free(c);
189 }
190
191 void do_ahci_stats(void)
192 {
193         DIR *dir;
194         struct dirent *dirent;
195         char pathname[PATH_MAX];
196
197         dir = opendir("/sys/class/scsi_host");
198         if (!dir)
199                 return;
200
201         cachunk_data();
202         while ((dirent = readdir(dir))) {
203                 if (dirent->d_name[0]=='.')
204                         continue;
205
206                 sprintf(pathname, "/sys/class/scsi_host/%s", dirent->d_name);
207                 update_ahci_device(pathname, dirent->d_name);
208         }
209
210         closedir(dir);
211         first_time = 0;
212 }
213
214
215 void display_ahci_activity(void)
216 {
217         struct device_data *dev;
218         printf("\n");
219         printf("%s\n", _("Recent SATA AHCI link activity statistics"));
220         printf("%s\n", _("Active\tPartial\tSlumber\tDevice name"));
221         dev = devices;
222         while (dev) {
223                 if (dev->total > 0)
224                         printf("%5.1f%%\t%5.1f%%\t%5.1f%%\t%s\n",
225                                 100.0*(dev->active - dev->previous_active) / (0.00001 + dev->total - dev->previous_total),
226                                 100.0*(dev->partial - dev->previous_partial) / (0.00001 + dev->total - dev->previous_total),
227                                 100.0*(dev->slumber - dev->previous_slumber) / (0.00001 + dev->total - dev->previous_total),
228                                 dev->human_name);
229                 dev = dev->next;
230         }
231
232 }
233
234 void ahci_activity_hint(void)
235 {
236         int total_active = 0;
237         int pick;
238         struct device_data *dev;
239         dev = devices;
240         while (dev) {
241                 if (dev->active-1 > dev->previous_active && dev->active)
242                         total_active++;
243                 dev = dev->next;
244         }
245         if (!total_active)
246                 return;
247
248         pick = rand() % total_active;
249         total_active = 0;
250         dev = devices;
251         while (dev) {
252                 if (dev->active-1 > dev->previous_active && dev->active) {
253                         if (total_active == pick) {
254                                 char ahci_hint[8000];
255                                 sprintf(ahci_hint, _("A SATA device is active %1.1f%% of the time:\n%s"),
256                                  100.0*(dev->active - dev->previous_active) / (0.00001 + dev->total - dev->previous_total),
257                                 dev->human_name);
258                                 add_suggestion(ahci_hint,
259                                 15, 'S', _(" S - SATA Link Power Management "), activate_alpm);
260                         }
261                         total_active++;
262                 }
263                 dev = dev->next;
264         }
265
266 }