Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
1cc93586
Commit
1cc93586
authored
Dec 28, 2004
by
Dave Jones
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[CPUFREQ] Check in missing file for cpufreq stats.
Signed-off-by:
Dave Jones
<
davej@redhat.com
>
parent
f395e6c8
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
334 additions
and
0 deletions
+334
-0
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/cpufreq_stats.c
+334
-0
No files found.
drivers/cpufreq/cpufreq_stats.c
0 → 100644
View file @
1cc93586
/*
* drivers/cpufreq/cpufreq_stats.c
*
* Copyright (C) 2003-2004 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>.
* (C) 2004 Zou Nan hai <nanhai.zou@intel.com>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
#include <linux/sysfs.h>
#include <linux/cpufreq.h>
#include <linux/jiffies.h>
#include <linux/percpu.h>
#include <linux/kobject.h>
#include <linux/spinlock.h>
static
spinlock_t
cpufreq_stats_lock
;
#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
static struct freq_attr _attr_##_name = {\
.attr = {.name = __stringify(_name), .owner = THIS_MODULE, \
.mode = _mode, }, \
.show = _show,\
};
static
unsigned
long
delta_time
(
unsigned
long
old
,
unsigned
long
new
)
{
return
(
old
>
new
)
?
(
old
-
new
)
:
(
new
+
~
old
+
1
);
}
struct
cpufreq_stats
{
unsigned
int
cpu
;
unsigned
int
total_trans
;
unsigned
long
long
last_time
;
unsigned
int
max_state
;
unsigned
int
state_num
;
unsigned
int
last_index
;
unsigned
long
long
*
time_in_state
;
unsigned
int
*
freq_table
;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
unsigned
int
*
trans_table
;
#endif
};
static
struct
cpufreq_stats
*
cpufreq_stats_table
[
NR_CPUS
];
struct
cpufreq_stats_attribute
{
struct
attribute
attr
;
ssize_t
(
*
show
)
(
struct
cpufreq_stats
*
,
char
*
);
};
static
int
cpufreq_stats_update
(
unsigned
int
cpu
)
{
struct
cpufreq_stats
*
stat
;
spin_lock
(
&
cpufreq_stats_lock
);
stat
=
cpufreq_stats_table
[
cpu
];
if
(
stat
->
time_in_state
)
stat
->
time_in_state
[
stat
->
last_index
]
+=
delta_time
(
stat
->
last_time
,
jiffies
);
stat
->
last_time
=
jiffies
;
spin_unlock
(
&
cpufreq_stats_lock
);
return
0
;
}
static
ssize_t
show_total_trans
(
struct
cpufreq_policy
*
policy
,
char
*
buf
)
{
struct
cpufreq_stats
*
stat
=
cpufreq_stats_table
[
policy
->
cpu
];
if
(
!
stat
)
return
0
;
return
sprintf
(
buf
,
"%d
\n
"
,
cpufreq_stats_table
[
stat
->
cpu
]
->
total_trans
);
}
static
ssize_t
show_time_in_state
(
struct
cpufreq_policy
*
policy
,
char
*
buf
)
{
ssize_t
len
=
0
;
int
i
;
struct
cpufreq_stats
*
stat
=
cpufreq_stats_table
[
policy
->
cpu
];
if
(
!
stat
)
return
0
;
cpufreq_stats_update
(
stat
->
cpu
);
for
(
i
=
0
;
i
<
stat
->
state_num
;
i
++
)
{
len
+=
sprintf
(
buf
+
len
,
"%u %llu
\n
"
,
stat
->
freq_table
[
i
],
stat
->
time_in_state
[
i
]);
}
return
len
;
}
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
static
ssize_t
show_trans_table
(
struct
cpufreq_policy
*
policy
,
char
*
buf
)
{
ssize_t
len
=
0
;
int
i
,
j
;
struct
cpufreq_stats
*
stat
=
cpufreq_stats_table
[
policy
->
cpu
];
if
(
!
stat
)
return
0
;
cpufreq_stats_update
(
stat
->
cpu
);
for
(
i
=
0
;
i
<
stat
->
state_num
;
i
++
)
{
if
(
len
>=
PAGE_SIZE
)
break
;
len
+=
snprintf
(
buf
+
len
,
PAGE_SIZE
-
len
,
"%9u:
\t
"
,
stat
->
freq_table
[
i
]);
for
(
j
=
0
;
j
<
stat
->
state_num
;
j
++
)
{
if
(
len
>=
PAGE_SIZE
)
break
;
len
+=
snprintf
(
buf
+
len
,
PAGE_SIZE
-
len
,
"%u
\t
"
,
stat
->
trans_table
[
i
*
stat
->
max_state
+
j
]);
}
len
+=
snprintf
(
buf
+
len
,
PAGE_SIZE
-
len
,
"
\n
"
);
}
return
len
;
}
CPUFREQ_STATDEVICE_ATTR
(
trans_table
,
0444
,
show_trans_table
);
#endif
CPUFREQ_STATDEVICE_ATTR
(
total_trans
,
0444
,
show_total_trans
);
CPUFREQ_STATDEVICE_ATTR
(
time_in_state
,
0444
,
show_time_in_state
);
static
struct
attribute
*
default_attrs
[]
=
{
&
_attr_total_trans
.
attr
,
&
_attr_time_in_state
.
attr
,
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
&
_attr_trans_table
.
attr
,
#endif
NULL
};
static
struct
attribute_group
stats_attr_group
=
{
.
attrs
=
default_attrs
,
.
name
=
"stats"
};
static
int
freq_table_get_index
(
struct
cpufreq_stats
*
stat
,
unsigned
int
freq
)
{
int
index
;
for
(
index
=
0
;
index
<
stat
->
max_state
;
index
++
)
if
(
stat
->
freq_table
[
index
]
==
freq
)
return
index
;
return
-
1
;
}
static
void
cpufreq_stats_free_table
(
unsigned
int
cpu
)
{
struct
cpufreq_stats
*
stat
=
cpufreq_stats_table
[
cpu
];
struct
cpufreq_policy
*
policy
=
cpufreq_cpu_get
(
cpu
);
if
(
policy
&&
policy
->
cpu
==
cpu
)
sysfs_remove_group
(
&
policy
->
kobj
,
&
stats_attr_group
);
if
(
stat
)
{
kfree
(
stat
->
time_in_state
);
kfree
(
stat
);
}
cpufreq_stats_table
[
cpu
]
=
NULL
;
if
(
policy
)
cpufreq_cpu_put
(
policy
);
}
static
int
cpufreq_stats_create_table
(
struct
cpufreq_policy
*
policy
,
struct
cpufreq_frequency_table
*
table
)
{
unsigned
int
i
,
j
,
count
=
0
,
ret
=
0
;
struct
cpufreq_stats
*
stat
;
struct
cpufreq_policy
*
data
;
unsigned
int
alloc_size
;
unsigned
int
cpu
=
policy
->
cpu
;
if
(
cpufreq_stats_table
[
cpu
])
return
-
EBUSY
;
if
((
stat
=
kmalloc
(
sizeof
(
struct
cpufreq_stats
),
GFP_KERNEL
))
==
NULL
)
return
-
ENOMEM
;
memset
(
stat
,
0
,
sizeof
(
struct
cpufreq_stats
));
data
=
cpufreq_cpu_get
(
cpu
);
if
((
ret
=
sysfs_create_group
(
&
data
->
kobj
,
&
stats_attr_group
)))
goto
error_out
;
stat
->
cpu
=
cpu
;
cpufreq_stats_table
[
cpu
]
=
stat
;
for
(
i
=
0
;
table
[
i
].
frequency
!=
CPUFREQ_TABLE_END
;
i
++
)
{
unsigned
int
freq
=
table
[
i
].
frequency
;
if
(
freq
==
CPUFREQ_ENTRY_INVALID
)
continue
;
count
++
;
}
alloc_size
=
count
*
sizeof
(
int
)
+
count
*
sizeof
(
long
long
);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size
+=
count
*
count
*
sizeof
(
int
);
#endif
stat
->
max_state
=
count
;
stat
->
time_in_state
=
kmalloc
(
alloc_size
,
GFP_KERNEL
);
if
(
!
stat
->
time_in_state
)
{
ret
=
-
ENOMEM
;
goto
error_out
;
}
memset
(
stat
->
time_in_state
,
0
,
alloc_size
);
stat
->
freq_table
=
(
unsigned
int
*
)(
stat
->
time_in_state
+
count
);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat
->
trans_table
=
stat
->
freq_table
+
count
;
#endif
j
=
0
;
for
(
i
=
0
;
table
[
i
].
frequency
!=
CPUFREQ_TABLE_END
;
i
++
)
{
unsigned
int
freq
=
table
[
i
].
frequency
;
if
(
freq
==
CPUFREQ_ENTRY_INVALID
)
continue
;
if
(
freq_table_get_index
(
stat
,
freq
)
==
-
1
)
stat
->
freq_table
[
j
++
]
=
freq
;
}
stat
->
state_num
=
j
;
spin_lock
(
&
cpufreq_stats_lock
);
stat
->
last_time
=
jiffies
;
stat
->
last_index
=
freq_table_get_index
(
stat
,
policy
->
cur
);
spin_unlock
(
&
cpufreq_stats_lock
);
cpufreq_cpu_put
(
data
);
return
0
;
error_out:
cpufreq_cpu_put
(
data
);
kfree
(
stat
);
cpufreq_stats_table
[
cpu
]
=
NULL
;
return
ret
;
}
static
int
cpufreq_stat_notifier_policy
(
struct
notifier_block
*
nb
,
unsigned
long
val
,
void
*
data
)
{
int
ret
;
struct
cpufreq_policy
*
policy
=
data
;
struct
cpufreq_frequency_table
*
table
;
unsigned
int
cpu
=
policy
->
cpu
;
if
(
val
!=
CPUFREQ_NOTIFY
)
return
0
;
table
=
cpufreq_frequency_get_table
(
cpu
);
if
(
!
table
)
return
0
;
if
((
ret
=
cpufreq_stats_create_table
(
policy
,
table
)))
return
ret
;
return
0
;
}
static
int
cpufreq_stat_notifier_trans
(
struct
notifier_block
*
nb
,
unsigned
long
val
,
void
*
data
)
{
struct
cpufreq_freqs
*
freq
=
data
;
struct
cpufreq_stats
*
stat
;
int
old_index
,
new_index
;
if
(
val
!=
CPUFREQ_POSTCHANGE
)
return
0
;
stat
=
cpufreq_stats_table
[
freq
->
cpu
];
if
(
!
stat
)
return
0
;
old_index
=
freq_table_get_index
(
stat
,
freq
->
old
);
new_index
=
freq_table_get_index
(
stat
,
freq
->
new
);
cpufreq_stats_update
(
freq
->
cpu
);
if
(
old_index
==
new_index
)
return
0
;
spin_lock
(
&
cpufreq_stats_lock
);
stat
->
last_index
=
new_index
;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat
->
trans_table
[
old_index
*
stat
->
max_state
+
new_index
]
++
;
#endif
stat
->
total_trans
++
;
spin_unlock
(
&
cpufreq_stats_lock
);
return
0
;
}
static
struct
notifier_block
notifier_policy_block
=
{
.
notifier_call
=
cpufreq_stat_notifier_policy
};
static
struct
notifier_block
notifier_trans_block
=
{
.
notifier_call
=
cpufreq_stat_notifier_trans
};
static
int
__init
cpufreq_stats_init
(
void
)
{
int
ret
;
unsigned
int
cpu
;
spin_lock_init
(
&
cpufreq_stats_lock
);
if
((
ret
=
cpufreq_register_notifier
(
&
notifier_policy_block
,
CPUFREQ_POLICY_NOTIFIER
)))
return
ret
;
if
((
ret
=
cpufreq_register_notifier
(
&
notifier_trans_block
,
CPUFREQ_TRANSITION_NOTIFIER
)))
{
cpufreq_unregister_notifier
(
&
notifier_policy_block
,
CPUFREQ_POLICY_NOTIFIER
);
return
ret
;
}
for_each_cpu
(
cpu
)
cpufreq_update_policy
(
cpu
);
return
0
;
}
static
void
__exit
cpufreq_stats_exit
(
void
)
{
unsigned
int
cpu
;
cpufreq_unregister_notifier
(
&
notifier_policy_block
,
CPUFREQ_POLICY_NOTIFIER
);
cpufreq_unregister_notifier
(
&
notifier_trans_block
,
CPUFREQ_TRANSITION_NOTIFIER
);
for_each_cpu
(
cpu
)
cpufreq_stats_free_table
(
cpu
);
}
MODULE_AUTHOR
(
"Zou Nan hai <nanhai.zou@intel.com>"
);
MODULE_DESCRIPTION
(
"'cpufreq_stats' - A driver to export cpufreq stats through sysfs filesystem"
);
MODULE_LICENSE
(
"GPL"
);
module_init
(
cpufreq_stats_init
);
module_exit
(
cpufreq_stats_exit
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment