xref: /linux/tools/laptop/dslm/dslm.c (revision 0cce284537fb42d9c28b9b31038ffc9b464555f5)
1*3ca9760fSShuah Khan /*
2*3ca9760fSShuah Khan  * dslm.c
3*3ca9760fSShuah Khan  * Simple Disk Sleep Monitor
4*3ca9760fSShuah Khan  *  by Bartek Kania
5*3ca9760fSShuah Khan  * Licensed under the GPL
6*3ca9760fSShuah Khan  */
7*3ca9760fSShuah Khan #include <unistd.h>
8*3ca9760fSShuah Khan #include <stdlib.h>
9*3ca9760fSShuah Khan #include <stdio.h>
10*3ca9760fSShuah Khan #include <fcntl.h>
11*3ca9760fSShuah Khan #include <errno.h>
12*3ca9760fSShuah Khan #include <time.h>
13*3ca9760fSShuah Khan #include <string.h>
14*3ca9760fSShuah Khan #include <signal.h>
15*3ca9760fSShuah Khan #include <sys/ioctl.h>
16*3ca9760fSShuah Khan #include <linux/hdreg.h>
17*3ca9760fSShuah Khan 
18*3ca9760fSShuah Khan #ifdef DEBUG
19*3ca9760fSShuah Khan #define D(x) x
20*3ca9760fSShuah Khan #else
21*3ca9760fSShuah Khan #define D(x)
22*3ca9760fSShuah Khan #endif
23*3ca9760fSShuah Khan 
24*3ca9760fSShuah Khan int endit = 0;
25*3ca9760fSShuah Khan 
26*3ca9760fSShuah Khan /* Check if the disk is in powersave-mode
27*3ca9760fSShuah Khan  * Most of the code is stolen from hdparm.
28*3ca9760fSShuah Khan  * 1 = active, 0 = standby/sleep, -1 = unknown */
check_powermode(int fd)29*3ca9760fSShuah Khan static int check_powermode(int fd)
30*3ca9760fSShuah Khan {
31*3ca9760fSShuah Khan     unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
32*3ca9760fSShuah Khan     int state;
33*3ca9760fSShuah Khan 
34*3ca9760fSShuah Khan     if (ioctl(fd, HDIO_DRIVE_CMD, &args)
35*3ca9760fSShuah Khan 	&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
36*3ca9760fSShuah Khan 	&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
37*3ca9760fSShuah Khan 	if (errno != EIO || args[0] != 0 || args[1] != 0) {
38*3ca9760fSShuah Khan 	    state = -1; /* "unknown"; */
39*3ca9760fSShuah Khan 	} else
40*3ca9760fSShuah Khan 	    state = 0; /* "sleeping"; */
41*3ca9760fSShuah Khan     } else {
42*3ca9760fSShuah Khan 	state = (args[2] == 255) ? 1 : 0;
43*3ca9760fSShuah Khan     }
44*3ca9760fSShuah Khan     D(printf(" drive state is:  %d\n", state));
45*3ca9760fSShuah Khan 
46*3ca9760fSShuah Khan     return state;
47*3ca9760fSShuah Khan }
48*3ca9760fSShuah Khan 
state_name(int i)49*3ca9760fSShuah Khan static char *state_name(int i)
50*3ca9760fSShuah Khan {
51*3ca9760fSShuah Khan     if (i == -1) return "unknown";
52*3ca9760fSShuah Khan     if (i == 0) return "sleeping";
53*3ca9760fSShuah Khan     if (i == 1) return "active";
54*3ca9760fSShuah Khan 
55*3ca9760fSShuah Khan     return "internal error";
56*3ca9760fSShuah Khan }
57*3ca9760fSShuah Khan 
myctime(time_t time)58*3ca9760fSShuah Khan static char *myctime(time_t time)
59*3ca9760fSShuah Khan {
60*3ca9760fSShuah Khan     char *ts = ctime(&time);
61*3ca9760fSShuah Khan     ts[strlen(ts) - 1] = 0;
62*3ca9760fSShuah Khan 
63*3ca9760fSShuah Khan     return ts;
64*3ca9760fSShuah Khan }
65*3ca9760fSShuah Khan 
measure(int fd)66*3ca9760fSShuah Khan static void measure(int fd)
67*3ca9760fSShuah Khan {
68*3ca9760fSShuah Khan     time_t start_time;
69*3ca9760fSShuah Khan     int last_state;
70*3ca9760fSShuah Khan     time_t last_time;
71*3ca9760fSShuah Khan     int curr_state;
72*3ca9760fSShuah Khan     time_t curr_time = 0;
73*3ca9760fSShuah Khan     time_t time_diff;
74*3ca9760fSShuah Khan     time_t active_time = 0;
75*3ca9760fSShuah Khan     time_t sleep_time = 0;
76*3ca9760fSShuah Khan     time_t unknown_time = 0;
77*3ca9760fSShuah Khan     time_t total_time = 0;
78*3ca9760fSShuah Khan     int changes = 0;
79*3ca9760fSShuah Khan     float tmp;
80*3ca9760fSShuah Khan 
81*3ca9760fSShuah Khan     printf("Starting measurements\n");
82*3ca9760fSShuah Khan 
83*3ca9760fSShuah Khan     last_state = check_powermode(fd);
84*3ca9760fSShuah Khan     start_time = last_time = time(0);
85*3ca9760fSShuah Khan     printf("  System is in state %s\n\n", state_name(last_state));
86*3ca9760fSShuah Khan 
87*3ca9760fSShuah Khan     while(!endit) {
88*3ca9760fSShuah Khan 	sleep(1);
89*3ca9760fSShuah Khan 	curr_state = check_powermode(fd);
90*3ca9760fSShuah Khan 
91*3ca9760fSShuah Khan 	if (curr_state != last_state || endit) {
92*3ca9760fSShuah Khan 	    changes++;
93*3ca9760fSShuah Khan 	    curr_time = time(0);
94*3ca9760fSShuah Khan 	    time_diff = curr_time - last_time;
95*3ca9760fSShuah Khan 
96*3ca9760fSShuah Khan 	    if (last_state == 1) active_time += time_diff;
97*3ca9760fSShuah Khan 	    else if (last_state == 0) sleep_time += time_diff;
98*3ca9760fSShuah Khan 	    else unknown_time += time_diff;
99*3ca9760fSShuah Khan 
100*3ca9760fSShuah Khan 	    last_state = curr_state;
101*3ca9760fSShuah Khan 	    last_time = curr_time;
102*3ca9760fSShuah Khan 
103*3ca9760fSShuah Khan 	    printf("%s: State-change to %s\n", myctime(curr_time),
104*3ca9760fSShuah Khan 		   state_name(curr_state));
105*3ca9760fSShuah Khan 	}
106*3ca9760fSShuah Khan     }
107*3ca9760fSShuah Khan     changes--; /* Compensate for SIGINT */
108*3ca9760fSShuah Khan 
109*3ca9760fSShuah Khan     total_time = time(0) - start_time;
110*3ca9760fSShuah Khan     printf("\nTotal running time:  %lus\n", curr_time - start_time);
111*3ca9760fSShuah Khan     printf(" State changed %d times\n", changes);
112*3ca9760fSShuah Khan 
113*3ca9760fSShuah Khan     tmp = (float)sleep_time / (float)total_time * 100;
114*3ca9760fSShuah Khan     printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
115*3ca9760fSShuah Khan     tmp = (float)active_time / (float)total_time * 100;
116*3ca9760fSShuah Khan     printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
117*3ca9760fSShuah Khan     tmp = (float)unknown_time / (float)total_time * 100;
118*3ca9760fSShuah Khan     printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
119*3ca9760fSShuah Khan }
120*3ca9760fSShuah Khan 
ender(int s)121*3ca9760fSShuah Khan static void ender(int s)
122*3ca9760fSShuah Khan {
123*3ca9760fSShuah Khan     endit = 1;
124*3ca9760fSShuah Khan }
125*3ca9760fSShuah Khan 
usage(void)126*3ca9760fSShuah Khan static void usage(void)
127*3ca9760fSShuah Khan {
128*3ca9760fSShuah Khan     puts("usage: dslm [-w <time>] <disk>");
129*3ca9760fSShuah Khan     exit(0);
130*3ca9760fSShuah Khan }
131*3ca9760fSShuah Khan 
main(int argc,char ** argv)132*3ca9760fSShuah Khan int main(int argc, char **argv)
133*3ca9760fSShuah Khan {
134*3ca9760fSShuah Khan     int fd;
135*3ca9760fSShuah Khan     char *disk = 0;
136*3ca9760fSShuah Khan     int settle_time = 60;
137*3ca9760fSShuah Khan 
138*3ca9760fSShuah Khan     /* Parse the simple command-line */
139*3ca9760fSShuah Khan     if (argc == 2)
140*3ca9760fSShuah Khan 	disk = argv[1];
141*3ca9760fSShuah Khan     else if (argc == 4) {
142*3ca9760fSShuah Khan 	settle_time = atoi(argv[2]);
143*3ca9760fSShuah Khan 	disk = argv[3];
144*3ca9760fSShuah Khan     } else
145*3ca9760fSShuah Khan 	usage();
146*3ca9760fSShuah Khan 
147*3ca9760fSShuah Khan     if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
148*3ca9760fSShuah Khan 	printf("Can't open %s, because: %s\n", disk, strerror(errno));
149*3ca9760fSShuah Khan 	exit(-1);
150*3ca9760fSShuah Khan     }
151*3ca9760fSShuah Khan 
152*3ca9760fSShuah Khan     if (settle_time) {
153*3ca9760fSShuah Khan 	printf("Waiting %d seconds for the system to settle down to "
154*3ca9760fSShuah Khan 	       "'normal'\n", settle_time);
155*3ca9760fSShuah Khan 	sleep(settle_time);
156*3ca9760fSShuah Khan     } else
157*3ca9760fSShuah Khan 	puts("Not waiting for system to settle down");
158*3ca9760fSShuah Khan 
159*3ca9760fSShuah Khan     signal(SIGINT, ender);
160*3ca9760fSShuah Khan 
161*3ca9760fSShuah Khan     measure(fd);
162*3ca9760fSShuah Khan 
163*3ca9760fSShuah Khan     close(fd);
164*3ca9760fSShuah Khan 
165*3ca9760fSShuah Khan     return 0;
166*3ca9760fSShuah Khan }
167