1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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>
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
44 #define NUM_SAMPLES 64
45 #define NUM_SAMPLES_MASK (NUM_SAMPLES-1)
48 struct cputime_sample
{
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
;
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)
91 static void __attribute__((constructor
)) get_initial_time(void)
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 */
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
));
111 clock_t total_cputime
;
112 clock_t diff_utime
, diff_stime
;
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
))
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
;
135 int cpucount_linux(void)
140 int frequency_linux(int cpu
, bool scaling
)
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
);
151 if (read(cpu_dev
, temp
, sizeof(temp
)) >= 0)
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
;
162 snprintf(path
, sizeof(path
), "/sys/devices/system/cpu/cpu%d/cpufreq/stats/time_in_state", cpu
);
163 cpu_dev
= open(path
, O_RDONLY
);
166 read_size
= read(cpu_dev
, buf
, sizeof(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
++));
184 return (max_elements
- elements_left
) ?: -1;