Commit 2dfc818b35cbea59188cc86e86e0a0efce2b0dbe

Authored by Thomas Renninger
Committed by Dominik Brodowski
1 parent 75f25bd31d

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));