Commit 2dfc818b35cbea59188cc86e86e0a0efce2b0dbe
Committed by
Dominik Brodowski
1 parent
75f25bd31d
Exists in
master
and in
4 other branches
cpupower: mperf monitor - Use TSC to calculate max frequency if possible
Which makes the implementation independent from cpufreq drivers. Therefore this would also work on a Xen kernel where the hypervisor is doing frequency switching and idle entering. Signed-off-by: Thomas Renninger <trenn@suse.de> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Showing 2 changed files with 131 additions and 48 deletions Inline Diff
tools/power/cpupower/Makefile
1 | # Makefile for cpupower | 1 | # Makefile for cpupower |
2 | # | 2 | # |
3 | # Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net> | 3 | # Copyright (C) 2005,2006 Dominik Brodowski <linux@dominikbrodowski.net> |
4 | # | 4 | # |
5 | # Based largely on the Makefile for udev by: | 5 | # Based largely on the Makefile for udev by: |
6 | # | 6 | # |
7 | # Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com> | 7 | # Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com> |
8 | # | 8 | # |
9 | # This program is free software; you can redistribute it and/or modify | 9 | # This program is free software; you can redistribute it and/or modify |
10 | # it under the terms of the GNU General Public License as published by | 10 | # it under the terms of the GNU General Public License as published by |
11 | # the Free Software Foundation; version 2 of the License. | 11 | # the Free Software Foundation; version 2 of the License. |
12 | # | 12 | # |
13 | # This program is distributed in the hope that it will be useful, | 13 | # This program is distributed in the hope that it will be useful, |
14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | # General Public License for more details. | 16 | # General Public License for more details. |
17 | # | 17 | # |
18 | # You should have received a copy of the GNU General Public License | 18 | # You should have received a copy of the GNU General Public License |
19 | # along with this program; if not, write to the Free Software | 19 | # along with this program; if not, write to the Free Software |
20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | # | 21 | # |
22 | 22 | ||
23 | # --- CONFIGURATION BEGIN --- | 23 | # --- CONFIGURATION BEGIN --- |
24 | 24 | ||
25 | # Set the following to `true' to make a unstripped, unoptimized | 25 | # Set the following to `true' to make a unstripped, unoptimized |
26 | # binary. Leave this set to `false' for production use. | 26 | # binary. Leave this set to `false' for production use. |
27 | DEBUG ?= false | 27 | DEBUG ?= true |
28 | 28 | ||
29 | # make the build silent. Set this to something else to make it noisy again. | 29 | # make the build silent. Set this to something else to make it noisy again. |
30 | V ?= false | 30 | V ?= false |
31 | 31 | ||
32 | # Internationalization support (output in different languages). | 32 | # Internationalization support (output in different languages). |
33 | # Requires gettext. | 33 | # Requires gettext. |
34 | NLS ?= true | 34 | NLS ?= true |
35 | 35 | ||
36 | # Set the following to 'true' to build/install the | 36 | # Set the following to 'true' to build/install the |
37 | # cpufreq-bench benchmarking tool | 37 | # cpufreq-bench benchmarking tool |
38 | CPUFRQ_BENCH ?= true | 38 | CPUFRQ_BENCH ?= true |
39 | 39 | ||
40 | # Prefix to the directories we're installing to | 40 | # Prefix to the directories we're installing to |
41 | DESTDIR ?= | 41 | DESTDIR ?= |
42 | 42 | ||
43 | # --- CONFIGURATION END --- | 43 | # --- CONFIGURATION END --- |
44 | 44 | ||
45 | 45 | ||
46 | 46 | ||
47 | # Package-related definitions. Distributions can modify the version | 47 | # Package-related definitions. Distributions can modify the version |
48 | # and _should_ modify the PACKAGE_BUGREPORT definition | 48 | # and _should_ modify the PACKAGE_BUGREPORT definition |
49 | 49 | ||
50 | VERSION= $(shell ./utils/version-gen.sh) | 50 | VERSION= $(shell ./utils/version-gen.sh) |
51 | LIB_MAJ= 0.0.0 | 51 | LIB_MAJ= 0.0.0 |
52 | LIB_MIN= 0 | 52 | LIB_MIN= 0 |
53 | 53 | ||
54 | PACKAGE = cpupower | 54 | PACKAGE = cpupower |
55 | PACKAGE_BUGREPORT = cpufreq@vger.kernel.org | 55 | PACKAGE_BUGREPORT = cpufreq@vger.kernel.org |
56 | LANGUAGES = de fr it cs pt | 56 | LANGUAGES = de fr it cs pt |
57 | 57 | ||
58 | 58 | ||
59 | # Directory definitions. These are default and most probably | 59 | # Directory definitions. These are default and most probably |
60 | # do not need to be changed. Please note that DESTDIR is | 60 | # do not need to be changed. Please note that DESTDIR is |
61 | # added in front of any of them | 61 | # added in front of any of them |
62 | 62 | ||
63 | bindir ?= /usr/bin | 63 | bindir ?= /usr/bin |
64 | sbindir ?= /usr/sbin | 64 | sbindir ?= /usr/sbin |
65 | mandir ?= /usr/man | 65 | mandir ?= /usr/man |
66 | includedir ?= /usr/include | 66 | includedir ?= /usr/include |
67 | libdir ?= /usr/lib | 67 | libdir ?= /usr/lib |
68 | localedir ?= /usr/share/locale | 68 | localedir ?= /usr/share/locale |
69 | docdir ?= /usr/share/doc/packages/cpupower | 69 | docdir ?= /usr/share/doc/packages/cpupower |
70 | confdir ?= /etc/ | 70 | confdir ?= /etc/ |
71 | 71 | ||
72 | # Toolchain: what tools do we use, and what options do they need: | 72 | # Toolchain: what tools do we use, and what options do they need: |
73 | 73 | ||
74 | CP = cp -fpR | 74 | CP = cp -fpR |
75 | INSTALL = /usr/bin/install -c | 75 | INSTALL = /usr/bin/install -c |
76 | INSTALL_PROGRAM = ${INSTALL} | 76 | INSTALL_PROGRAM = ${INSTALL} |
77 | INSTALL_DATA = ${INSTALL} -m 644 | 77 | INSTALL_DATA = ${INSTALL} -m 644 |
78 | INSTALL_SCRIPT = ${INSTALL_PROGRAM} | 78 | INSTALL_SCRIPT = ${INSTALL_PROGRAM} |
79 | 79 | ||
80 | # If you are running a cross compiler, you may want to set this | 80 | # If you are running a cross compiler, you may want to set this |
81 | # to something more interesting, like "arm-linux-". If you want | 81 | # to something more interesting, like "arm-linux-". If you want |
82 | # to compile vs uClibc, that can be done here as well. | 82 | # to compile vs uClibc, that can be done here as well. |
83 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- | 83 | CROSS = #/usr/i386-linux-uclibc/usr/bin/i386-uclibc- |
84 | CC = $(CROSS)gcc | 84 | CC = $(CROSS)gcc |
85 | LD = $(CROSS)gcc | 85 | LD = $(CROSS)gcc |
86 | AR = $(CROSS)ar | 86 | AR = $(CROSS)ar |
87 | STRIP = $(CROSS)strip | 87 | STRIP = $(CROSS)strip |
88 | RANLIB = $(CROSS)ranlib | 88 | RANLIB = $(CROSS)ranlib |
89 | HOSTCC = gcc | 89 | HOSTCC = gcc |
90 | 90 | ||
91 | 91 | ||
92 | # Now we set up the build system | 92 | # Now we set up the build system |
93 | # | 93 | # |
94 | 94 | ||
95 | # set up PWD so that older versions of make will work with our build. | 95 | # set up PWD so that older versions of make will work with our build. |
96 | PWD = $(shell pwd) | 96 | PWD = $(shell pwd) |
97 | 97 | ||
98 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;} | 98 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;} |
99 | 99 | ||
100 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS | 100 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS |
101 | 101 | ||
102 | # check if compiler option is supported | 102 | # check if compiler option is supported |
103 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} | 103 | cc-supports = ${shell if $(CC) ${1} -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; fi;} |
104 | 104 | ||
105 | # use '-Os' optimization if available, else use -O2 | 105 | # use '-Os' optimization if available, else use -O2 |
106 | OPTIMIZATION := $(call cc-supports,-Os,-O2) | 106 | OPTIMIZATION := $(call cc-supports,-Os,-O2) |
107 | 107 | ||
108 | WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare | 108 | WARNINGS := -Wall -Wchar-subscripts -Wpointer-arith -Wsign-compare |
109 | WARNINGS += $(call cc-supports,-Wno-pointer-sign) | 109 | WARNINGS += $(call cc-supports,-Wno-pointer-sign) |
110 | WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) | 110 | WARNINGS += $(call cc-supports,-Wdeclaration-after-statement) |
111 | WARNINGS += -Wshadow | 111 | WARNINGS += -Wshadow |
112 | 112 | ||
113 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ | 113 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ |
114 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE | 114 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE |
115 | 115 | ||
116 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ | 116 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ |
117 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ | 117 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ |
118 | utils/helpers/pci.o utils/helpers/bitmask.o \ | 118 | utils/helpers/pci.o utils/helpers/bitmask.o \ |
119 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ | 119 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ |
120 | utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ | 120 | utils/idle_monitor/amd_fam14h_idle.o utils/idle_monitor/cpuidle_sysfs.o \ |
121 | utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ | 121 | utils/idle_monitor/mperf_monitor.o utils/idle_monitor/cpupower-monitor.o \ |
122 | utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ | 122 | utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ |
123 | utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o | 123 | utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o |
124 | 124 | ||
125 | UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ | 125 | UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ |
126 | utils/helpers/bitmask.h \ | 126 | utils/helpers/bitmask.h \ |
127 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def | 127 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def |
128 | 128 | ||
129 | UTIL_SRC := $(UTIL_OBJS:.o=.c) | 129 | UTIL_SRC := $(UTIL_OBJS:.o=.c) |
130 | 130 | ||
131 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h | 131 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h |
132 | LIB_SRC = lib/cpufreq.c lib/sysfs.c | 132 | LIB_SRC = lib/cpufreq.c lib/sysfs.c |
133 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o | 133 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o |
134 | 134 | ||
135 | CFLAGS += -pipe | 135 | CFLAGS += -pipe |
136 | 136 | ||
137 | ifeq ($(strip $(NLS)),true) | 137 | ifeq ($(strip $(NLS)),true) |
138 | INSTALL_NLS += install-gmo | 138 | INSTALL_NLS += install-gmo |
139 | COMPILE_NLS += create-gmo | 139 | COMPILE_NLS += create-gmo |
140 | endif | 140 | endif |
141 | 141 | ||
142 | ifeq ($(strip $(CPUFRQ_BENCH)),true) | 142 | ifeq ($(strip $(CPUFRQ_BENCH)),true) |
143 | INSTALL_BENCH += install-bench | 143 | INSTALL_BENCH += install-bench |
144 | COMPILE_BENCH += compile-bench | 144 | COMPILE_BENCH += compile-bench |
145 | endif | 145 | endif |
146 | 146 | ||
147 | CFLAGS += $(WARNINGS) | 147 | CFLAGS += $(WARNINGS) |
148 | 148 | ||
149 | ifeq ($(strip $(V)),false) | 149 | ifeq ($(strip $(V)),false) |
150 | QUIET=@ | 150 | QUIET=@ |
151 | ECHO=@echo | 151 | ECHO=@echo |
152 | else | 152 | else |
153 | QUIET= | 153 | QUIET= |
154 | ECHO=@\# | 154 | ECHO=@\# |
155 | endif | 155 | endif |
156 | export QUIET ECHO | 156 | export QUIET ECHO |
157 | 157 | ||
158 | # if DEBUG is enabled, then we do not strip or optimize | 158 | # if DEBUG is enabled, then we do not strip or optimize |
159 | ifeq ($(strip $(DEBUG)),true) | 159 | ifeq ($(strip $(DEBUG)),true) |
160 | CFLAGS += -O1 -g -DDEBUG | 160 | CFLAGS += -O1 -g -DDEBUG |
161 | STRIPCMD = /bin/true -Since_we_are_debugging | 161 | STRIPCMD = /bin/true -Since_we_are_debugging |
162 | else | 162 | else |
163 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer | 163 | CFLAGS += $(OPTIMIZATION) -fomit-frame-pointer |
164 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment | 164 | STRIPCMD = $(STRIP) -s --remove-section=.note --remove-section=.comment |
165 | endif | 165 | endif |
166 | 166 | ||
167 | 167 | ||
168 | # the actual make rules | 168 | # the actual make rules |
169 | 169 | ||
170 | all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH) | 170 | all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH) |
171 | 171 | ||
172 | lib/%.o: $(LIB_SRC) $(LIB_HEADERS) | 172 | lib/%.o: $(LIB_SRC) $(LIB_HEADERS) |
173 | $(ECHO) " CC " $@ | 173 | $(ECHO) " CC " $@ |
174 | $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c | 174 | $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c |
175 | 175 | ||
176 | libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) | 176 | libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) |
177 | $(ECHO) " LD " $@ | 177 | $(ECHO) " LD " $@ |
178 | $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ | 178 | $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ |
179 | -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) | 179 | -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) |
180 | @ln -sf $@ libcpupower.so | 180 | @ln -sf $@ libcpupower.so |
181 | @ln -sf $@ libcpupower.so.$(LIB_MIN) | 181 | @ln -sf $@ libcpupower.so.$(LIB_MIN) |
182 | 182 | ||
183 | libcpupower: libcpupower.so.$(LIB_MAJ) | 183 | libcpupower: libcpupower.so.$(LIB_MAJ) |
184 | 184 | ||
185 | # Let all .o files depend on its .c file and all headers | 185 | # Let all .o files depend on its .c file and all headers |
186 | # Might be worth to put this into utils/Makefile at some point of time | 186 | # Might be worth to put this into utils/Makefile at some point of time |
187 | $(UTIL_OBJS): $(UTIL_HEADERS) | 187 | $(UTIL_OBJS): $(UTIL_HEADERS) |
188 | 188 | ||
189 | .c.o: | 189 | .c.o: |
190 | $(ECHO) " CC " $@ | 190 | $(ECHO) " CC " $@ |
191 | $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c | 191 | $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c |
192 | 192 | ||
193 | cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ) | 193 | cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ) |
194 | $(ECHO) " CC " $@ | 194 | $(ECHO) " CC " $@ |
195 | $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS) | 195 | $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS) |
196 | $(QUIET) $(STRIPCMD) $@ | 196 | $(QUIET) $(STRIPCMD) $@ |
197 | 197 | ||
198 | po/$(PACKAGE).pot: $(UTIL_SRC) | 198 | po/$(PACKAGE).pot: $(UTIL_SRC) |
199 | $(ECHO) " GETTEXT " $@ | 199 | $(ECHO) " GETTEXT " $@ |
200 | $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ | 200 | $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ |
201 | --keyword=_ --keyword=N_ $(UTIL_SRC) && \ | 201 | --keyword=_ --keyword=N_ $(UTIL_SRC) && \ |
202 | test -f $(PACKAGE).po && \ | 202 | test -f $(PACKAGE).po && \ |
203 | mv -f $(PACKAGE).po po/$(PACKAGE).pot | 203 | mv -f $(PACKAGE).po po/$(PACKAGE).pot |
204 | 204 | ||
205 | po/%.gmo: po/%.po | 205 | po/%.gmo: po/%.po |
206 | $(ECHO) " MSGFMT " $@ | 206 | $(ECHO) " MSGFMT " $@ |
207 | $(QUIET) msgfmt -o $@ po/$*.po | 207 | $(QUIET) msgfmt -o $@ po/$*.po |
208 | 208 | ||
209 | create-gmo: ${GMO_FILES} | 209 | create-gmo: ${GMO_FILES} |
210 | 210 | ||
211 | update-po: po/$(PACKAGE).pot | 211 | update-po: po/$(PACKAGE).pot |
212 | $(ECHO) " MSGMRG " $@ | 212 | $(ECHO) " MSGMRG " $@ |
213 | $(QUIET) @for HLANG in $(LANGUAGES); do \ | 213 | $(QUIET) @for HLANG in $(LANGUAGES); do \ |
214 | echo -n "Updating $$HLANG "; \ | 214 | echo -n "Updating $$HLANG "; \ |
215 | if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \ | 215 | if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \ |
216 | po/$$HLANG.new.po; then \ | 216 | po/$$HLANG.new.po; then \ |
217 | mv -f po/$$HLANG.new.po po/$$HLANG.po; \ | 217 | mv -f po/$$HLANG.new.po po/$$HLANG.po; \ |
218 | else \ | 218 | else \ |
219 | echo "msgmerge for $$HLANG failed!"; \ | 219 | echo "msgmerge for $$HLANG failed!"; \ |
220 | rm -f po/$$HLANG.new.po; \ | 220 | rm -f po/$$HLANG.new.po; \ |
221 | fi; \ | 221 | fi; \ |
222 | done; | 222 | done; |
223 | 223 | ||
224 | compile-bench: libcpupower.so.$(LIB_MAJ) | 224 | compile-bench: libcpupower.so.$(LIB_MAJ) |
225 | @V=$(V) confdir=$(confdir) $(MAKE) -C bench | 225 | @V=$(V) confdir=$(confdir) $(MAKE) -C bench |
226 | 226 | ||
227 | clean: | 227 | clean: |
228 | -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | 228 | -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ |
229 | | xargs rm -f | 229 | | xargs rm -f |
230 | -rm -f $(UTIL_BINS) | 230 | -rm -f $(UTIL_BINS) |
231 | -rm -f $(IDLE_OBJS) | 231 | -rm -f $(IDLE_OBJS) |
232 | -rm -f cpupower | 232 | -rm -f cpupower |
233 | -rm -f libcpupower.so* | 233 | -rm -f libcpupower.so* |
234 | -rm -rf po/*.gmo po/*.pot | 234 | -rm -rf po/*.gmo po/*.pot |
235 | $(MAKE) -C bench clean | 235 | $(MAKE) -C bench clean |
236 | 236 | ||
237 | 237 | ||
238 | install-lib: | 238 | install-lib: |
239 | $(INSTALL) -d $(DESTDIR)${libdir} | 239 | $(INSTALL) -d $(DESTDIR)${libdir} |
240 | $(CP) libcpupower.so* $(DESTDIR)${libdir}/ | 240 | $(CP) libcpupower.so* $(DESTDIR)${libdir}/ |
241 | $(INSTALL) -d $(DESTDIR)${includedir} | 241 | $(INSTALL) -d $(DESTDIR)${includedir} |
242 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h | 242 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h |
243 | 243 | ||
244 | install-tools: | 244 | install-tools: |
245 | $(INSTALL) -d $(DESTDIR)${bindir} | 245 | $(INSTALL) -d $(DESTDIR)${bindir} |
246 | $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir} | 246 | $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir} |
247 | 247 | ||
248 | install-man: | 248 | install-man: |
249 | $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 | 249 | $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 |
250 | $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 | 250 | $(INSTALL_DATA) -D man/cpupower-frequency-set.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 |
251 | $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1 | 251 | $(INSTALL_DATA) -D man/cpupower-frequency-info.1 $(DESTDIR)${mandir}/man1/cpupower-frequency-info.1 |
252 | $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 | 252 | $(INSTALL_DATA) -D man/cpupower-set.1 $(DESTDIR)${mandir}/man1/cpupower-set.1 |
253 | $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1 | 253 | $(INSTALL_DATA) -D man/cpupower-info.1 $(DESTDIR)${mandir}/man1/cpupower-info.1 |
254 | $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1 | 254 | $(INSTALL_DATA) -D man/cpupower-monitor.1 $(DESTDIR)${mandir}/man1/cpupower-monitor.1 |
255 | 255 | ||
256 | install-gmo: | 256 | install-gmo: |
257 | $(INSTALL) -d $(DESTDIR)${localedir} | 257 | $(INSTALL) -d $(DESTDIR)${localedir} |
258 | for HLANG in $(LANGUAGES); do \ | 258 | for HLANG in $(LANGUAGES); do \ |
259 | echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ | 259 | echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ |
260 | $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ | 260 | $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ |
261 | done; | 261 | done; |
262 | 262 | ||
263 | install-bench: | 263 | install-bench: |
264 | @#DESTDIR must be set from outside to survive | 264 | @#DESTDIR must be set from outside to survive |
265 | @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install | 265 | @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install |
266 | 266 | ||
267 | install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) | 267 | install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) |
268 | 268 | ||
269 | uninstall: | 269 | uninstall: |
270 | - rm -f $(DESTDIR)${libdir}/libcpupower.* | 270 | - rm -f $(DESTDIR)${libdir}/libcpupower.* |
271 | - rm -f $(DESTDIR)${includedir}/cpufreq.h | 271 | - rm -f $(DESTDIR)${includedir}/cpufreq.h |
272 | - rm -f $(DESTDIR)${bindir}/utils/cpupower | 272 | - rm -f $(DESTDIR)${bindir}/utils/cpupower |
273 | - rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1 | 273 | - rm -f $(DESTDIR)${mandir}/man1/cpufreq-set.1 |
274 | - rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1 | 274 | - rm -f $(DESTDIR)${mandir}/man1/cpufreq-info.1 |
275 | - for HLANG in $(LANGUAGES); do \ | 275 | - for HLANG in $(LANGUAGES); do \ |
276 | rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ | 276 | rm -f $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ |
277 | done; | 277 | done; |
278 | 278 | ||
279 | .PHONY: all utils libcpupower update-po create-gmo install-lib install-tools install-man install-gmo install uninstall clean | 279 | .PHONY: all utils libcpupower update-po create-gmo install-lib install-tools install-man install-gmo install uninstall clean |
280 | 280 |
tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
1 | /* | 1 | /* |
2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. | 2 | * (C) 2010,2011 Thomas Renninger <trenn@suse.de>, Novell Inc. |
3 | * | 3 | * |
4 | * Licensed under the terms of the GNU GPL License version 2. | 4 | * Licensed under the terms of the GNU GPL License version 2. |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #if defined(__i386__) || defined(__x86_64__) | 7 | #if defined(__i386__) || defined(__x86_64__) |
8 | 8 | ||
9 | #include <stdio.h> | 9 | #include <stdio.h> |
10 | #include <stdint.h> | 10 | #include <stdint.h> |
11 | #include <stdlib.h> | 11 | #include <stdlib.h> |
12 | #include <string.h> | 12 | #include <string.h> |
13 | #include <limits.h> | 13 | #include <limits.h> |
14 | 14 | ||
15 | #include <cpufreq.h> | 15 | #include <cpufreq.h> |
16 | 16 | ||
17 | #include "helpers/helpers.h" | 17 | #include "helpers/helpers.h" |
18 | #include "idle_monitor/cpupower-monitor.h" | 18 | #include "idle_monitor/cpupower-monitor.h" |
19 | 19 | ||
20 | #define MSR_APERF 0xE8 | 20 | #define MSR_APERF 0xE8 |
21 | #define MSR_MPERF 0xE7 | 21 | #define MSR_MPERF 0xE7 |
22 | 22 | ||
23 | #define MSR_TSC 0x10 | 23 | #define MSR_TSC 0x10 |
24 | 24 | ||
25 | #define MSR_AMD_HWCR 0xc0010015 | ||
26 | |||
25 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; | 27 | enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT }; |
26 | 28 | ||
27 | static int mperf_get_count_percent(unsigned int self_id, double *percent, | 29 | static int mperf_get_count_percent(unsigned int self_id, double *percent, |
28 | unsigned int cpu); | 30 | unsigned int cpu); |
29 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | 31 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
30 | unsigned int cpu); | 32 | unsigned int cpu); |
33 | static struct timespec time_start, time_end; | ||
31 | 34 | ||
32 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { | 35 | static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = { |
33 | { | 36 | { |
34 | .name = "C0", | 37 | .name = "C0", |
35 | .desc = N_("Processor Core not idle"), | 38 | .desc = N_("Processor Core not idle"), |
36 | .id = C0, | 39 | .id = C0, |
37 | .range = RANGE_THREAD, | 40 | .range = RANGE_THREAD, |
38 | .get_count_percent = mperf_get_count_percent, | 41 | .get_count_percent = mperf_get_count_percent, |
39 | }, | 42 | }, |
40 | { | 43 | { |
41 | .name = "Cx", | 44 | .name = "Cx", |
42 | .desc = N_("Processor Core in an idle state"), | 45 | .desc = N_("Processor Core in an idle state"), |
43 | .id = Cx, | 46 | .id = Cx, |
44 | .range = RANGE_THREAD, | 47 | .range = RANGE_THREAD, |
45 | .get_count_percent = mperf_get_count_percent, | 48 | .get_count_percent = mperf_get_count_percent, |
46 | }, | 49 | }, |
47 | 50 | ||
48 | { | 51 | { |
49 | .name = "Freq", | 52 | .name = "Freq", |
50 | .desc = N_("Average Frequency (including boost) in MHz"), | 53 | .desc = N_("Average Frequency (including boost) in MHz"), |
51 | .id = AVG_FREQ, | 54 | .id = AVG_FREQ, |
52 | .range = RANGE_THREAD, | 55 | .range = RANGE_THREAD, |
53 | .get_count = mperf_get_count_freq, | 56 | .get_count = mperf_get_count_freq, |
54 | }, | 57 | }, |
55 | }; | 58 | }; |
56 | 59 | ||
60 | enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF }; | ||
61 | static int max_freq_mode; | ||
62 | /* | ||
63 | * The max frequency mperf is ticking at (in C0), either retrieved via: | ||
64 | * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency | ||
65 | * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time | ||
66 | * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen) | ||
67 | */ | ||
68 | static unsigned long max_frequency; | ||
69 | |||
57 | static unsigned long long tsc_at_measure_start; | 70 | static unsigned long long tsc_at_measure_start; |
58 | static unsigned long long tsc_at_measure_end; | 71 | static unsigned long long tsc_at_measure_end; |
59 | static unsigned long max_frequency; | ||
60 | static unsigned long long *mperf_previous_count; | 72 | static unsigned long long *mperf_previous_count; |
61 | static unsigned long long *aperf_previous_count; | 73 | static unsigned long long *aperf_previous_count; |
62 | static unsigned long long *mperf_current_count; | 74 | static unsigned long long *mperf_current_count; |
63 | static unsigned long long *aperf_current_count; | 75 | static unsigned long long *aperf_current_count; |
76 | |||
64 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ | 77 | /* valid flag for all CPUs. If a MSR read failed it will be zero */ |
65 | static int *is_valid; | 78 | static int *is_valid; |
66 | 79 | ||
67 | static int mperf_get_tsc(unsigned long long *tsc) | 80 | static int mperf_get_tsc(unsigned long long *tsc) |
68 | { | 81 | { |
69 | return read_msr(0, MSR_TSC, tsc); | 82 | int ret; |
83 | ret = read_msr(0, MSR_TSC, tsc); | ||
84 | if (ret) | ||
85 | dprint("Reading TSC MSR failed, returning %llu\n", *tsc); | ||
86 | return ret; | ||
70 | } | 87 | } |
71 | 88 | ||
72 | static int mperf_init_stats(unsigned int cpu) | 89 | static int mperf_init_stats(unsigned int cpu) |
73 | { | 90 | { |
74 | unsigned long long val; | 91 | unsigned long long val; |
75 | int ret; | 92 | int ret; |
76 | 93 | ||
77 | ret = read_msr(cpu, MSR_APERF, &val); | 94 | ret = read_msr(cpu, MSR_APERF, &val); |
78 | aperf_previous_count[cpu] = val; | 95 | aperf_previous_count[cpu] = val; |
79 | ret |= read_msr(cpu, MSR_MPERF, &val); | 96 | ret |= read_msr(cpu, MSR_MPERF, &val); |
80 | mperf_previous_count[cpu] = val; | 97 | mperf_previous_count[cpu] = val; |
81 | is_valid[cpu] = !ret; | 98 | is_valid[cpu] = !ret; |
82 | 99 | ||
83 | return 0; | 100 | return 0; |
84 | } | 101 | } |
85 | 102 | ||
86 | static int mperf_measure_stats(unsigned int cpu) | 103 | static int mperf_measure_stats(unsigned int cpu) |
87 | { | 104 | { |
88 | unsigned long long val; | 105 | unsigned long long val; |
89 | int ret; | 106 | int ret; |
90 | 107 | ||
91 | ret = read_msr(cpu, MSR_APERF, &val); | 108 | ret = read_msr(cpu, MSR_APERF, &val); |
92 | aperf_current_count[cpu] = val; | 109 | aperf_current_count[cpu] = val; |
93 | ret |= read_msr(cpu, MSR_MPERF, &val); | 110 | ret |= read_msr(cpu, MSR_MPERF, &val); |
94 | mperf_current_count[cpu] = val; | 111 | mperf_current_count[cpu] = val; |
95 | is_valid[cpu] = !ret; | 112 | is_valid[cpu] = !ret; |
96 | 113 | ||
97 | return 0; | 114 | return 0; |
98 | } | 115 | } |
99 | 116 | ||
100 | /* | ||
101 | * get_average_perf() | ||
102 | * | ||
103 | * Returns the average performance (also considers boosted frequencies) | ||
104 | * | ||
105 | * Input: | ||
106 | * aperf_diff: Difference of the aperf register over a time period | ||
107 | * mperf_diff: Difference of the mperf register over the same time period | ||
108 | * max_freq: Maximum frequency (P0) | ||
109 | * | ||
110 | * Returns: | ||
111 | * Average performance over the time period | ||
112 | */ | ||
113 | static unsigned long get_average_perf(unsigned long long aperf_diff, | ||
114 | unsigned long long mperf_diff) | ||
115 | { | ||
116 | unsigned int perf_percent = 0; | ||
117 | if (((unsigned long)(-1) / 100) < aperf_diff) { | ||
118 | int shift_count = 7; | ||
119 | aperf_diff >>= shift_count; | ||
120 | mperf_diff >>= shift_count; | ||
121 | } | ||
122 | perf_percent = (aperf_diff * 100) / mperf_diff; | ||
123 | return (max_frequency * perf_percent) / 100; | ||
124 | } | ||
125 | |||
126 | static int mperf_get_count_percent(unsigned int id, double *percent, | 117 | static int mperf_get_count_percent(unsigned int id, double *percent, |
127 | unsigned int cpu) | 118 | unsigned int cpu) |
128 | { | 119 | { |
129 | unsigned long long aperf_diff, mperf_diff, tsc_diff; | 120 | unsigned long long aperf_diff, mperf_diff, tsc_diff; |
121 | unsigned long long timediff; | ||
130 | 122 | ||
131 | if (!is_valid[cpu]) | 123 | if (!is_valid[cpu]) |
132 | return -1; | 124 | return -1; |
133 | 125 | ||
134 | if (id != C0 && id != Cx) | 126 | if (id != C0 && id != Cx) |
135 | return -1; | 127 | return -1; |
136 | 128 | ||
137 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | 129 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
138 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | 130 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; |
139 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; | ||
140 | 131 | ||
141 | *percent = 100.0 * mperf_diff / tsc_diff; | 132 | if (max_freq_mode == MAX_FREQ_TSC_REF) { |
142 | dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n", | 133 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; |
143 | mperf_cstates[id].name, mperf_diff, tsc_diff); | 134 | *percent = 100.0 * mperf_diff / tsc_diff; |
135 | dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n", | ||
136 | mperf_cstates[id].name, mperf_diff, tsc_diff); | ||
137 | } else if (max_freq_mode == MAX_FREQ_SYSFS) { | ||
138 | timediff = timespec_diff_us(time_start, time_end); | ||
139 | *percent = 100.0 * mperf_diff / timediff; | ||
140 | dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n", | ||
141 | mperf_cstates[id].name, mperf_diff, timediff); | ||
142 | } else | ||
143 | return -1; | ||
144 | 144 | ||
145 | if (id == Cx) | 145 | if (id == Cx) |
146 | *percent = 100.0 - *percent; | 146 | *percent = 100.0 - *percent; |
147 | 147 | ||
148 | dprint("%s: previous: %llu - current: %llu - (%u)\n", | 148 | dprint("%s: previous: %llu - current: %llu - (%u)\n", |
149 | mperf_cstates[id].name, mperf_diff, aperf_diff, cpu); | 149 | mperf_cstates[id].name, mperf_diff, aperf_diff, cpu); |
150 | dprint("%s: %f\n", mperf_cstates[id].name, *percent); | 150 | dprint("%s: %f\n", mperf_cstates[id].name, *percent); |
151 | return 0; | 151 | return 0; |
152 | } | 152 | } |
153 | 153 | ||
154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, | 154 | static int mperf_get_count_freq(unsigned int id, unsigned long long *count, |
155 | unsigned int cpu) | 155 | unsigned int cpu) |
156 | { | 156 | { |
157 | unsigned long long aperf_diff, mperf_diff; | 157 | unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff; |
158 | 158 | ||
159 | if (id != AVG_FREQ) | 159 | if (id != AVG_FREQ) |
160 | return 1; | 160 | return 1; |
161 | 161 | ||
162 | if (!is_valid[cpu]) | 162 | if (!is_valid[cpu]) |
163 | return -1; | 163 | return -1; |
164 | 164 | ||
165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; | 165 | mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu]; |
166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; | 166 | aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu]; |
167 | 167 | ||
168 | /* Return MHz for now, might want to return KHz if column width is more | 168 | if (max_freq_mode == MAX_FREQ_TSC_REF) { |
169 | generic */ | 169 | /* Calculate max_freq from TSC count */ |
170 | *count = get_average_perf(aperf_diff, mperf_diff) / 1000; | 170 | tsc_diff = tsc_at_measure_end - tsc_at_measure_start; |
171 | dprint("%s: %llu\n", mperf_cstates[id].name, *count); | 171 | time_diff = timespec_diff_us(time_start, time_end); |
172 | max_frequency = tsc_diff / time_diff; | ||
173 | } | ||
172 | 174 | ||
175 | *count = max_frequency * ((double)aperf_diff / mperf_diff); | ||
176 | dprint("%s: Average freq based on %s maximum frequency:\n", | ||
177 | mperf_cstates[id].name, | ||
178 | (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read"); | ||
179 | dprint("%max_frequency: %lu", max_frequency); | ||
180 | dprint("aperf_diff: %llu\n", aperf_diff); | ||
181 | dprint("mperf_diff: %llu\n", mperf_diff); | ||
182 | dprint("avg freq: %llu\n", *count); | ||
173 | return 0; | 183 | return 0; |
174 | } | 184 | } |
175 | 185 | ||
176 | static int mperf_start(void) | 186 | static int mperf_start(void) |
177 | { | 187 | { |
178 | int cpu; | 188 | int cpu; |
179 | unsigned long long dbg; | 189 | unsigned long long dbg; |
180 | 190 | ||
191 | clock_gettime(CLOCK_REALTIME, &time_start); | ||
181 | mperf_get_tsc(&tsc_at_measure_start); | 192 | mperf_get_tsc(&tsc_at_measure_start); |
182 | 193 | ||
183 | for (cpu = 0; cpu < cpu_count; cpu++) | 194 | for (cpu = 0; cpu < cpu_count; cpu++) |
184 | mperf_init_stats(cpu); | 195 | mperf_init_stats(cpu); |
185 | 196 | ||
186 | mperf_get_tsc(&dbg); | 197 | mperf_get_tsc(&dbg); |
187 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); | 198 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_start); |
188 | return 0; | 199 | return 0; |
189 | } | 200 | } |
190 | 201 | ||
191 | static int mperf_stop(void) | 202 | static int mperf_stop(void) |
192 | { | 203 | { |
193 | unsigned long long dbg; | 204 | unsigned long long dbg; |
194 | int cpu; | 205 | int cpu; |
195 | 206 | ||
196 | mperf_get_tsc(&tsc_at_measure_end); | ||
197 | |||
198 | for (cpu = 0; cpu < cpu_count; cpu++) | 207 | for (cpu = 0; cpu < cpu_count; cpu++) |
199 | mperf_measure_stats(cpu); | 208 | mperf_measure_stats(cpu); |
200 | 209 | ||
210 | mperf_get_tsc(&tsc_at_measure_end); | ||
211 | clock_gettime(CLOCK_REALTIME, &time_end); | ||
212 | |||
201 | mperf_get_tsc(&dbg); | 213 | mperf_get_tsc(&dbg); |
202 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); | 214 | dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end); |
203 | 215 | ||
204 | return 0; | 216 | return 0; |
205 | } | 217 | } |
206 | 218 | ||
207 | struct cpuidle_monitor mperf_monitor; | 219 | /* |
208 | 220 | * Mperf register is defined to tick at P0 (maximum) frequency | |
209 | struct cpuidle_monitor *mperf_register(void) | 221 | * |
222 | * Instead of reading out P0 which can be tricky to read out from HW, | ||
223 | * we use TSC counter if it reliably ticks at P0/mperf frequency. | ||
224 | * | ||
225 | * Still try to fall back to: | ||
226 | * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq | ||
227 | * on older Intel HW without invariant TSC feature. | ||
228 | * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but | ||
229 | * it's still double checked (MSR_AMD_HWCR)). | ||
230 | * | ||
231 | * On these machines the user would still get useful mperf | ||
232 | * stats when acpi-cpufreq driver is loaded. | ||
233 | */ | ||
234 | static int init_maxfreq_mode(void) | ||
210 | { | 235 | { |
236 | int ret; | ||
237 | unsigned long long hwcr; | ||
211 | unsigned long min; | 238 | unsigned long min; |
212 | 239 | ||
213 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | 240 | if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC) |
214 | return NULL; | 241 | goto use_sysfs; |
215 | 242 | ||
216 | /* Assume min/max all the same on all cores */ | 243 | if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) { |
244 | /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf | ||
245 | * freq. | ||
246 | * A test whether hwcr is accessable/available would be: | ||
247 | * (cpupower_cpu_info.family > 0x10 || | ||
248 | * cpupower_cpu_info.family == 0x10 && | ||
249 | * cpupower_cpu_info.model >= 0x2)) | ||
250 | * This should be the case for all aperf/mperf | ||
251 | * capable AMD machines and is therefore safe to test here. | ||
252 | * Compare with Linus kernel git commit: acf01734b1747b1ec4 | ||
253 | */ | ||
254 | ret = read_msr(0, MSR_AMD_HWCR, &hwcr); | ||
255 | /* | ||
256 | * If the MSR read failed, assume a Xen system that did | ||
257 | * not explicitly provide access to it and assume TSC works | ||
258 | */ | ||
259 | if (ret != 0) { | ||
260 | dprint("TSC read 0x%x failed - assume TSC working\n", | ||
261 | MSR_AMD_HWCR); | ||
262 | return 0; | ||
263 | } else if (1 & (hwcr >> 24)) { | ||
264 | max_freq_mode = MAX_FREQ_TSC_REF; | ||
265 | return 0; | ||
266 | } else { /* Use sysfs max frequency if available */ } | ||
267 | } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) { | ||
268 | /* | ||
269 | * On Intel we assume mperf (in C0) is ticking at same | ||
270 | * rate than TSC | ||
271 | */ | ||
272 | max_freq_mode = MAX_FREQ_TSC_REF; | ||
273 | return 0; | ||
274 | } | ||
275 | use_sysfs: | ||
217 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { | 276 | if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) { |
218 | dprint("Cannot retrieve max freq from cpufreq kernel " | 277 | dprint("Cannot retrieve max freq from cpufreq kernel " |
219 | "subsystem\n"); | 278 | "subsystem\n"); |
220 | return NULL; | 279 | return -1; |
221 | } | 280 | } |
281 | max_freq_mode = MAX_FREQ_SYSFS; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * This monitor provides: | ||
287 | * | ||
288 | * 1) Average frequency a CPU resided in | ||
289 | * This always works if the CPU has aperf/mperf capabilities | ||
290 | * | ||
291 | * 2) C0 and Cx (any sleep state) time a CPU resided in | ||
292 | * Works if mperf timer stops ticking in sleep states which | ||
293 | * seem to be the case on all current HW. | ||
294 | * Both is directly retrieved from HW registers and is independent | ||
295 | * from kernel statistics. | ||
296 | */ | ||
297 | struct cpuidle_monitor mperf_monitor; | ||
298 | struct cpuidle_monitor *mperf_register(void) | ||
299 | { | ||
300 | if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF)) | ||
301 | return NULL; | ||
302 | |||
303 | if (init_maxfreq_mode()) | ||
304 | return NULL; | ||
222 | 305 | ||
223 | /* Free this at program termination */ | 306 | /* Free this at program termination */ |
224 | is_valid = calloc(cpu_count, sizeof(int)); | 307 | is_valid = calloc(cpu_count, sizeof(int)); |
225 | mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); | 308 | mperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); |
226 | aperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); | 309 | aperf_previous_count = calloc(cpu_count, sizeof(unsigned long long)); |