|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
Linux动态频率调节系统CPUFreq之定义一个governor1 q8 w7 G8 a3 ?4 D
7 C& Y1 z f/ S A" W2 T
4 p, a2 b/ q, f* y5 h# }要实现一个governor,首先要定义一个cpufreq_governor结构,对于ondeman来说,它的定义如下:
) Z! F1 ~- O$ a3 o+ B* [
7 ?, U' H# b: d" r# u- }# T; D" }* `3 Q
- struct cpufreq_governor cpufreq_gov_ondemand = {
- .name = "ondemand",
- .governor = od_cpufreq_governor_dbs,
- .max_transition_latency = TRANSITION_LATENCY_LIMIT,
- .owner = THIS_MODULE,
- };5 M# c+ O! {7 R0 n
8 ^" ?' t# H8 i) Y/ {/ b: @1 a
2 l, J+ ]3 C* F+ k
: ]$ E9 J: m& v H
8 Q. z5 w1 {4 h& g5 C4 J. y! u- F
: C) y, a) ~6 e% S7 y
其中,governor是这个结构的核心字段,cpufreq_governor注册后,cpufreq的核心层通过该字段操纵这个governor的行为,包括:初始化、启动、退出等工作。现在,该字段被设置为od_cpufreq_governor_dbs,我们看看它的实现:
* G7 ]. J6 Z; ~, G/ S
p7 P E- Z# e( d5 r0 _5 ~
( r" T- ?' \: ^; ?- static int od_cpufreq_governor_dbs(struct cpufreq_policy *policy,
- unsigned int event)
- {
- return cpufreq_governor_dbs(policy, &od_dbs_cdata, event);
- }
1 F! Z' |5 Z3 H q: G( y
$ [* I/ k/ m5 P9 I/ p7 v0 v* e0 S# B* R4 q- D7 q6 D
6 ?5 r% _2 W7 Y1 g) w2 o
% @9 t( Z$ o( u9 L
, n }% ]5 M& u1 @5 p4 A" @$ E& A只是简单地调用了governor的公共层提供的API:cpufreq_governor_dbs,关于这个API,我们在后面会逐一进行展开,这里我们注意到参数:&od_dbs_cdata,正是我们前面讨论过得common_dbs_data结构,作为和governor公共层的接口,在这里它的定义如下:
, D0 @; u: ]$ h% A" m2 ?* L) O; E' F) E& b$ M7 v6 i9 N" a( J% R9 p5 v
) B$ [! k# Q1 E
- static struct common_dbs_data od_dbs_cdata = {
- .governor = GOV_ONDEMAND,
- .attr_group_gov_sys = &od_attr_group_gov_sys,
- .attr_group_gov_pol = &od_attr_group_gov_pol,
- .get_cpu_cdbs = get_cpu_cdbs,
- .get_cpu_dbs_info_s = get_cpu_dbs_info_s,
- .gov_dbs_timer = od_dbs_timer,
- .gov_check_cpu = od_check_cpu,
- .gov_ops = &od_ops,
- .init = od_init,
- .exit = od_exit,
- };
, a0 u3 g% H8 i |, V/ D+ g. }' [' Z- t
; J. a& h. U. a r, v$ c4 f; i' `2 a S& N; s) m* Z7 _" A
8 b' |( h' n2 o g
# ]0 Y' C A, R# L. y0 D这里先介绍一下get_cpu_cdbs和get_cpu_dbs_info_s这两个回调,前面介绍cpu_dbs_common_info_s结构的时候已经说过,各个governor需要定义一个cpu_dbs_common_info_s结构的派生结构,对于ondemand来说,这个派生结构是:od_cpu_dbs_info_s。两个回调函数分别用来获得基类和派生类这两个结构的指针。我们先看看od_cpu_dbs_info_s是如何定义的:5 U1 k8 F& X' c! U' {* Z
( ]. V) C5 @6 j
8 T' x2 x4 o2 z, H% N" y% @- static DEFINE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);
) l C- u2 _) i7 |6 i4 g
( M( A% P7 N: A6 |0 l% Z% o. j+ c) j2 K5 R2 k" ^' A
u m- U3 |8 Z9 K# W" J0 v. B2 W0 m% t& a6 B0 A
8 {# Q/ W* D% y2 A2 z7 i没错,它被定义为了一个per_cpu变量,也就是说,每个cpu拥有各自独立的od_cpu_dbs_info_s,这很正常,因为每个cpu需要的实时负载是不一样的,需要独立的上下文变量来进行负载的统计。前面也已经列出了od_cpu_dbs_info_s的声明,他的第一个字段cdbs就是一个cpu_dbs_common_info_s结构。内核为我们提供了一个辅助宏来帮助我们定义get_cpu_cdbs和get_cpu_dbs_info_s这两个回调函数:
% G: Y; E" u2 W& u& R9 M$ B& z6 o8 i4 b* e1 C% D
# l* V9 O- b" d6 {- #define define_get_cpu_dbs_routines(_dbs_info) \
- static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \
- { \
- return &per_cpu(_dbs_info, cpu).cdbs; \
- } \
- \
- static void *get_cpu_dbs_info_s(int cpu) \
- { \
- return &per_cpu(_dbs_info, cpu); \
- }
: I# J; J/ ^0 h( {( R& J 8 B3 X. j4 X; T( [, j
3 u, i. w( I+ ]3 b3 e7 O
' I; Q6 \: R( q1 p8 q& T3 E2 C& c9 o, z2 @0 {( h
) b% q8 Z! a( W. U9 c% ~8 _: @7 O" Z所以,在cpufreq_ondemand.c中,我们只要简单地使用上述的宏即可定义这两个回调:& V* K D$ ]7 V" C4 }7 J
* G, E6 |/ g+ Q" e& a5 u$ U; o' N5 p
- define_get_cpu_dbs_routines(od_cpu_dbs_info);/ R) Z* j; c0 Q, |3 C5 l, [
! i# y; ~1 [7 T2 L [* X6 z3 ], K
f d, i, U+ r# x5 p. e
1 A J; U- K) D) y% A
% E& q$ v& J3 N+ u4 n5 v5 W9 |$ Z( C0 V( c$ x; V
经过上述这一系列的定义以后,governor的公共层即可通过这两个回调获取各个cpu所对应的cpu_dbs_common_info_s和od_cpu_dbs_info_s的结构指针,用来记录本次统计周期的一些上下文参数(idle时间和运行时间等等)。) L# I% a: Q: r+ y; x( Q4 h
2 e g$ y' g$ A/ m& d* e: l! v0 C; x6 m. I( y0 `' p
5 A6 P% M- ?$ f, d
) P# X) Z; X9 c) Y/ a
6 v- c& c- m9 T4 h: q' f
9 o, l. N" I. q! W
2 V/ a5 C& W$ K' V8 ~" s5 _* p7 n( ^8 ^' Y2 k* s# k
# X. V( H/ z' ` a9 e. ?6 N. o6 |) X
: g# ^" n. d4 } h* h1 `! Y |
|