diff options
Diffstat (limited to 'tools/power/cpupower/bench')
-rw-r--r-- | tools/power/cpupower/bench/Makefile | 30 | ||||
-rw-r--r-- | tools/power/cpupower/bench/README-BENCH | 124 | ||||
-rw-r--r-- | tools/power/cpupower/bench/benchmark.c | 184 | ||||
-rw-r--r-- | tools/power/cpupower/bench/benchmark.h | 27 | ||||
-rw-r--r-- | tools/power/cpupower/bench/config.h | 36 | ||||
-rw-r--r-- | tools/power/cpupower/bench/cpufreq-bench_plot.sh | 104 | ||||
-rw-r--r-- | tools/power/cpupower/bench/cpufreq-bench_script.sh | 101 | ||||
-rw-r--r-- | tools/power/cpupower/bench/example.cfg | 11 | ||||
-rw-r--r-- | tools/power/cpupower/bench/main.c | 203 | ||||
-rw-r--r-- | tools/power/cpupower/bench/parse.c | 224 | ||||
-rw-r--r-- | tools/power/cpupower/bench/parse.h | 50 | ||||
-rw-r--r-- | tools/power/cpupower/bench/system.c | 188 | ||||
-rw-r--r-- | tools/power/cpupower/bench/system.h | 29 |
13 files changed, 1311 insertions, 0 deletions
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile new file mode 100644 index 00000000000..3d8fa21855f --- /dev/null +++ b/tools/power/cpupower/bench/Makefile | |||
@@ -0,0 +1,30 @@ | |||
1 | LIBS = -L../ -lm -lcpufreq | ||
2 | |||
3 | OBJS = main.o parse.o system.o benchmark.o | ||
4 | CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" | ||
5 | |||
6 | ifeq ($(strip $(V)),false) | ||
7 | CC=@../build/ccdv gcc | ||
8 | else | ||
9 | CC=gcc | ||
10 | endif | ||
11 | |||
12 | cpufreq-bench: $(OBJS) | ||
13 | $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) | ||
14 | |||
15 | all: cpufreq-bench | ||
16 | |||
17 | install: | ||
18 | mkdir -p $(DESTDIR)/$(sbindir) | ||
19 | mkdir -p $(DESTDIR)/$(bindir) | ||
20 | mkdir -p $(DESTDIR)/$(docdir) | ||
21 | mkdir -p $(DESTDIR)/$(confdir) | ||
22 | install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench | ||
23 | install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh | ||
24 | install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH | ||
25 | install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh | ||
26 | install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf | ||
27 | |||
28 | clean: | ||
29 | rm -f *.o | ||
30 | rm -f cpufreq-bench | ||
diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH new file mode 100644 index 00000000000..8093ec73817 --- /dev/null +++ b/tools/power/cpupower/bench/README-BENCH | |||
@@ -0,0 +1,124 @@ | |||
1 | This is cpufreq-bench, a microbenchmark for the cpufreq framework. | ||
2 | |||
3 | Purpose | ||
4 | ======= | ||
5 | |||
6 | What is this benchmark for: | ||
7 | - Identify worst case performance loss when doing dynamic frequency | ||
8 | scaling using Linux kernel governors | ||
9 | - Identify average reaction time of a governor to CPU load changes | ||
10 | - (Stress) Testing whether a cpufreq low level driver or governor works | ||
11 | as expected | ||
12 | - Identify cpufreq related performance regressions between kernels | ||
13 | - Possibly Real time priority testing? -> what happens if there are | ||
14 | processes with a higher prio than the governor's kernel thread | ||
15 | - ... | ||
16 | |||
17 | What this benchmark does *not* cover: | ||
18 | - Power saving related regressions (In fact as better the performance | ||
19 | throughput is, the worse the power savings will be, but the first should | ||
20 | mostly count more...) | ||
21 | - Real world (workloads) | ||
22 | |||
23 | |||
24 | Description | ||
25 | =========== | ||
26 | |||
27 | cpufreq-bench helps to test the condition of a given cpufreq governor. | ||
28 | For that purpose, it compares the performance governor to a configured | ||
29 | powersave module. | ||
30 | |||
31 | |||
32 | How it works | ||
33 | ============ | ||
34 | You can specify load (100% CPU load) and sleep (0% CPU load) times in us which | ||
35 | will be run X time in a row (cycles): | ||
36 | |||
37 | sleep=25000 | ||
38 | load=25000 | ||
39 | cycles=20 | ||
40 | |||
41 | This part of the configuration file will create 25ms load/sleep turns, | ||
42 | repeated 20 times. | ||
43 | |||
44 | Adding this: | ||
45 | sleep_step=25000 | ||
46 | load_step=25000 | ||
47 | rounds=5 | ||
48 | Will increase load and sleep time by 25ms 5 times. | ||
49 | Together you get following test: | ||
50 | 25ms load/sleep time repeated 20 times (cycles). | ||
51 | 50ms load/sleep time repeated 20 times (cycles). | ||
52 | .. | ||
53 | 100ms load/sleep time repeated 20 times (cycles). | ||
54 | |||
55 | First it is calibrated how long a specific CPU intensive calculation | ||
56 | takes on this machine and needs to be run in a loop using the performance | ||
57 | governor. | ||
58 | Then the above test runs are processed using the performance governor | ||
59 | and the governor to test. The time the calculation really needed | ||
60 | with the dynamic freq scaling governor is compared with the time needed | ||
61 | on full performance and you get the overall performance loss. | ||
62 | |||
63 | |||
64 | Example of expected results with ondemand governor: | ||
65 | |||
66 | This shows expected results of the first two test run rounds from | ||
67 | above config, you there have: | ||
68 | |||
69 | 100% CPU load (load) | 0 % CPU load (sleep) | round | ||
70 | 25 ms | 25 ms | 1 | ||
71 | 50 ms | 50 ms | 2 | ||
72 | |||
73 | For example if ondemand governor is configured to have a 50ms | ||
74 | sampling rate you get: | ||
75 | |||
76 | In round 1, ondemand should have rather static 50% load and probably | ||
77 | won't ever switch up (as long as up_threshold is above). | ||
78 | |||
79 | In round 2, if the ondemand sampling times exactly match the load/sleep | ||
80 | trigger of the cpufreq-bench, you will see no performance loss (compare with | ||
81 | below possible ondemand sample kick ins (1)): | ||
82 | |||
83 | But if ondemand always kicks in in the middle of the load sleep cycles, it | ||
84 | will always see 50% loads and you get worst performance impact never | ||
85 | switching up (compare with below possible ondemand sample kick ins (2)):: | ||
86 | |||
87 | 50 50 50 50ms ->time | ||
88 | load -----| |-----| |-----| |-----| | ||
89 | | | | | | | | | ||
90 | sleep |-----| |-----| |-----| |---- | ||
91 | |-----|-----|-----|-----|-----|-----|-----|---- ondemand sampling (1) | ||
92 | 100 0 100 0 100 0 100 load seen by ondemand(%) | ||
93 | |-----|-----|-----|-----|-----|-----|-----|-- ondemand sampling (2) | ||
94 | 50 50 50 50 50 50 50 load seen by ondemand(%) | ||
95 | |||
96 | You can easily test all kind of load/sleep times and check whether your | ||
97 | governor in average behaves as expected. | ||
98 | |||
99 | |||
100 | ToDo | ||
101 | ==== | ||
102 | |||
103 | Provide a gnuplot utility script for easy generation of plots to present | ||
104 | the outcome nicely. | ||
105 | |||
106 | |||
107 | cpufreq-bench Command Usage | ||
108 | =========================== | ||
109 | -l, --load=<long int> initial load time in us | ||
110 | -s, --sleep=<long int> initial sleep time in us | ||
111 | -x, --load-step=<long int> time to be added to load time, in us | ||
112 | -y, --sleep-step=<long int> time to be added to sleep time, in us | ||
113 | -c, --cpu=<unsigned int> CPU Number to use, starting at 0 | ||
114 | -p, --prio=<priority> scheduler priority, HIGH, LOW or DEFAULT | ||
115 | -g, --governor=<governor> cpufreq governor to test | ||
116 | -n, --cycles=<int> load/sleep cycles to get an avarage value to compare | ||
117 | -r, --rounds<int> load/sleep rounds | ||
118 | -f, --file=<configfile> config file to use | ||
119 | -o, --output=<dir> output dir, must exist | ||
120 | -v, --verbose verbose output on/off | ||
121 | |||
122 | Due to the high priority, the application may not be responsible for some time. | ||
123 | After the benchmark, the logfile is saved in OUTPUTDIR/benchmark_TIMESTAMP.log | ||
124 | |||
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c new file mode 100644 index 00000000000..f538633b8b4 --- /dev/null +++ b/tools/power/cpupower/bench/benchmark.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <unistd.h> | ||
22 | #include <math.h> | ||
23 | |||
24 | #include "config.h" | ||
25 | #include "system.h" | ||
26 | #include "benchmark.h" | ||
27 | |||
28 | /* Print out progress if we log into a file */ | ||
29 | #define show_progress(total_time, progress_time) \ | ||
30 | if (config->output != stdout) { \ | ||
31 | fprintf(stdout, "Progress: %02lu %%\r", \ | ||
32 | (progress_time * 100) / total_time); \ | ||
33 | fflush(stdout); \ | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * compute how many rounds of calculation we should do | ||
38 | * to get the given load time | ||
39 | * | ||
40 | * @param load aimed load time in µs | ||
41 | * | ||
42 | * @retval rounds of calculation | ||
43 | **/ | ||
44 | |||
45 | unsigned int calculate_timespace(long load, struct config *config) | ||
46 | { | ||
47 | int i; | ||
48 | long long now, then; | ||
49 | unsigned int estimated = GAUGECOUNT; | ||
50 | unsigned int rounds = 0; | ||
51 | unsigned int timed = 0; | ||
52 | |||
53 | if (config->verbose) | ||
54 | printf("calibrating load of %lius, please wait...\n", load); | ||
55 | |||
56 | /* get the initial calculation time for a specific number of rounds */ | ||
57 | now = get_time(); | ||
58 | ROUNDS(estimated); | ||
59 | then = get_time(); | ||
60 | |||
61 | timed = (unsigned int)(then - now); | ||
62 | |||
63 | /* approximation of the wanted load time by comparing with the | ||
64 | * initial calculation time */ | ||
65 | for (i= 0; i < 4; i++) | ||
66 | { | ||
67 | rounds = (unsigned int)(load * estimated / timed); | ||
68 | dprintf("calibrating with %u rounds\n", rounds); | ||
69 | now = get_time(); | ||
70 | ROUNDS(rounds); | ||
71 | then = get_time(); | ||
72 | |||
73 | timed = (unsigned int)(then - now); | ||
74 | estimated = rounds; | ||
75 | } | ||
76 | if (config->verbose) | ||
77 | printf("calibration done\n"); | ||
78 | |||
79 | return estimated; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * benchmark | ||
84 | * generates a specific sleep an load time with the performance | ||
85 | * governor and compares the used time for same calculations done | ||
86 | * with the configured powersave governor | ||
87 | * | ||
88 | * @param config config values for the benchmark | ||
89 | * | ||
90 | **/ | ||
91 | |||
92 | void start_benchmark(struct config *config) | ||
93 | { | ||
94 | unsigned int _round, cycle; | ||
95 | long long now, then; | ||
96 | long sleep_time = 0, load_time = 0; | ||
97 | long performance_time = 0, powersave_time = 0; | ||
98 | unsigned int calculations; | ||
99 | unsigned long total_time = 0, progress_time = 0; | ||
100 | |||
101 | sleep_time = config->sleep; | ||
102 | load_time = config->load; | ||
103 | |||
104 | /* For the progress bar */ | ||
105 | for (_round=1; _round <= config->rounds; _round++) | ||
106 | total_time += _round * (config->sleep + config->load); | ||
107 | total_time *= 2; /* powersave and performance cycles */ | ||
108 | |||
109 | for (_round=0; _round < config->rounds; _round++) { | ||
110 | performance_time = 0LL; | ||
111 | powersave_time = 0LL; | ||
112 | |||
113 | show_progress(total_time, progress_time); | ||
114 | |||
115 | /* set the cpufreq governor to "performance" which disables | ||
116 | * P-State switching. */ | ||
117 | if (set_cpufreq_governor("performance", config->cpu) != 0) | ||
118 | return; | ||
119 | |||
120 | /* calibrate the calculation time. the resulting calculation | ||
121 | * _rounds should produce a load which matches the configured | ||
122 | * load time */ | ||
123 | calculations = calculate_timespace(load_time, config); | ||
124 | |||
125 | if (config->verbose) | ||
126 | printf("_round %i: doing %u cycles with %u calculations" | ||
127 | " for %lius\n", _round + 1, config->cycles, | ||
128 | calculations, load_time); | ||
129 | |||
130 | fprintf(config->output, "%u %li %li ", | ||
131 | _round, load_time, sleep_time); | ||
132 | |||
133 | if (config->verbose) { | ||
134 | printf("avarage: %lius, rps:%li\n", load_time / calculations, 1000000 * calculations / load_time); | ||
135 | } | ||
136 | |||
137 | /* do some sleep/load cycles with the performance governor */ | ||
138 | for (cycle = 0; cycle < config->cycles; cycle++) { | ||
139 | now = get_time(); | ||
140 | usleep(sleep_time); | ||
141 | ROUNDS(calculations); | ||
142 | then = get_time(); | ||
143 | performance_time += then - now - sleep_time; | ||
144 | if (config->verbose) | ||
145 | printf("performance cycle took %lius, sleep: %lius, load: %lius, rounds: %u\n", | ||
146 | (long)(then - now), sleep_time, load_time, calculations); | ||
147 | } | ||
148 | fprintf(config->output, "%li ", performance_time / config->cycles); | ||
149 | |||
150 | progress_time += sleep_time + load_time; | ||
151 | show_progress(total_time, progress_time); | ||
152 | |||
153 | /* set the powersave governor which activates P-State switching | ||
154 | * again */ | ||
155 | if (set_cpufreq_governor(config->governor, config->cpu) != 0) | ||
156 | return; | ||
157 | |||
158 | /* again, do some sleep/load cycles with the powersave governor */ | ||
159 | for (cycle = 0; cycle < config->cycles; cycle++) { | ||
160 | now = get_time(); | ||
161 | usleep(sleep_time); | ||
162 | ROUNDS(calculations); | ||
163 | then = get_time(); | ||
164 | powersave_time += then - now - sleep_time; | ||
165 | if (config->verbose) | ||
166 | printf("powersave cycle took %lius, sleep: %lius, load: %lius, rounds: %u\n", | ||
167 | (long)(then - now), sleep_time, load_time, calculations); | ||
168 | } | ||
169 | |||
170 | progress_time += sleep_time + load_time; | ||
171 | |||
172 | /* compare the avarage sleep/load cycles */ | ||
173 | fprintf(config->output, "%li ", powersave_time / config->cycles); | ||
174 | fprintf(config->output, "%.3f\n", performance_time * 100.0 / powersave_time); | ||
175 | fflush(config->output); | ||
176 | |||
177 | if (config->verbose) | ||
178 | printf("performance is at %.2f%%\n", performance_time * 100.0 / powersave_time); | ||
179 | |||
180 | sleep_time += config->sleep_step; | ||
181 | load_time += config->load_step; | ||
182 | } | ||
183 | } | ||
184 | |||
diff --git a/tools/power/cpupower/bench/benchmark.h b/tools/power/cpupower/bench/benchmark.h new file mode 100644 index 00000000000..0691f91b720 --- /dev/null +++ b/tools/power/cpupower/bench/benchmark.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* load loop, this schould take about 1 to 2ms to complete */ | ||
21 | #define ROUNDS(x) {unsigned int rcnt; \ | ||
22 | for (rcnt = 0; rcnt< x*1000; rcnt++) { \ | ||
23 | (void)(((int)(pow(rcnt, rcnt) * sqrt(rcnt*7230970)) ^ 7230716) ^ (int)atan2(rcnt, rcnt)); \ | ||
24 | }} \ | ||
25 | |||
26 | |||
27 | void start_benchmark(struct config *config); | ||
diff --git a/tools/power/cpupower/bench/config.h b/tools/power/cpupower/bench/config.h new file mode 100644 index 00000000000..9690f1be32f --- /dev/null +++ b/tools/power/cpupower/bench/config.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* initial loop count for the load calibration */ | ||
21 | #define GAUGECOUNT 1500 | ||
22 | |||
23 | /* default scheduling policy SCHED_OTHER */ | ||
24 | #define SCHEDULER SCHED_OTHER | ||
25 | |||
26 | #define PRIORITY_DEFAULT 0 | ||
27 | #define PRIORITY_HIGH sched_get_priority_max(SCHEDULER) | ||
28 | #define PRIORITY_LOW sched_get_priority_min(SCHEDULER) | ||
29 | |||
30 | /* enable further debug messages */ | ||
31 | #ifdef DEBUG | ||
32 | #define dprintf printf | ||
33 | #else | ||
34 | #define dprintf( ... ) while(0) { } | ||
35 | #endif | ||
36 | |||
diff --git a/tools/power/cpupower/bench/cpufreq-bench_plot.sh b/tools/power/cpupower/bench/cpufreq-bench_plot.sh new file mode 100644 index 00000000000..410021a12f4 --- /dev/null +++ b/tools/power/cpupower/bench/cpufreq-bench_plot.sh | |||
@@ -0,0 +1,104 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This program is free software: you can redistribute it and/or modify | ||
4 | # it under the terms of the GNU General Public License as published by | ||
5 | # the Free Software Foundation; either version 2, or (at your option) | ||
6 | # any later version. | ||
7 | |||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | |||
13 | # You should have received a copy of the GNU General Public License | ||
14 | # along with this program; if not, write to the Free Software | ||
15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
16 | # 02110-1301, USA. | ||
17 | |||
18 | # Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
19 | |||
20 | # Helper script to easily create nice plots of your cpufreq-bench results | ||
21 | |||
22 | dir=`mktemp -d` | ||
23 | output_file="cpufreq-bench.png" | ||
24 | global_title="cpufreq-bench plot" | ||
25 | picture_type="jpeg" | ||
26 | file[0]="" | ||
27 | |||
28 | function usage() | ||
29 | { | ||
30 | echo "cpufreq-bench_plot.sh [OPTIONS] logfile [measure_title] [logfile [measure_title]] ...]" | ||
31 | echo | ||
32 | echo "Options" | ||
33 | echo " -o output_file" | ||
34 | echo " -t global_title" | ||
35 | echo " -p picture_type [jpeg|gif|png|postscript|...]" | ||
36 | exit 1 | ||
37 | } | ||
38 | |||
39 | if [ $# -eq 0 ];then | ||
40 | echo "No benchmark results file provided" | ||
41 | echo | ||
42 | usage | ||
43 | fi | ||
44 | |||
45 | while getopts o:t:p: name ; do | ||
46 | case $name in | ||
47 | o) | ||
48 | output_file="$OPTARG".$picture_type | ||
49 | ;; | ||
50 | t) | ||
51 | global_title="$OPTARG" | ||
52 | ;; | ||
53 | p) | ||
54 | picture_type="$OPTARG" | ||
55 | ;; | ||
56 | ?) | ||
57 | usage | ||
58 | ;; | ||
59 | esac | ||
60 | done | ||
61 | shift $(($OPTIND -1)) | ||
62 | |||
63 | plots=0 | ||
64 | while [ "$1" ];do | ||
65 | if [ ! -f "$1" ];then | ||
66 | echo "File $1 does not exist" | ||
67 | usage | ||
68 | fi | ||
69 | file[$plots]="$1" | ||
70 | title[$plots]="$2" | ||
71 | # echo "File: ${file[$plots]} - ${title[plots]}" | ||
72 | shift;shift | ||
73 | plots=$((plots + 1)) | ||
74 | done | ||
75 | |||
76 | echo "set terminal $picture_type" >> $dir/plot_script.gpl | ||
77 | echo "set output \"$output_file\"" >> $dir/plot_script.gpl | ||
78 | echo "set title \"$global_title\"" >> $dir/plot_script.gpl | ||
79 | echo "set xlabel \"sleep/load time\"" >> $dir/plot_script.gpl | ||
80 | echo "set ylabel \"Performance (%)\"" >> $dir/plot_script.gpl | ||
81 | |||
82 | for((plot=0;plot<$plots;plot++));do | ||
83 | |||
84 | # Sanity check | ||
85 | ###### I am to dump to get this redirected to stderr/stdout in one awk call... ##### | ||
86 | cat ${file[$plot]} |grep -v "^#" |awk '{if ($2 != $3) printf("Error in measure %d:Load time %s does not equal sleep time %s, plot will not be correct\n", $1, $2, $3); ERR=1}' | ||
87 | ###### I am to dump to get this redirected in one awk call... ##### | ||
88 | |||
89 | # Parse out load time (which must be equal to sleep time for a plot), divide it by 1000 | ||
90 | # to get ms and parse out the performance in percentage and write it to a temp file for plotting | ||
91 | cat ${file[$plot]} |grep -v "^#" |awk '{printf "%lu %.1f\n",$2/1000, $6}' >$dir/data_$plot | ||
92 | |||
93 | if [ $plot -eq 0 ];then | ||
94 | echo -n "plot " >> $dir/plot_script.gpl | ||
95 | fi | ||
96 | echo -n "\"$dir/data_$plot\" title \"${title[$plot]}\" with lines" >> $dir/plot_script.gpl | ||
97 | if [ $(($plot + 1)) -ne $plots ];then | ||
98 | echo -n ", " >> $dir/plot_script.gpl | ||
99 | fi | ||
100 | done | ||
101 | echo >> $dir/plot_script.gpl | ||
102 | |||
103 | gnuplot $dir/plot_script.gpl | ||
104 | rm -r $dir \ No newline at end of file | ||
diff --git a/tools/power/cpupower/bench/cpufreq-bench_script.sh b/tools/power/cpupower/bench/cpufreq-bench_script.sh new file mode 100644 index 00000000000..de20d2a0687 --- /dev/null +++ b/tools/power/cpupower/bench/cpufreq-bench_script.sh | |||
@@ -0,0 +1,101 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # This program is free software: you can redistribute it and/or modify | ||
4 | # it under the terms of the GNU General Public License as published by | ||
5 | # the Free Software Foundation; either version 2, or (at your option) | ||
6 | # any later version. | ||
7 | |||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | |||
13 | # You should have received a copy of the GNU General Public License | ||
14 | # along with this program; if not, write to the Free Software | ||
15 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | ||
16 | # 02110-1301, USA. | ||
17 | |||
18 | # Author/Copyright(c): 2009, Thomas Renninger <trenn@suse.de>, Novell Inc. | ||
19 | |||
20 | # Ondemand up_threshold and sampling rate test script for cpufreq-bench | ||
21 | # mircobenchmark. | ||
22 | # Modify the general variables at the top or extend or copy out parts | ||
23 | # if you want to test other things | ||
24 | # | ||
25 | |||
26 | # Default with latest kernels is 95, before micro account patches | ||
27 | # it was 80, cmp. with git commit 808009131046b62ac434dbc796 | ||
28 | UP_THRESHOLD="60 80 95" | ||
29 | # Depending on the kernel and the HW sampling rate could be restricted | ||
30 | # and cannot be set that low... | ||
31 | # E.g. before git commit cef9615a853ebc4972084f7 one could only set | ||
32 | # min sampling rate of 80000 if CONFIG_HZ=250 | ||
33 | SAMPLING_RATE="20000 80000" | ||
34 | |||
35 | function measure() | ||
36 | { | ||
37 | local -i up_threshold_set | ||
38 | local -i sampling_rate_set | ||
39 | |||
40 | for up_threshold in $UP_THRESHOLD;do | ||
41 | for sampling_rate in $SAMPLING_RATE;do | ||
42 | # Set values in sysfs | ||
43 | echo $up_threshold >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold | ||
44 | echo $sampling_rate >/sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate | ||
45 | up_threshold_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/up_threshold) | ||
46 | sampling_rate_set=$(cat /sys/devices/system/cpu/cpu0/cpufreq/ondemand/sampling_rate) | ||
47 | |||
48 | # Verify set values in sysfs | ||
49 | if [ ${up_threshold_set} -eq ${up_threshold} ];then | ||
50 | echo "up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}" | ||
51 | else | ||
52 | echo "WARNING: Tried to set up_threshold: $up_threshold, set in sysfs: ${up_threshold_set}" | ||
53 | fi | ||
54 | if [ ${sampling_rate_set} -eq ${sampling_rate} ];then | ||
55 | echo "sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}" | ||
56 | else | ||
57 | echo "WARNING: Tried to set sampling_rate: $sampling_rate, set in sysfs: ${sampling_rate_set}" | ||
58 | fi | ||
59 | |||
60 | # Benchmark | ||
61 | cpufreq-bench -o /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate} | ||
62 | done | ||
63 | done | ||
64 | } | ||
65 | |||
66 | function create_plots() | ||
67 | { | ||
68 | local command | ||
69 | |||
70 | for up_threshold in $UP_THRESHOLD;do | ||
71 | command="cpufreq-bench_plot.sh -o \"sampling_rate_${SAMPLING_RATE}_up_threshold_${up_threshold}\" -t \"Ondemand sampling_rate: ${SAMPLING_RATE} comparison - Up_threshold: $up_threshold %\"" | ||
72 | for sampling_rate in $SAMPLING_RATE;do | ||
73 | command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"sampling_rate = $sampling_rate\"" | ||
74 | done | ||
75 | echo $command | ||
76 | eval "$command" | ||
77 | echo | ||
78 | done | ||
79 | |||
80 | for sampling_rate in $SAMPLING_RATE;do | ||
81 | command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${sampling_rate}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} % comparison - sampling_rate: $sampling_rate\"" | ||
82 | for up_threshold in $UP_THRESHOLD;do | ||
83 | command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold\"" | ||
84 | done | ||
85 | echo $command | ||
86 | eval "$command" | ||
87 | echo | ||
88 | done | ||
89 | |||
90 | command="cpufreq-bench_plot.sh -o \"up_threshold_${UP_THRESHOLD}_sampling_rate_${SAMPLING_RATE}\" -t \"Ondemand up_threshold: ${UP_THRESHOLD} and sampling_rate ${SAMPLING_RATE} comparison\"" | ||
91 | for sampling_rate in $SAMPLING_RATE;do | ||
92 | for up_threshold in $UP_THRESHOLD;do | ||
93 | command="${command} /var/log/cpufreq-bench/up_threshold_${up_threshold}_sampling_rate_${sampling_rate}/* \"up_threshold = $up_threshold - sampling_rate = $sampling_rate\"" | ||
94 | done | ||
95 | done | ||
96 | echo "$command" | ||
97 | eval "$command" | ||
98 | } | ||
99 | |||
100 | measure | ||
101 | create_plots \ No newline at end of file | ||
diff --git a/tools/power/cpupower/bench/example.cfg b/tools/power/cpupower/bench/example.cfg new file mode 100644 index 00000000000..f91f6436068 --- /dev/null +++ b/tools/power/cpupower/bench/example.cfg | |||
@@ -0,0 +1,11 @@ | |||
1 | sleep = 50000 | ||
2 | load = 50000 | ||
3 | cpu = 0 | ||
4 | priority = LOW | ||
5 | output = /var/log/cpufreq-bench | ||
6 | sleep_step = 50000 | ||
7 | load_step = 50000 | ||
8 | cycles = 20 | ||
9 | rounds = 40 | ||
10 | verbose = 0 | ||
11 | governor = ondemand | ||
diff --git a/tools/power/cpupower/bench/main.c b/tools/power/cpupower/bench/main.c new file mode 100644 index 00000000000..60953fc9343 --- /dev/null +++ b/tools/power/cpupower/bench/main.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <unistd.h> | ||
24 | #include <getopt.h> | ||
25 | #include <errno.h> | ||
26 | |||
27 | #include "config.h" | ||
28 | #include "system.h" | ||
29 | #include "benchmark.h" | ||
30 | |||
31 | static struct option long_options[] = | ||
32 | { | ||
33 | {"output", 1, 0, 'o'}, | ||
34 | {"sleep", 1, 0, 's'}, | ||
35 | {"load", 1, 0, 'l'}, | ||
36 | {"verbose", 0, 0, 'v'}, | ||
37 | {"cpu", 1, 0, 'c'}, | ||
38 | {"governor", 1, 0, 'g'}, | ||
39 | {"prio", 1, 0, 'p'}, | ||
40 | {"file", 1, 0, 'f'}, | ||
41 | {"cycles", 1, 0, 'n'}, | ||
42 | {"rounds", 1, 0, 'r'}, | ||
43 | {"load-step", 1, 0, 'x'}, | ||
44 | {"sleep-step", 1, 0, 'y'}, | ||
45 | {"help", 0, 0, 'h'}, | ||
46 | {0, 0, 0, 0} | ||
47 | }; | ||
48 | |||
49 | /******************************************************************* | ||
50 | usage | ||
51 | *******************************************************************/ | ||
52 | |||
53 | void usage() | ||
54 | { | ||
55 | printf("usage: ./bench\n"); | ||
56 | printf("Options:\n"); | ||
57 | printf(" -l, --load=<long int>\t\tinitial load time in us\n"); | ||
58 | printf(" -s, --sleep=<long int>\t\tinitial sleep time in us\n"); | ||
59 | printf(" -x, --load-step=<long int>\ttime to be added to load time, in us\n"); | ||
60 | printf(" -y, --sleep-step=<long int>\ttime to be added to sleep time, in us\n"); | ||
61 | printf(" -c, --cpu=<cpu #>\t\t\tCPU Nr. to use, starting at 0\n"); | ||
62 | printf(" -p, --prio=<priority>\t\t\tscheduler priority, HIGH, LOW or DEFAULT\n"); | ||
63 | printf(" -g, --governor=<governor>\t\tcpufreq governor to test\n"); | ||
64 | printf(" -n, --cycles=<int>\t\t\tload/sleep cycles\n"); | ||
65 | printf(" -r, --rounds<int>\t\t\tload/sleep rounds\n"); | ||
66 | printf(" -f, --file=<configfile>\t\tconfig file to use\n"); | ||
67 | printf(" -o, --output=<dir>\t\t\toutput path. Filename will be OUTPUTPATH/benchmark_TIMESTAMP.log\n"); | ||
68 | printf(" -v, --verbose\t\t\t\tverbose output on/off\n"); | ||
69 | printf(" -h, --help\t\t\t\tPrint this help screen\n"); | ||
70 | exit (1); | ||
71 | } | ||
72 | |||
73 | /******************************************************************* | ||
74 | main | ||
75 | *******************************************************************/ | ||
76 | |||
77 | int main(int argc, char **argv) | ||
78 | { | ||
79 | int c; | ||
80 | int option_index = 0; | ||
81 | struct config *config = NULL; | ||
82 | |||
83 | config = prepare_default_config(); | ||
84 | |||
85 | if (config == NULL) | ||
86 | return EXIT_FAILURE; | ||
87 | |||
88 | while (1) { | ||
89 | c = getopt_long (argc, argv, "hg:o:s:l:vc:p:f:n:r:x:y:", | ||
90 | long_options, &option_index); | ||
91 | if (c == -1) | ||
92 | break; | ||
93 | |||
94 | switch (c) { | ||
95 | case 'o': | ||
96 | if (config->output != NULL) | ||
97 | fclose(config->output); | ||
98 | |||
99 | config->output = prepare_output(optarg); | ||
100 | |||
101 | if (config->output == NULL) | ||
102 | return EXIT_FAILURE; | ||
103 | |||
104 | dprintf("user output path -> %s\n", optarg); | ||
105 | break; | ||
106 | case 's': | ||
107 | sscanf(optarg, "%li", &config->sleep); | ||
108 | dprintf("user sleep time -> %s\n", optarg); | ||
109 | break; | ||
110 | case 'l': | ||
111 | sscanf(optarg, "%li", &config->load); | ||
112 | dprintf("user load time -> %s\n", optarg); | ||
113 | break; | ||
114 | case 'c': | ||
115 | sscanf(optarg, "%u", &config->cpu); | ||
116 | dprintf("user cpu -> %s\n", optarg); | ||
117 | break; | ||
118 | case 'g': | ||
119 | strncpy(config->governor, optarg, 14); | ||
120 | dprintf("user governor -> %s\n", optarg); | ||
121 | break; | ||
122 | case 'p': | ||
123 | if (string_to_prio(optarg) != SCHED_ERR) { | ||
124 | config->prio = string_to_prio(optarg); | ||
125 | dprintf("user prio -> %s\n", optarg); | ||
126 | } else { | ||
127 | if (config != NULL) { | ||
128 | if (config->output != NULL) | ||
129 | fclose(config->output); | ||
130 | free(config); | ||
131 | } | ||
132 | usage(); | ||
133 | } | ||
134 | break; | ||
135 | case 'n': | ||
136 | sscanf(optarg, "%u", &config->cycles); | ||
137 | dprintf("user cycles -> %s\n", optarg); | ||
138 | break; | ||
139 | case 'r': | ||
140 | sscanf(optarg, "%u", &config->rounds); | ||
141 | dprintf("user rounds -> %s\n", optarg); | ||
142 | break; | ||
143 | case 'x': | ||
144 | sscanf(optarg, "%li", &config->load_step); | ||
145 | dprintf("user load_step -> %s\n", optarg); | ||
146 | break; | ||
147 | case 'y': | ||
148 | sscanf(optarg, "%li", &config->sleep_step); | ||
149 | dprintf("user sleep_step -> %s\n", optarg); | ||
150 | break; | ||
151 | case 'f': | ||
152 | if (prepare_config(optarg, config)) | ||
153 | return EXIT_FAILURE; | ||
154 | break; | ||
155 | case 'v': | ||
156 | config->verbose = 1; | ||
157 | dprintf("verbose output enabled\n"); | ||
158 | break; | ||
159 | case 'h': | ||
160 | case '?': | ||
161 | default: | ||
162 | if (config != NULL) { | ||
163 | if (config->output != NULL) | ||
164 | fclose(config->output); | ||
165 | free(config); | ||
166 | } | ||
167 | usage(); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if (config->verbose) { | ||
172 | printf("starting benchmark with parameters:\n"); | ||
173 | printf("config:\n\t" | ||
174 | "sleep=%li\n\t" | ||
175 | "load=%li\n\t" | ||
176 | "sleep_step=%li\n\t" | ||
177 | "load_step=%li\n\t" | ||
178 | "cpu=%u\n\t" | ||
179 | "cycles=%u\n\t" | ||
180 | "rounds=%u\n\t" | ||
181 | "governor=%s\n\n", | ||
182 | config->sleep, | ||
183 | config->load, | ||
184 | config->sleep_step, | ||
185 | config->load_step, | ||
186 | config->cpu, | ||
187 | config->cycles, | ||
188 | config->rounds, | ||
189 | config->governor); | ||
190 | } | ||
191 | |||
192 | prepare_user(config); | ||
193 | prepare_system(config); | ||
194 | start_benchmark(config); | ||
195 | |||
196 | if (config->output != stdout) | ||
197 | fclose(config->output); | ||
198 | |||
199 | free(config); | ||
200 | |||
201 | return EXIT_SUCCESS; | ||
202 | } | ||
203 | |||
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c new file mode 100644 index 00000000000..3b270ac92c4 --- /dev/null +++ b/tools/power/cpupower/bench/parse.c | |||
@@ -0,0 +1,224 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <stdarg.h> | ||
23 | #include <string.h> | ||
24 | #include <time.h> | ||
25 | #include <dirent.h> | ||
26 | |||
27 | #include <sys/utsname.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | |||
31 | #include "parse.h" | ||
32 | #include "config.h" | ||
33 | |||
34 | /** | ||
35 | * converts priority string to priority | ||
36 | * | ||
37 | * @param str string that represents a scheduler priority | ||
38 | * | ||
39 | * @retval priority | ||
40 | * @retval SCHED_ERR when the priority doesn't exit | ||
41 | **/ | ||
42 | |||
43 | enum sched_prio string_to_prio(const char *str) | ||
44 | { | ||
45 | if (strncasecmp("high", str, strlen(str)) == 0) | ||
46 | return SCHED_HIGH; | ||
47 | else if (strncasecmp("default", str, strlen(str)) == 0) | ||
48 | return SCHED_DEFAULT; | ||
49 | else if (strncasecmp("low", str, strlen(str)) == 0) | ||
50 | return SCHED_LOW; | ||
51 | else | ||
52 | return SCHED_ERR; | ||
53 | } | ||
54 | |||
55 | /** | ||
56 | * create and open logfile | ||
57 | * | ||
58 | * @param dir directory in which the logfile should be created | ||
59 | * | ||
60 | * @retval logfile on success | ||
61 | * @retval NULL when the file can't be created | ||
62 | **/ | ||
63 | |||
64 | FILE *prepare_output(const char *dirname) | ||
65 | { | ||
66 | FILE *output = NULL; | ||
67 | int len; | ||
68 | char *filename; | ||
69 | struct utsname sysdata; | ||
70 | DIR *dir; | ||
71 | |||
72 | dir = opendir(dirname); | ||
73 | if (dir == NULL) { | ||
74 | if (mkdir(dirname, 0755)) { | ||
75 | perror("mkdir"); | ||
76 | fprintf(stderr, "error: Cannot create dir %s\n", | ||
77 | dirname); | ||
78 | return NULL; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | len = strlen(dirname) + 30; | ||
83 | filename = malloc(sizeof(char) * len); | ||
84 | |||
85 | if (uname(&sysdata) == 0) { | ||
86 | len += strlen(sysdata.nodename) + strlen(sysdata.release); | ||
87 | filename = realloc(filename, sizeof(char) * len); | ||
88 | |||
89 | if(filename == NULL) { | ||
90 | perror("realloc"); | ||
91 | return NULL; | ||
92 | } | ||
93 | |||
94 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", | ||
95 | dirname, sysdata.nodename, sysdata.release, time(NULL)); | ||
96 | } else { | ||
97 | snprintf(filename, len -1, "%s/benchmark_%li.log", dirname, time(NULL)); | ||
98 | } | ||
99 | |||
100 | dprintf("logilename: %s\n", filename); | ||
101 | |||
102 | if ((output = fopen(filename, "w+")) == NULL) { | ||
103 | perror("fopen"); | ||
104 | fprintf(stderr, "error: unable to open logfile\n"); | ||
105 | } | ||
106 | |||
107 | fprintf(stdout, "Logfile: %s\n", filename); | ||
108 | |||
109 | free(filename); | ||
110 | fprintf(output, "#round load sleep performance powersave percentage\n"); | ||
111 | return output; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * returns the default config | ||
116 | * | ||
117 | * @retval default config on success | ||
118 | * @retval NULL when the output file can't be created | ||
119 | **/ | ||
120 | |||
121 | struct config *prepare_default_config() | ||
122 | { | ||
123 | struct config *config = malloc(sizeof(struct config)); | ||
124 | |||
125 | dprintf("loading defaults\n"); | ||
126 | |||
127 | config->sleep = 500000; | ||
128 | config->load = 500000; | ||
129 | config->sleep_step = 500000; | ||
130 | config->load_step = 500000; | ||
131 | config->cycles = 5; | ||
132 | config->rounds = 50; | ||
133 | config->cpu = 0; | ||
134 | config->prio = SCHED_HIGH; | ||
135 | config->verbose = 0; | ||
136 | strncpy(config->governor, "ondemand", 8); | ||
137 | |||
138 | config->output = stdout; | ||
139 | |||
140 | #ifdef DEFAULT_CONFIG_FILE | ||
141 | if (prepare_config(DEFAULT_CONFIG_FILE, config)) | ||
142 | return NULL; | ||
143 | #endif | ||
144 | return config; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * parses config file and returns the config to the caller | ||
149 | * | ||
150 | * @param path config file name | ||
151 | * | ||
152 | * @retval 1 on error | ||
153 | * @retval 0 on success | ||
154 | **/ | ||
155 | |||
156 | int prepare_config(const char *path, struct config *config) | ||
157 | { | ||
158 | size_t len = 0; | ||
159 | char *opt, *val, *line = NULL; | ||
160 | FILE *configfile = fopen(path, "r"); | ||
161 | |||
162 | if (config == NULL) { | ||
163 | fprintf(stderr, "error: config is NULL\n"); | ||
164 | return 1; | ||
165 | } | ||
166 | |||
167 | if (configfile == NULL) { | ||
168 | perror("fopen"); | ||
169 | fprintf(stderr, "error: unable to read configfile\n"); | ||
170 | free(config); | ||
171 | return 1; | ||
172 | } | ||
173 | |||
174 | while (getline(&line, &len, configfile) != -1) | ||
175 | { | ||
176 | if (line[0] == '#' || line[0] == ' ') | ||
177 | continue; | ||
178 | |||
179 | sscanf(line, "%as = %as", &opt, &val); | ||
180 | |||
181 | dprintf("parsing: %s -> %s\n", opt, val); | ||
182 | |||
183 | if (strncmp("sleep", opt, strlen(opt)) == 0) | ||
184 | sscanf(val, "%li", &config->sleep); | ||
185 | |||
186 | else if (strncmp("load", opt, strlen(opt)) == 0) | ||
187 | sscanf(val, "%li", &config->load); | ||
188 | |||
189 | else if (strncmp("load_step", opt, strlen(opt)) == 0) | ||
190 | sscanf(val, "%li", &config->load_step); | ||
191 | |||
192 | else if (strncmp("sleep_step", opt, strlen(opt)) == 0) | ||
193 | sscanf(val, "%li", &config->sleep_step); | ||
194 | |||
195 | else if (strncmp("cycles", opt, strlen(opt)) == 0) | ||
196 | sscanf(val, "%u", &config->cycles); | ||
197 | |||
198 | else if (strncmp("rounds", opt, strlen(opt)) == 0) | ||
199 | sscanf(val, "%u", &config->rounds); | ||
200 | |||
201 | else if (strncmp("verbose", opt, strlen(opt)) == 0) | ||
202 | sscanf(val, "%u", &config->verbose); | ||
203 | |||
204 | else if (strncmp("output", opt, strlen(opt)) == 0) | ||
205 | config->output = prepare_output(val); | ||
206 | |||
207 | else if (strncmp("cpu", opt, strlen(opt)) == 0) | ||
208 | sscanf(val, "%u", &config->cpu); | ||
209 | |||
210 | else if (strncmp("governor", opt, 14) == 0) | ||
211 | strncpy(config->governor, val, 14); | ||
212 | |||
213 | else if (strncmp("priority", opt, strlen(opt)) == 0) { | ||
214 | if (string_to_prio(val) != SCHED_ERR) | ||
215 | config->prio = string_to_prio(val); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | free(line); | ||
220 | free(opt); | ||
221 | free(val); | ||
222 | |||
223 | return 0; | ||
224 | } | ||
diff --git a/tools/power/cpupower/bench/parse.h b/tools/power/cpupower/bench/parse.h new file mode 100644 index 00000000000..9fcdfa23dd9 --- /dev/null +++ b/tools/power/cpupower/bench/parse.h | |||
@@ -0,0 +1,50 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | /* struct that holds the required config parameters */ | ||
21 | struct config | ||
22 | { | ||
23 | long sleep; /* sleep time in µs */ | ||
24 | long load; /* load time in µs */ | ||
25 | long sleep_step; /* time value which changes the | ||
26 | * sleep time after every round in µs */ | ||
27 | long load_step; /* time value which changes the | ||
28 | * load time after every round in µs */ | ||
29 | unsigned int cycles; /* calculation cycles with the same sleep/load time */ | ||
30 | unsigned int rounds; /* calculation rounds with iterated sleep/load time */ | ||
31 | unsigned int cpu; /* cpu for which the affinity is set */ | ||
32 | char governor[15]; /* cpufreq governor */ | ||
33 | enum sched_prio /* possible scheduler priorities */ | ||
34 | { | ||
35 | SCHED_ERR=-1,SCHED_HIGH, SCHED_DEFAULT, SCHED_LOW | ||
36 | } prio; | ||
37 | |||
38 | unsigned int verbose; /* verbose output */ | ||
39 | FILE *output; /* logfile */ | ||
40 | char *output_filename; /* logfile name, must be freed at the end | ||
41 | if output != NULL and output != stdout*/ | ||
42 | }; | ||
43 | |||
44 | enum sched_prio string_to_prio(const char *str); | ||
45 | |||
46 | FILE *prepare_output(const char *dir); | ||
47 | |||
48 | int prepare_config(const char *path, struct config *config); | ||
49 | struct config *prepare_default_config(); | ||
50 | |||
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c new file mode 100644 index 00000000000..3e3a82e8bdd --- /dev/null +++ b/tools/power/cpupower/bench/system.c | |||
@@ -0,0 +1,188 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <time.h> | ||
22 | #include <sys/time.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <unistd.h> | ||
25 | |||
26 | #include <sched.h> | ||
27 | |||
28 | #include <cpufreq.h> | ||
29 | |||
30 | #include "config.h" | ||
31 | #include "system.h" | ||
32 | |||
33 | /** | ||
34 | * returns time since epoch in µs | ||
35 | * | ||
36 | * @retval time | ||
37 | **/ | ||
38 | |||
39 | long long int get_time() | ||
40 | { | ||
41 | struct timeval now; | ||
42 | |||
43 | gettimeofday(&now, NULL); | ||
44 | |||
45 | return (long long int)(now.tv_sec * 1000000LL + now.tv_usec); | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * sets the cpufreq governor | ||
50 | * | ||
51 | * @param governor cpufreq governor name | ||
52 | * @param cpu cpu for which the governor should be set | ||
53 | * | ||
54 | * @retval 0 on success | ||
55 | * @retval -1 when failed | ||
56 | **/ | ||
57 | |||
58 | int set_cpufreq_governor(char *governor, unsigned int cpu) | ||
59 | { | ||
60 | |||
61 | dprintf("set %s as cpufreq governor\n", governor); | ||
62 | |||
63 | if (cpufreq_cpu_exists(cpu) != 0) { | ||
64 | perror("cpufreq_cpu_exists"); | ||
65 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); | ||
66 | return -1; | ||
67 | } | ||
68 | |||
69 | if (cpufreq_modify_policy_governor(cpu, governor) != 0) { | ||
70 | perror("cpufreq_modify_policy_governor"); | ||
71 | fprintf(stderr, "error: unable to set %s governor\n", governor); | ||
72 | return -1; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * sets cpu affinity for the process | ||
80 | * | ||
81 | * @param cpu cpu# to which the affinity should be set | ||
82 | * | ||
83 | * @retval 0 on success | ||
84 | * @retval -1 when setting the affinity failed | ||
85 | **/ | ||
86 | |||
87 | int set_cpu_affinity(unsigned int cpu) | ||
88 | { | ||
89 | cpu_set_t cpuset; | ||
90 | |||
91 | CPU_ZERO(&cpuset); | ||
92 | CPU_SET(cpu, &cpuset); | ||
93 | |||
94 | dprintf("set affinity to cpu #%u\n", cpu); | ||
95 | |||
96 | if (sched_setaffinity(getpid(), sizeof(cpu_set_t), &cpuset) < 0) { | ||
97 | perror("sched_setaffinity"); | ||
98 | fprintf(stderr, "warning: unable to set cpu affinity\n"); | ||
99 | return -1; | ||
100 | } | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * sets the process priority parameter | ||
107 | * | ||
108 | * @param priority priority value | ||
109 | * | ||
110 | * @retval 0 on success | ||
111 | * @retval -1 when setting the priority failed | ||
112 | **/ | ||
113 | |||
114 | int set_process_priority(int priority) | ||
115 | { | ||
116 | struct sched_param param; | ||
117 | |||
118 | dprintf("set scheduler priority to %i\n", priority); | ||
119 | |||
120 | param.sched_priority = priority; | ||
121 | |||
122 | if (sched_setscheduler(0, SCHEDULER, ¶m) < 0) { | ||
123 | perror("sched_setscheduler"); | ||
124 | fprintf(stderr, "warning: unable to set scheduler priority\n"); | ||
125 | return -1; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /** | ||
132 | * notifys the user that the benchmark may run some time | ||
133 | * | ||
134 | * @param config benchmark config values | ||
135 | * | ||
136 | **/ | ||
137 | |||
138 | void prepare_user(const struct config *config) | ||
139 | { | ||
140 | unsigned long sleep_time = 0; | ||
141 | unsigned long load_time = 0; | ||
142 | unsigned int round; | ||
143 | |||
144 | for (round = 0; round < config->rounds; round++) { | ||
145 | sleep_time += 2 * config->cycles * (config->sleep + config->sleep_step * round); | ||
146 | load_time += 2 * config->cycles * (config->load + config->load_step * round) + (config->load + config->load_step * round * 4); | ||
147 | } | ||
148 | |||
149 | if (config->verbose || config->output != stdout) | ||
150 | printf("approx. test duration: %im\n", | ||
151 | (int)((sleep_time + load_time) / 60000000)); | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * sets up the cpu affinity and scheduler priority | ||
156 | * | ||
157 | * @param config benchmark config values | ||
158 | * | ||
159 | **/ | ||
160 | |||
161 | void prepare_system(const struct config *config) | ||
162 | { | ||
163 | if (config->verbose) | ||
164 | printf("set cpu affinity to cpu #%u\n", config->cpu); | ||
165 | |||
166 | set_cpu_affinity(config->cpu); | ||
167 | |||
168 | switch (config->prio) { | ||
169 | case SCHED_HIGH: | ||
170 | if (config->verbose) | ||
171 | printf("high priority condition requested\n"); | ||
172 | |||
173 | set_process_priority(PRIORITY_HIGH); | ||
174 | break; | ||
175 | case SCHED_LOW: | ||
176 | if (config->verbose) | ||
177 | printf("low priority condition requested\n"); | ||
178 | |||
179 | set_process_priority(PRIORITY_LOW); | ||
180 | break; | ||
181 | default: | ||
182 | if (config->verbose) | ||
183 | printf("default priority condition requested\n"); | ||
184 | |||
185 | set_process_priority(PRIORITY_DEFAULT); | ||
186 | } | ||
187 | } | ||
188 | |||
diff --git a/tools/power/cpupower/bench/system.h b/tools/power/cpupower/bench/system.h new file mode 100644 index 00000000000..3a8c858b78f --- /dev/null +++ b/tools/power/cpupower/bench/system.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* cpufreq-bench CPUFreq microbenchmark | ||
2 | * | ||
3 | * Copyright (C) 2008 Christian Kornacker <ckornacker@suse.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include "parse.h" | ||
21 | |||
22 | long long get_time(); | ||
23 | |||
24 | int set_cpufreq_governor(char *governor, unsigned int cpu); | ||
25 | int set_cpu_affinity(unsigned int cpu); | ||
26 | int set_process_priority(int priority); | ||
27 | |||
28 | void prepare_user(const struct config *config); | ||
29 | void prepare_system(const struct config *config); | ||