Fix non-integer display_zoom for charcell.
[maemo-rb.git] / firmware / target / hosted / cpuinfo-linux.c
blobe0a6bd76dafb4c37dd38781b21ff9ba9952824c9
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2011 Thomas Martitz
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include <sys/times.h>
24 #include <sys/sysinfo.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33 #include "kernel.h"
34 #include "thread.h"
35 #include "cpuinfo-linux.h"
36 #include "gcc_extensions.h"
38 #undef open /* want the *real* open here, not sim_open or the like */
39 #if (CONFIG_PLATFORM & PLATFORM_ANDROID)
40 #include "cpu-features.h"
41 #define get_nprocs android_getCpuCount
42 #endif
44 #define NUM_SAMPLES 64
45 #define NUM_SAMPLES_MASK (NUM_SAMPLES-1)
46 #define SAMPLE_RATE 4
48 struct cputime_sample {
49 struct tms sample;
50 time_t time;
53 static struct cputime_sample samples[NUM_SAMPLES];
54 static int current_sample;
55 static int samples_taken;
56 static clock_t initial_time, hz;
59 static char cputime_thread_stack[DEFAULT_STACK_SIZE + 0x100];
60 static char cputime_thread_name[] = "cputime";
61 static int cputime_threadid;
62 static void cputime_thread(void);
64 /* times() can return -1 early after boot */
65 static clock_t times_wrapper(struct tms *t)
67 clock_t res = times(t);
68 if (res == (clock_t)-1)
69 res = time(NULL) * hz;
71 return res;
74 static inline void thread_func(void)
76 struct cputime_sample *s = &samples[current_sample++];
77 s->time = times_wrapper(&s->sample);
79 current_sample &= NUM_SAMPLES_MASK;
80 if (samples_taken < NUM_SAMPLES) samples_taken++;
82 sleep(HZ/SAMPLE_RATE);
85 static void NORETURN_ATTR cputime_thread(void)
87 while(1)
88 thread_func();
91 static void __attribute__((constructor)) get_initial_time(void)
93 struct tms ign;
94 hz = sysconf(_SC_CLK_TCK);
95 initial_time = times_wrapper(&ign); /* dont pass NULL */;
98 int cpuusage_linux(struct cpuusage* u)
100 if (UNLIKELY(!cputime_threadid))
102 /* collect some initial data and start the thread */
103 thread_func();
104 cputime_threadid = create_thread(cputime_thread, cputime_thread_stack,
105 sizeof(cputime_thread_stack), 0, cputime_thread_name
106 IF_PRIO(,PRIORITY_BACKGROUND) IF_COP(, CPU));
108 if (!u)
109 return -1;
111 clock_t total_cputime;
112 clock_t diff_utime, diff_stime;
113 time_t diff_rtime;
114 int latest_sample = ((current_sample == 0) ? NUM_SAMPLES : current_sample) - 1;
115 int oldest_sample = (samples_taken < NUM_SAMPLES) ? 0 : current_sample;
117 diff_utime = samples[latest_sample].sample.tms_utime - samples[oldest_sample].sample.tms_utime;
118 diff_stime = samples[latest_sample].sample.tms_stime - samples[oldest_sample].sample.tms_stime;
119 diff_rtime = samples[latest_sample].time - samples[oldest_sample].time;
120 if (UNLIKELY(!diff_rtime))
121 diff_rtime = 1;
122 u->hz = hz;
124 u->utime = samples[latest_sample].sample.tms_utime;
125 u->stime = samples[latest_sample].sample.tms_stime;
126 u->rtime = samples[latest_sample].time - initial_time;
128 total_cputime = diff_utime + diff_stime;
129 total_cputime *= 100; /* pump up by 100 for hundredth */
130 u->usage = total_cputime * 100 / diff_rtime;
132 return 0;
135 int cpucount_linux(void)
137 return get_nprocs();
140 int frequency_linux(int cpu, bool scaling)
142 char path[64];
143 char temp[10];
144 int cpu_dev, ret = -1;
145 snprintf(path, sizeof(path),
146 "/sys/devices/system/cpu/cpu%d/cpufreq/%s_cur_freq",
147 cpu, scaling ? "scaling" : "cpuinfo");
148 cpu_dev = open(path, O_RDONLY);
149 if (cpu_dev < 0)
150 return -1;
151 if (read(cpu_dev, temp, sizeof(temp)) >= 0)
152 ret = atoi(temp);
153 close(cpu_dev);
154 return ret;
157 int cpustatetimes_linux(int cpu, struct time_state* data, int max_elements)
159 int elements_left = max_elements, cpu_dev;
160 char buf[256], path[64], *p;
161 ssize_t read_size;
162 snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", cpu);
163 cpu_dev = open(path, O_RDONLY);
164 if (cpu_dev < 0)
165 return -1;
166 read_size = read(cpu_dev, buf, sizeof(buf));
168 close(cpu_dev);
170 p = buf;
171 while(elements_left > 0 && (p-buf) < read_size)
173 data->frequency = atol(p);
174 /* this loop breaks when it seems the space or line-feed,
175 * so buf points to a number aftwards */
176 while(isdigit(*p++));
177 data->time = atol(p);
178 /* now skip over to the next line */
179 while(isdigit(*p++));
180 data++;
181 elements_left--;
184 return (max_elements - elements_left) ?: -1;