diff options
author | Ingo Molnar <mingo@kernel.org> | 2012-04-13 03:57:10 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-04-13 03:57:10 -0400 |
commit | a385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (patch) | |
tree | a2c186cb828e3713c2ec48a4d7191166fb798b3d /tools | |
parent | 659c36fcda403013a01b85da07cf2d9711e6d6c7 (diff) | |
parent | 0034102808e0dbbf3a2394b82b1bb40b5778de9e (diff) |
Merge tag 'v3.4-rc2' into perf/core
Merge Linux 3.4-rc2: we were on v3.3, update the base.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
29 files changed, 1972 insertions, 241 deletions
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index e8a03aceceb1..a93e06cfcc2a 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -19,6 +19,16 @@ | |||
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 | OUTPUT=./ | ||
23 | ifeq ("$(origin O)", "command line") | ||
24 | OUTPUT := $(O)/ | ||
25 | endif | ||
26 | |||
27 | ifneq ($(OUTPUT),) | ||
28 | # check that the output directory actually exists | ||
29 | OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) | ||
30 | $(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) | ||
31 | endif | ||
22 | 32 | ||
23 | # --- CONFIGURATION BEGIN --- | 33 | # --- CONFIGURATION BEGIN --- |
24 | 34 | ||
@@ -87,6 +97,7 @@ AR = $(CROSS)ar | |||
87 | STRIP = $(CROSS)strip | 97 | STRIP = $(CROSS)strip |
88 | RANLIB = $(CROSS)ranlib | 98 | RANLIB = $(CROSS)ranlib |
89 | HOSTCC = gcc | 99 | HOSTCC = gcc |
100 | MKDIR = mkdir | ||
90 | 101 | ||
91 | 102 | ||
92 | # Now we set up the build system | 103 | # Now we set up the build system |
@@ -95,7 +106,7 @@ HOSTCC = gcc | |||
95 | # set up PWD so that older versions of make will work with our build. | 106 | # set up PWD so that older versions of make will work with our build. |
96 | PWD = $(shell pwd) | 107 | PWD = $(shell pwd) |
97 | 108 | ||
98 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo po/$$HLANG.gmo; done;} | 109 | GMO_FILES = ${shell for HLANG in ${LANGUAGES}; do echo $(OUTPUT)po/$$HLANG.gmo; done;} |
99 | 110 | ||
100 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS | 111 | export CROSS CC AR STRIP RANLIB CFLAGS LDFLAGS LIB_OBJS |
101 | 112 | ||
@@ -122,15 +133,18 @@ UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ | |||
122 | utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ | 133 | utils/cpupower.o utils/cpufreq-info.o utils/cpufreq-set.o \ |
123 | utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o | 134 | utils/cpupower-set.o utils/cpupower-info.o utils/cpuidle-info.o |
124 | 135 | ||
136 | UTIL_SRC := $(UTIL_OBJS:.o=.c) | ||
137 | |||
138 | UTIL_OBJS := $(addprefix $(OUTPUT),$(UTIL_OBJS)) | ||
139 | |||
125 | UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ | 140 | UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ |
126 | utils/helpers/bitmask.h \ | 141 | utils/helpers/bitmask.h \ |
127 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def | 142 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def |
128 | 143 | ||
129 | UTIL_SRC := $(UTIL_OBJS:.o=.c) | ||
130 | |||
131 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h | 144 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h |
132 | LIB_SRC = lib/cpufreq.c lib/sysfs.c | 145 | LIB_SRC = lib/cpufreq.c lib/sysfs.c |
133 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o | 146 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o |
147 | LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) | ||
134 | 148 | ||
135 | CFLAGS += -pipe | 149 | CFLAGS += -pipe |
136 | 150 | ||
@@ -168,83 +182,90 @@ endif | |||
168 | 182 | ||
169 | # the actual make rules | 183 | # the actual make rules |
170 | 184 | ||
171 | all: libcpupower cpupower $(COMPILE_NLS) $(COMPILE_BENCH) | 185 | all: libcpupower $(OUTPUT)cpupower $(COMPILE_NLS) $(COMPILE_BENCH) |
172 | 186 | ||
173 | lib/%.o: $(LIB_SRC) $(LIB_HEADERS) | 187 | $(OUTPUT)lib/%.o: $(LIB_SRC) $(LIB_HEADERS) |
174 | $(ECHO) " CC " $@ | 188 | $(ECHO) " CC " $@ |
175 | $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c | 189 | $(QUIET) $(CC) $(CFLAGS) -fPIC -o $@ -c lib/$*.c |
176 | 190 | ||
177 | libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) | 191 | $(OUTPUT)libcpupower.so.$(LIB_MAJ): $(LIB_OBJS) |
178 | $(ECHO) " LD " $@ | 192 | $(ECHO) " LD " $@ |
179 | $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ | 193 | $(QUIET) $(CC) -shared $(CFLAGS) $(LDFLAGS) -o $@ \ |
180 | -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) | 194 | -Wl,-soname,libcpupower.so.$(LIB_MIN) $(LIB_OBJS) |
181 | @ln -sf $@ libcpupower.so | 195 | @ln -sf $(@F) $(OUTPUT)libcpupower.so |
182 | @ln -sf $@ libcpupower.so.$(LIB_MIN) | 196 | @ln -sf $(@F) $(OUTPUT)libcpupower.so.$(LIB_MIN) |
183 | 197 | ||
184 | libcpupower: libcpupower.so.$(LIB_MAJ) | 198 | libcpupower: $(OUTPUT)libcpupower.so.$(LIB_MAJ) |
185 | 199 | ||
186 | # Let all .o files depend on its .c file and all headers | 200 | # Let all .o files depend on its .c file and all headers |
187 | # Might be worth to put this into utils/Makefile at some point of time | 201 | # Might be worth to put this into utils/Makefile at some point of time |
188 | $(UTIL_OBJS): $(UTIL_HEADERS) | 202 | $(UTIL_OBJS): $(UTIL_HEADERS) |
189 | 203 | ||
190 | .c.o: | 204 | $(OUTPUT)%.o: %.c |
191 | $(ECHO) " CC " $@ | 205 | $(ECHO) " CC " $@ |
192 | $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c | 206 | $(QUIET) $(CC) $(CFLAGS) -I./lib -I ./utils -o $@ -c $*.c |
193 | 207 | ||
194 | cpupower: $(UTIL_OBJS) libcpupower.so.$(LIB_MAJ) | 208 | $(OUTPUT)cpupower: $(UTIL_OBJS) $(OUTPUT)libcpupower.so.$(LIB_MAJ) |
195 | $(ECHO) " CC " $@ | 209 | $(ECHO) " CC " $@ |
196 | $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) -lcpupower -lrt -lpci -L. -o $@ $(UTIL_OBJS) | 210 | $(QUIET) $(CC) $(CFLAGS) $(LDFLAGS) $(UTIL_OBJS) -lcpupower -lrt -lpci -L$(OUTPUT) -o $@ |
197 | $(QUIET) $(STRIPCMD) $@ | 211 | $(QUIET) $(STRIPCMD) $@ |
198 | 212 | ||
199 | po/$(PACKAGE).pot: $(UTIL_SRC) | 213 | $(OUTPUT)po/$(PACKAGE).pot: $(UTIL_SRC) |
200 | $(ECHO) " GETTEXT " $@ | 214 | $(ECHO) " GETTEXT " $@ |
201 | $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ | 215 | $(QUIET) xgettext --default-domain=$(PACKAGE) --add-comments \ |
202 | --keyword=_ --keyword=N_ $(UTIL_SRC) && \ | 216 | --keyword=_ --keyword=N_ $(UTIL_SRC) -p $(@D) -o $(@F) |
203 | test -f $(PACKAGE).po && \ | ||
204 | mv -f $(PACKAGE).po po/$(PACKAGE).pot | ||
205 | 217 | ||
206 | po/%.gmo: po/%.po | 218 | $(OUTPUT)po/%.gmo: po/%.po |
207 | $(ECHO) " MSGFMT " $@ | 219 | $(ECHO) " MSGFMT " $@ |
208 | $(QUIET) msgfmt -o $@ po/$*.po | 220 | $(QUIET) msgfmt -o $@ po/$*.po |
209 | 221 | ||
210 | create-gmo: ${GMO_FILES} | 222 | create-gmo: ${GMO_FILES} |
211 | 223 | ||
212 | update-po: po/$(PACKAGE).pot | 224 | update-po: $(OUTPUT)po/$(PACKAGE).pot |
213 | $(ECHO) " MSGMRG " $@ | 225 | $(ECHO) " MSGMRG " $@ |
214 | $(QUIET) @for HLANG in $(LANGUAGES); do \ | 226 | $(QUIET) @for HLANG in $(LANGUAGES); do \ |
215 | echo -n "Updating $$HLANG "; \ | 227 | echo -n "Updating $$HLANG "; \ |
216 | if msgmerge po/$$HLANG.po po/$(PACKAGE).pot -o \ | 228 | if msgmerge po/$$HLANG.po $< -o \ |
217 | po/$$HLANG.new.po; then \ | 229 | $(OUTPUT)po/$$HLANG.new.po; then \ |
218 | mv -f po/$$HLANG.new.po po/$$HLANG.po; \ | 230 | mv -f $(OUTPUT)po/$$HLANG.new.po $(OUTPUT)po/$$HLANG.po; \ |
219 | else \ | 231 | else \ |
220 | echo "msgmerge for $$HLANG failed!"; \ | 232 | echo "msgmerge for $$HLANG failed!"; \ |
221 | rm -f po/$$HLANG.new.po; \ | 233 | rm -f $(OUTPUT)po/$$HLANG.new.po; \ |
222 | fi; \ | 234 | fi; \ |
223 | done; | 235 | done; |
224 | 236 | ||
225 | compile-bench: libcpupower.so.$(LIB_MAJ) | 237 | compile-bench: $(OUTPUT)libcpupower.so.$(LIB_MAJ) |
226 | @V=$(V) confdir=$(confdir) $(MAKE) -C bench | 238 | @V=$(V) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) |
239 | |||
240 | # we compile into subdirectories. if the target directory is not the | ||
241 | # source directory, they might not exists. So we depend the various | ||
242 | # files onto their directories. | ||
243 | DIRECTORY_DEPS = $(LIB_OBJS) $(UTIL_OBJS) $(GMO_FILES) | ||
244 | $(DIRECTORY_DEPS): | $(sort $(dir $(DIRECTORY_DEPS))) | ||
245 | |||
246 | # In the second step, we make a rule to actually create these directories | ||
247 | $(sort $(dir $(DIRECTORY_DEPS))): | ||
248 | $(ECHO) " MKDIR " $@ | ||
249 | $(QUIET) $(MKDIR) -p $@ 2>/dev/null | ||
227 | 250 | ||
228 | clean: | 251 | clean: |
229 | -find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ | 252 | -find $(OUTPUT) \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \ |
230 | | xargs rm -f | 253 | | xargs rm -f |
231 | -rm -f $(UTIL_BINS) | 254 | -rm -f $(OUTPUT)cpupower |
232 | -rm -f $(IDLE_OBJS) | 255 | -rm -f $(OUTPUT)libcpupower.so* |
233 | -rm -f cpupower | 256 | -rm -rf $(OUTPUT)po/*.{gmo,pot} |
234 | -rm -f libcpupower.so* | 257 | $(MAKE) -C bench O=$(OUTPUT) clean |
235 | -rm -rf po/*.gmo po/*.pot | ||
236 | $(MAKE) -C bench clean | ||
237 | 258 | ||
238 | 259 | ||
239 | install-lib: | 260 | install-lib: |
240 | $(INSTALL) -d $(DESTDIR)${libdir} | 261 | $(INSTALL) -d $(DESTDIR)${libdir} |
241 | $(CP) libcpupower.so* $(DESTDIR)${libdir}/ | 262 | $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ |
242 | $(INSTALL) -d $(DESTDIR)${includedir} | 263 | $(INSTALL) -d $(DESTDIR)${includedir} |
243 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h | 264 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h |
244 | 265 | ||
245 | install-tools: | 266 | install-tools: |
246 | $(INSTALL) -d $(DESTDIR)${bindir} | 267 | $(INSTALL) -d $(DESTDIR)${bindir} |
247 | $(INSTALL_PROGRAM) cpupower $(DESTDIR)${bindir} | 268 | $(INSTALL_PROGRAM) $(OUTPUT)cpupower $(DESTDIR)${bindir} |
248 | 269 | ||
249 | install-man: | 270 | install-man: |
250 | $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 | 271 | $(INSTALL_DATA) -D man/cpupower.1 $(DESTDIR)${mandir}/man1/cpupower.1 |
@@ -257,13 +278,13 @@ install-man: | |||
257 | install-gmo: | 278 | install-gmo: |
258 | $(INSTALL) -d $(DESTDIR)${localedir} | 279 | $(INSTALL) -d $(DESTDIR)${localedir} |
259 | for HLANG in $(LANGUAGES); do \ | 280 | for HLANG in $(LANGUAGES); do \ |
260 | echo '$(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ | 281 | echo '$(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo'; \ |
261 | $(INSTALL_DATA) -D po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ | 282 | $(INSTALL_DATA) -D $(OUTPUT)po/$$HLANG.gmo $(DESTDIR)${localedir}/$$HLANG/LC_MESSAGES/cpupower.mo; \ |
262 | done; | 283 | done; |
263 | 284 | ||
264 | install-bench: | 285 | install-bench: |
265 | @#DESTDIR must be set from outside to survive | 286 | @#DESTDIR must be set from outside to survive |
266 | @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench install | 287 | @sbindir=$(sbindir) bindir=$(bindir) docdir=$(docdir) confdir=$(confdir) $(MAKE) -C bench O=$(OUTPUT) install |
267 | 288 | ||
268 | install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) | 289 | install: all install-lib install-tools install-man $(INSTALL_NLS) $(INSTALL_BENCH) |
269 | 290 | ||
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile index 2b67606fc3e3..7ec7021a29cd 100644 --- a/tools/power/cpupower/bench/Makefile +++ b/tools/power/cpupower/bench/Makefile | |||
@@ -1,29 +1,36 @@ | |||
1 | LIBS = -L../ -lm -lcpupower | 1 | OUTPUT := ./ |
2 | ifeq ("$(origin O)", "command line") | ||
3 | ifneq ($(O),) | ||
4 | OUTPUT := $(O)/ | ||
5 | endif | ||
6 | endif | ||
2 | 7 | ||
3 | OBJS = main.o parse.o system.o benchmark.o | 8 | LIBS = -L../ -L$(OUTPUT) -lm -lcpupower |
9 | |||
10 | OBJS = $(OUTPUT)main.o $(OUTPUT)parse.o $(OUTPUT)system.o $(OUTPUT)benchmark.o | ||
4 | CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" | 11 | CFLAGS += -D_GNU_SOURCE -I../lib -DDEFAULT_CONFIG_FILE=\"$(confdir)/cpufreq-bench.conf\" |
5 | 12 | ||
6 | %.o : %.c | 13 | $(OUTPUT)%.o : %.c |
7 | $(ECHO) " CC " $@ | 14 | $(ECHO) " CC " $@ |
8 | $(QUIET) $(CC) -c $(CFLAGS) $< -o $@ | 15 | $(QUIET) $(CC) -c $(CFLAGS) $< -o $@ |
9 | 16 | ||
10 | cpufreq-bench: $(OBJS) | 17 | $(OUTPUT)cpufreq-bench: $(OBJS) |
11 | $(ECHO) " CC " $@ | 18 | $(ECHO) " CC " $@ |
12 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) | 19 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) |
13 | 20 | ||
14 | all: cpufreq-bench | 21 | all: $(OUTPUT)cpufreq-bench |
15 | 22 | ||
16 | install: | 23 | install: |
17 | mkdir -p $(DESTDIR)/$(sbindir) | 24 | mkdir -p $(DESTDIR)/$(sbindir) |
18 | mkdir -p $(DESTDIR)/$(bindir) | 25 | mkdir -p $(DESTDIR)/$(bindir) |
19 | mkdir -p $(DESTDIR)/$(docdir) | 26 | mkdir -p $(DESTDIR)/$(docdir) |
20 | mkdir -p $(DESTDIR)/$(confdir) | 27 | mkdir -p $(DESTDIR)/$(confdir) |
21 | install -m 755 cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench | 28 | install -m 755 $(OUTPUT)cpufreq-bench $(DESTDIR)/$(sbindir)/cpufreq-bench |
22 | install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh | 29 | install -m 755 cpufreq-bench_plot.sh $(DESTDIR)/$(bindir)/cpufreq-bench_plot.sh |
23 | install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH | 30 | install -m 644 README-BENCH $(DESTDIR)/$(docdir)/README-BENCH |
24 | install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh | 31 | install -m 755 cpufreq-bench_script.sh $(DESTDIR)/$(docdir)/cpufreq-bench_script.sh |
25 | install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf | 32 | install -m 644 example.cfg $(DESTDIR)/$(confdir)/cpufreq-bench.conf |
26 | 33 | ||
27 | clean: | 34 | clean: |
28 | rm -f *.o | 35 | rm -f $(OUTPUT)*.o |
29 | rm -f cpufreq-bench | 36 | rm -f $(OUTPUT)cpufreq-bench |
diff --git a/tools/power/cpupower/debug/i386/Makefile b/tools/power/cpupower/debug/i386/Makefile index d08cc1ead9bc..3ba158f0e287 100644 --- a/tools/power/cpupower/debug/i386/Makefile +++ b/tools/power/cpupower/debug/i386/Makefile | |||
@@ -1,20 +1,38 @@ | |||
1 | OUTPUT=./ | ||
2 | ifeq ("$(origin O)", "command line") | ||
3 | OUTPUT := $(O)/ | ||
4 | endif | ||
5 | |||
6 | DESTDIR = | ||
7 | bindir = /usr/bin | ||
8 | |||
9 | INSTALL = /usr/bin/install | ||
10 | |||
11 | |||
1 | default: all | 12 | default: all |
2 | 13 | ||
3 | centrino-decode: centrino-decode.c | 14 | $(OUTPUT)centrino-decode: centrino-decode.c |
4 | $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c | 15 | $(CC) $(CFLAGS) -o $@ centrino-decode.c |
5 | 16 | ||
6 | dump_psb: dump_psb.c | 17 | $(OUTPUT)dump_psb: dump_psb.c |
7 | $(CC) $(CFLAGS) -o dump_psb dump_psb.c | 18 | $(CC) $(CFLAGS) -o $@ dump_psb.c |
8 | 19 | ||
9 | intel_gsic: intel_gsic.c | 20 | $(OUTPUT)intel_gsic: intel_gsic.c |
10 | $(CC) $(CFLAGS) -o intel_gsic -llrmi intel_gsic.c | 21 | $(CC) $(CFLAGS) -o $@ -llrmi intel_gsic.c |
11 | 22 | ||
12 | powernow-k8-decode: powernow-k8-decode.c | 23 | $(OUTPUT)powernow-k8-decode: powernow-k8-decode.c |
13 | $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c | 24 | $(CC) $(CFLAGS) -o $@ powernow-k8-decode.c |
14 | 25 | ||
15 | all: centrino-decode dump_psb intel_gsic powernow-k8-decode | 26 | all: $(OUTPUT)centrino-decode $(OUTPUT)dump_psb $(OUTPUT)intel_gsic $(OUTPUT)powernow-k8-decode |
16 | 27 | ||
17 | clean: | 28 | clean: |
18 | rm -rf centrino-decode dump_psb intel_gsic powernow-k8-decode | 29 | rm -rf $(OUTPUT){centrino-decode,dump_psb,intel_gsic,powernow-k8-decode} |
30 | |||
31 | install: | ||
32 | $(INSTALL) -d $(DESTDIR)${bindir} | ||
33 | $(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir} | ||
34 | $(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir} | ||
35 | $(INSTALL) $(OUTPUT)dump_psb $(DESTDIR)${bindir} | ||
36 | $(INSTALL) $(OUTPUT)intel_gsic $(DESTDIR)${bindir} | ||
19 | 37 | ||
20 | .PHONY: all default clean | 38 | .PHONY: all default clean install |
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile index 3326217dd311..1c5214526716 100644 --- a/tools/power/cpupower/debug/x86_64/Makefile +++ b/tools/power/cpupower/debug/x86_64/Makefile | |||
@@ -1,14 +1,30 @@ | |||
1 | OUTPUT=./ | ||
2 | ifeq ("$(origin O)", "command line") | ||
3 | OUTPUT := $(O)/ | ||
4 | endif | ||
5 | |||
6 | DESTDIR = | ||
7 | bindir = /usr/bin | ||
8 | |||
9 | INSTALL = /usr/bin/install | ||
10 | |||
11 | |||
1 | default: all | 12 | default: all |
2 | 13 | ||
3 | centrino-decode: ../i386/centrino-decode.c | 14 | $(OUTPUT)centrino-decode: ../i386/centrino-decode.c |
4 | $(CC) $(CFLAGS) -o $@ $< | 15 | $(CC) $(CFLAGS) -o $@ $< |
5 | 16 | ||
6 | powernow-k8-decode: ../i386/powernow-k8-decode.c | 17 | $(OUTPUT)powernow-k8-decode: ../i386/powernow-k8-decode.c |
7 | $(CC) $(CFLAGS) -o $@ $< | 18 | $(CC) $(CFLAGS) -o $@ $< |
8 | 19 | ||
9 | all: centrino-decode powernow-k8-decode | 20 | all: $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode |
10 | 21 | ||
11 | clean: | 22 | clean: |
12 | rm -rf centrino-decode powernow-k8-decode | 23 | rm -rf $(OUTPUT)centrino-decode $(OUTPUT)powernow-k8-decode |
24 | |||
25 | install: | ||
26 | $(INSTALL) -d $(DESTDIR)${bindir} | ||
27 | $(INSTALL) $(OUTPUT)centrino-decode $(DESTDIR)${bindir} | ||
28 | $(INSTALL) $(OUTPUT)powernow-k8-decode $(DESTDIR)${bindir} | ||
13 | 29 | ||
14 | .PHONY: all default clean | 30 | .PHONY: all default clean install |
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 index bb60a8d1e45a..4a1918ea8f9c 100644 --- a/tools/power/cpupower/man/cpupower-frequency-info.1 +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" "" | 1 | .TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower frequency\-info \- Utility to retrieve cpufreq kernel information | 4 | cpupower frequency\-info \- Utility to retrieve cpufreq kernel information |
@@ -50,8 +50,6 @@ Prints out information like provided by the /proc/cpufreq interface in 2.4. and | |||
50 | \fB\-m\fR \fB\-\-human\fR | 50 | \fB\-m\fR \fB\-\-human\fR |
51 | human\-readable output for the \-f, \-w, \-s and \-y parameters. | 51 | human\-readable output for the \-f, \-w, \-s and \-y parameters. |
52 | .TP | 52 | .TP |
53 | \fB\-h\fR \fB\-\-help\fR | ||
54 | Prints out the help screen. | ||
55 | .SH "REMARKS" | 53 | .SH "REMARKS" |
56 | .LP | 54 | .LP |
57 | By default only values of core zero are displayed. How to display settings of | 55 | By default only values of core zero are displayed. How to display settings of |
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 index 685f469093ad..3eacc8d03d1a 100644 --- a/tools/power/cpupower/man/cpupower-frequency-set.1 +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 | |||
@@ -1,4 +1,4 @@ | |||
1 | .TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" "" | 1 | .TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. | 4 | cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. |
@@ -26,8 +26,6 @@ specific frequency to be set. Requires userspace governor to be available and lo | |||
26 | \fB\-r\fR \fB\-\-related\fR | 26 | \fB\-r\fR \fB\-\-related\fR |
27 | modify all hardware-related CPUs at the same time | 27 | modify all hardware-related CPUs at the same time |
28 | .TP | 28 | .TP |
29 | \fB\-h\fR \fB\-\-help\fR | ||
30 | Prints out the help screen. | ||
31 | .SH "REMARKS" | 29 | .SH "REMARKS" |
32 | .LP | 30 | .LP |
33 | By default values are applied on all cores. How to modify single core | 31 | By default values are applied on all cores. How to modify single core |
diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1 new file mode 100644 index 000000000000..4178effd9e99 --- /dev/null +++ b/tools/power/cpupower/man/cpupower-idle-info.1 | |||
@@ -0,0 +1,90 @@ | |||
1 | .TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual" | ||
2 | .SH "NAME" | ||
3 | .LP | ||
4 | cpupower idle\-info \- Utility to retrieve cpu idle kernel information | ||
5 | .SH "SYNTAX" | ||
6 | .LP | ||
7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] | ||
8 | .SH "DESCRIPTION" | ||
9 | .LP | ||
10 | A tool which prints out per cpu idle information helpful to developers and interested users. | ||
11 | .SH "OPTIONS" | ||
12 | .LP | ||
13 | .TP | ||
14 | \fB\-f\fR \fB\-\-silent\fR | ||
15 | Only print a summary of all available C-states in the system. | ||
16 | .TP | ||
17 | \fB\-e\fR \fB\-\-proc\fR | ||
18 | deprecated. | ||
19 | Prints out idle information in old /proc/acpi/processor/*/power format. This | ||
20 | interface has been removed from the kernel for quite some time, do not let | ||
21 | further code depend on this option, best do not use it. | ||
22 | |||
23 | .SH IDLE\-INFO DESCRIPTIONS | ||
24 | CPU sleep state statistics and descriptions are retrieved from sysfs files, | ||
25 | exported by the cpuidle kernel subsystem. The kernel only updates these | ||
26 | statistics when it enters or leaves an idle state, therefore on a very idle or | ||
27 | a very busy system, these statistics may not be accurate. They still provide a | ||
28 | good overview about the usage and availability of processor sleep states on | ||
29 | the platform. | ||
30 | |||
31 | Be aware that the sleep states as exported by the hardware or BIOS and used by | ||
32 | the Linux kernel may not exactly reflect the capabilities of the | ||
33 | processor. This often is the case on the X86 architecture when the acpi_idle | ||
34 | driver is used. It is also possible that the hardware overrules the kernel | ||
35 | requests, due to internal activity monitors or other reasons. | ||
36 | On recent X86 platforms it is often possible to read out hardware registers | ||
37 | which monitor the duration of sleep states the processor resided in. The | ||
38 | cpupower monitor tool (cpupower\-monitor(1)) can be used to show real sleep | ||
39 | state residencies. Please refer to the architecture specific description | ||
40 | section below. | ||
41 | |||
42 | .SH IDLE\-INFO ARCHITECTURE SPECIFIC DESCRIPTIONS | ||
43 | .SS "X86" | ||
44 | POLL idle state | ||
45 | |||
46 | If cpuidle is active, X86 platforms have one special idle state. | ||
47 | The POLL idle state is not a real idle state, it does not save any | ||
48 | power. Instead, a busy\-loop is executed doing nothing for a short period of | ||
49 | time. This state is used if the kernel knows that work has to be processed | ||
50 | very soon and entering any real hardware idle state may result in a slight | ||
51 | performance penalty. | ||
52 | |||
53 | There exist two different cpuidle drivers on the X86 architecture platform: | ||
54 | |||
55 | "acpi_idle" cpuidle driver | ||
56 | |||
57 | The acpi_idle cpuidle driver retrieves available sleep states (C\-states) from | ||
58 | the ACPI BIOS tables (from the _CST ACPI function on recent platforms or from | ||
59 | the FADT BIOS table on older ones). | ||
60 | The C1 state is not retrieved from ACPI tables. If the C1 state is entered, | ||
61 | the kernel will call the hlt instruction (or mwait on Intel). | ||
62 | |||
63 | "intel_idle" cpuidle driver | ||
64 | |||
65 | In kernel 2.6.36 the intel_idle driver was introduced. | ||
66 | It only serves recent Intel CPUs (Nehalem, Westmere, Sandybridge, Atoms or | ||
67 | newer). On older Intel CPUs the acpi_idle driver is still used (if the BIOS | ||
68 | provides C\-state ACPI tables). | ||
69 | The intel_idle driver knows the sleep state capabilities of the processor and | ||
70 | ignores ACPI BIOS exported processor sleep states tables. | ||
71 | |||
72 | .SH "REMARKS" | ||
73 | .LP | ||
74 | By default only values of core zero are displayed. How to display settings of | ||
75 | other cores is described in the cpupower(1) manpage in the \-\-cpu option | ||
76 | section. | ||
77 | .SH REFERENCES | ||
78 | http://www.acpi.info/spec.htm | ||
79 | .SH "FILES" | ||
80 | .nf | ||
81 | \fI/sys/devices/system/cpu/cpu*/cpuidle/state*\fP | ||
82 | \fI/sys/devices/system/cpu/cpuidle/*\fP | ||
83 | .fi | ||
84 | .SH "AUTHORS" | ||
85 | .nf | ||
86 | Thomas Renninger <trenn@suse.de> | ||
87 | .fi | ||
88 | .SH "SEE ALSO" | ||
89 | .LP | ||
90 | cpupower(1), cpupower\-monitor(1), cpupower\-info(1), cpupower\-set(1) | ||
diff --git a/tools/power/cpupower/man/cpupower-monitor.1 b/tools/power/cpupower/man/cpupower-monitor.1 index d5cfa265c3d3..1141c2073719 100644 --- a/tools/power/cpupower/man/cpupower-monitor.1 +++ b/tools/power/cpupower/man/cpupower-monitor.1 | |||
@@ -107,7 +107,7 @@ Deepest package sleep states may in reality show up as machine/platform wide | |||
107 | sleep states and can only be entered if all cores are idle. Look up Intel | 107 | sleep states and can only be entered if all cores are idle. Look up Intel |
108 | manuals (some are provided in the References section) for further details. | 108 | manuals (some are provided in the References section) for further details. |
109 | 109 | ||
110 | .SS "Ontario" "Liano" | 110 | .SS "Fam_12h" "Fam_14h" |
111 | AMD laptop and desktop processor (family 12h and 14h) sleep state counters. | 111 | AMD laptop and desktop processor (family 12h and 14h) sleep state counters. |
112 | The registers are accessed via PCI and therefore can still be read out while | 112 | The registers are accessed via PCI and therefore can still be read out while |
113 | cores have been offlined. | 113 | cores have been offlined. |
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index b028267c1376..8145af5f93a6 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c | |||
@@ -35,17 +35,9 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
35 | printf(_("CPU %u: Can't read idle state info\n"), cpu); | 35 | printf(_("CPU %u: Can't read idle state info\n"), cpu); |
36 | return; | 36 | return; |
37 | } | 37 | } |
38 | tmp = sysfs_get_idlestate_name(cpu, idlestates - 1); | ||
39 | if (!tmp) { | ||
40 | printf(_("Could not determine max idle state %u\n"), | ||
41 | idlestates - 1); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | printf(_("Number of idle states: %d\n"), idlestates); | 38 | printf(_("Number of idle states: %d\n"), idlestates); |
46 | |||
47 | printf(_("Available idle states:")); | 39 | printf(_("Available idle states:")); |
48 | for (idlestate = 1; idlestate < idlestates; idlestate++) { | 40 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
49 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | 41 | tmp = sysfs_get_idlestate_name(cpu, idlestate); |
50 | if (!tmp) | 42 | if (!tmp) |
51 | continue; | 43 | continue; |
@@ -57,7 +49,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
57 | if (!verbose) | 49 | if (!verbose) |
58 | return; | 50 | return; |
59 | 51 | ||
60 | for (idlestate = 1; idlestate < idlestates; idlestate++) { | 52 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
61 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | 53 | tmp = sysfs_get_idlestate_name(cpu, idlestate); |
62 | if (!tmp) | 54 | if (!tmp) |
63 | continue; | 55 | continue; |
diff --git a/tools/power/cpupower/utils/helpers/amd.c b/tools/power/cpupower/utils/helpers/amd.c index 87d5605bdda8..6437ef39aeea 100644 --- a/tools/power/cpupower/utils/helpers/amd.c +++ b/tools/power/cpupower/utils/helpers/amd.c | |||
@@ -112,14 +112,12 @@ int decode_pstates(unsigned int cpu, unsigned int cpu_family, | |||
112 | int amd_pci_get_num_boost_states(int *active, int *states) | 112 | int amd_pci_get_num_boost_states(int *active, int *states) |
113 | { | 113 | { |
114 | struct pci_access *pci_acc; | 114 | struct pci_access *pci_acc; |
115 | int vendor_id = 0x1022; | ||
116 | int boost_dev_ids[4] = {0x1204, 0x1604, 0x1704, 0}; | ||
117 | struct pci_dev *device; | 115 | struct pci_dev *device; |
118 | uint8_t val = 0; | 116 | uint8_t val = 0; |
119 | 117 | ||
120 | *active = *states = 0; | 118 | *active = *states = 0; |
121 | 119 | ||
122 | device = pci_acc_init(&pci_acc, vendor_id, boost_dev_ids); | 120 | device = pci_slot_func_init(&pci_acc, 0x18, 4); |
123 | 121 | ||
124 | if (device == NULL) | 122 | if (device == NULL) |
125 | return -ENODEV; | 123 | return -ENODEV; |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index 2747e738efb0..2eb584cf2f55 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -66,8 +66,8 @@ enum cpupower_cpu_vendor {X86_VENDOR_UNKNOWN = 0, X86_VENDOR_INTEL, | |||
66 | #define CPUPOWER_CAP_AMD_CBP 0x00000004 | 66 | #define CPUPOWER_CAP_AMD_CBP 0x00000004 |
67 | #define CPUPOWER_CAP_PERF_BIAS 0x00000008 | 67 | #define CPUPOWER_CAP_PERF_BIAS 0x00000008 |
68 | #define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010 | 68 | #define CPUPOWER_CAP_HAS_TURBO_RATIO 0x00000010 |
69 | #define CPUPOWER_CAP_IS_SNB 0x00000011 | 69 | #define CPUPOWER_CAP_IS_SNB 0x00000020 |
70 | #define CPUPOWER_CAP_INTEL_IDA 0x00000012 | 70 | #define CPUPOWER_CAP_INTEL_IDA 0x00000040 |
71 | 71 | ||
72 | #define MAX_HW_PSTATES 10 | 72 | #define MAX_HW_PSTATES 10 |
73 | 73 | ||
@@ -132,8 +132,11 @@ extern unsigned long long msr_intel_get_turbo_ratio(unsigned int cpu); | |||
132 | 132 | ||
133 | /* PCI stuff ****************************/ | 133 | /* PCI stuff ****************************/ |
134 | extern int amd_pci_get_num_boost_states(int *active, int *states); | 134 | extern int amd_pci_get_num_boost_states(int *active, int *states); |
135 | extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id, | 135 | extern struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, |
136 | int *dev_ids); | 136 | int bus, int slot, int func, int vendor, |
137 | int dev); | ||
138 | extern struct pci_dev *pci_slot_func_init(struct pci_access **pacc, | ||
139 | int slot, int func); | ||
137 | 140 | ||
138 | /* PCI stuff ****************************/ | 141 | /* PCI stuff ****************************/ |
139 | 142 | ||
diff --git a/tools/power/cpupower/utils/helpers/pci.c b/tools/power/cpupower/utils/helpers/pci.c index cd2eb6fe41c4..9690798e6446 100644 --- a/tools/power/cpupower/utils/helpers/pci.c +++ b/tools/power/cpupower/utils/helpers/pci.c | |||
@@ -10,19 +10,24 @@ | |||
10 | * **pacc : if a valid pci_dev is returned | 10 | * **pacc : if a valid pci_dev is returned |
11 | * *pacc must be passed to pci_acc_cleanup to free it | 11 | * *pacc must be passed to pci_acc_cleanup to free it |
12 | * | 12 | * |
13 | * vendor_id : the pci vendor id matching the pci device to access | 13 | * domain: domain |
14 | * dev_ids : device ids matching the pci device to access | 14 | * bus: bus |
15 | * slot: slot | ||
16 | * func: func | ||
17 | * vendor: vendor | ||
18 | * device: device | ||
19 | * Pass -1 for one of the six above to match any | ||
15 | * | 20 | * |
16 | * Returns : | 21 | * Returns : |
17 | * struct pci_dev which can be used with pci_{read,write}_* functions | 22 | * struct pci_dev which can be used with pci_{read,write}_* functions |
18 | * to access the PCI config space of matching pci devices | 23 | * to access the PCI config space of matching pci devices |
19 | */ | 24 | */ |
20 | struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id, | 25 | struct pci_dev *pci_acc_init(struct pci_access **pacc, int domain, int bus, |
21 | int *dev_ids) | 26 | int slot, int func, int vendor, int dev) |
22 | { | 27 | { |
23 | struct pci_filter filter_nb_link = { -1, -1, -1, -1, vendor_id, 0}; | 28 | struct pci_filter filter_nb_link = { domain, bus, slot, func, |
29 | vendor, dev }; | ||
24 | struct pci_dev *device; | 30 | struct pci_dev *device; |
25 | unsigned int i; | ||
26 | 31 | ||
27 | *pacc = pci_alloc(); | 32 | *pacc = pci_alloc(); |
28 | if (*pacc == NULL) | 33 | if (*pacc == NULL) |
@@ -31,14 +36,20 @@ struct pci_dev *pci_acc_init(struct pci_access **pacc, int vendor_id, | |||
31 | pci_init(*pacc); | 36 | pci_init(*pacc); |
32 | pci_scan_bus(*pacc); | 37 | pci_scan_bus(*pacc); |
33 | 38 | ||
34 | for (i = 0; dev_ids[i] != 0; i++) { | 39 | for (device = (*pacc)->devices; device; device = device->next) { |
35 | filter_nb_link.device = dev_ids[i]; | 40 | if (pci_filter_match(&filter_nb_link, device)) |
36 | for (device = (*pacc)->devices; device; device = device->next) { | 41 | return device; |
37 | if (pci_filter_match(&filter_nb_link, device)) | ||
38 | return device; | ||
39 | } | ||
40 | } | 42 | } |
41 | pci_cleanup(*pacc); | 43 | pci_cleanup(*pacc); |
42 | return NULL; | 44 | return NULL; |
43 | } | 45 | } |
46 | |||
47 | /* Typically one wants to get a specific slot(device)/func of the root domain | ||
48 | and bus */ | ||
49 | struct pci_dev *pci_slot_func_init(struct pci_access **pacc, int slot, | ||
50 | int func) | ||
51 | { | ||
52 | return pci_acc_init(pacc, 0, 0, slot, func, -1, -1); | ||
53 | } | ||
54 | |||
44 | #endif /* defined(__i386__) || defined(__x86_64__) */ | 55 | #endif /* defined(__i386__) || defined(__x86_64__) */ |
diff --git a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c index 202e555988be..2116df9ad832 100644 --- a/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c +++ b/tools/power/cpupower/utils/idle_monitor/amd_fam14h_idle.c | |||
@@ -20,8 +20,6 @@ | |||
20 | #include "idle_monitor/cpupower-monitor.h" | 20 | #include "idle_monitor/cpupower-monitor.h" |
21 | #include "helpers/helpers.h" | 21 | #include "helpers/helpers.h" |
22 | 22 | ||
23 | /******** PCI parts could go into own file and get shared ***************/ | ||
24 | |||
25 | #define PCI_NON_PC0_OFFSET 0xb0 | 23 | #define PCI_NON_PC0_OFFSET 0xb0 |
26 | #define PCI_PC1_OFFSET 0xb4 | 24 | #define PCI_PC1_OFFSET 0xb4 |
27 | #define PCI_PC6_OFFSET 0xb8 | 25 | #define PCI_PC6_OFFSET 0xb8 |
@@ -82,10 +80,7 @@ static cstate_t amd_fam14h_cstates[AMD_FAM14H_STATE_NUM] = { | |||
82 | }; | 80 | }; |
83 | 81 | ||
84 | static struct pci_access *pci_acc; | 82 | static struct pci_access *pci_acc; |
85 | static int pci_vendor_id = 0x1022; | ||
86 | static int pci_dev_ids[2] = {0x1716, 0}; | ||
87 | static struct pci_dev *amd_fam14h_pci_dev; | 83 | static struct pci_dev *amd_fam14h_pci_dev; |
88 | |||
89 | static int nbp1_entered; | 84 | static int nbp1_entered; |
90 | 85 | ||
91 | struct timespec start_time; | 86 | struct timespec start_time; |
@@ -286,13 +281,13 @@ struct cpuidle_monitor *amd_fam14h_register(void) | |||
286 | if (cpupower_cpu_info.vendor != X86_VENDOR_AMD) | 281 | if (cpupower_cpu_info.vendor != X86_VENDOR_AMD) |
287 | return NULL; | 282 | return NULL; |
288 | 283 | ||
289 | if (cpupower_cpu_info.family == 0x14) { | 284 | if (cpupower_cpu_info.family == 0x14) |
290 | if (cpu_count <= 0 || cpu_count > 2) { | 285 | strncpy(amd_fam14h_monitor.name, "Fam_14h", |
291 | fprintf(stderr, "AMD fam14h: Invalid cpu count: %d\n", | 286 | MONITOR_NAME_LEN - 1); |
292 | cpu_count); | 287 | else if (cpupower_cpu_info.family == 0x12) |
293 | return NULL; | 288 | strncpy(amd_fam14h_monitor.name, "Fam_12h", |
294 | } | 289 | MONITOR_NAME_LEN - 1); |
295 | } else | 290 | else |
296 | return NULL; | 291 | return NULL; |
297 | 292 | ||
298 | /* We do not alloc for nbp1 machine wide counter */ | 293 | /* We do not alloc for nbp1 machine wide counter */ |
@@ -303,7 +298,9 @@ struct cpuidle_monitor *amd_fam14h_register(void) | |||
303 | sizeof(unsigned long long)); | 298 | sizeof(unsigned long long)); |
304 | } | 299 | } |
305 | 300 | ||
306 | amd_fam14h_pci_dev = pci_acc_init(&pci_acc, pci_vendor_id, pci_dev_ids); | 301 | /* We need PCI device: Slot 18, Func 6, compare with BKDG |
302 | for fam 12h/14h */ | ||
303 | amd_fam14h_pci_dev = pci_slot_func_init(&pci_acc, 0x18, 6); | ||
307 | if (amd_fam14h_pci_dev == NULL || pci_acc == NULL) | 304 | if (amd_fam14h_pci_dev == NULL || pci_acc == NULL) |
308 | return NULL; | 305 | return NULL; |
309 | 306 | ||
@@ -325,7 +322,7 @@ static void amd_fam14h_unregister(void) | |||
325 | } | 322 | } |
326 | 323 | ||
327 | struct cpuidle_monitor amd_fam14h_monitor = { | 324 | struct cpuidle_monitor amd_fam14h_monitor = { |
328 | .name = "Ontario", | 325 | .name = "", |
329 | .hw_states = amd_fam14h_cstates, | 326 | .hw_states = amd_fam14h_cstates, |
330 | .hw_states_num = AMD_FAM14H_STATE_NUM, | 327 | .hw_states_num = AMD_FAM14H_STATE_NUM, |
331 | .start = amd_fam14h_start, | 328 | .start = amd_fam14h_start, |
diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 555c69a5592a..adf175f61496 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 | |||
@@ -4,11 +4,13 @@ turbostat \- Report processor frequency and idle statistics | |||
4 | .SH SYNOPSIS | 4 | .SH SYNOPSIS |
5 | .ft B | 5 | .ft B |
6 | .B turbostat | 6 | .B turbostat |
7 | .RB [ "\-s" ] | ||
7 | .RB [ "\-v" ] | 8 | .RB [ "\-v" ] |
8 | .RB [ "\-M MSR#" ] | 9 | .RB [ "\-M MSR#" ] |
9 | .RB command | 10 | .RB command |
10 | .br | 11 | .br |
11 | .B turbostat | 12 | .B turbostat |
13 | .RB [ "\-s" ] | ||
12 | .RB [ "\-v" ] | 14 | .RB [ "\-v" ] |
13 | .RB [ "\-M MSR#" ] | 15 | .RB [ "\-M MSR#" ] |
14 | .RB [ "\-i interval_sec" ] | 16 | .RB [ "\-i interval_sec" ] |
@@ -25,6 +27,8 @@ supports an "invariant" TSC, plus the APERF and MPERF MSRs. | |||
25 | on processors that additionally support C-state residency counters. | 27 | on processors that additionally support C-state residency counters. |
26 | 28 | ||
27 | .SS Options | 29 | .SS Options |
30 | The \fB-s\fP option prints only a 1-line summary for each sample interval. | ||
31 | .PP | ||
28 | The \fB-v\fP option increases verbosity. | 32 | The \fB-v\fP option increases verbosity. |
29 | .PP | 33 | .PP |
30 | The \fB-M MSR#\fP option dumps the specified MSR, | 34 | The \fB-M MSR#\fP option dumps the specified MSR, |
@@ -39,13 +43,14 @@ displays the statistics gathered since it was forked. | |||
39 | .SH FIELD DESCRIPTIONS | 43 | .SH FIELD DESCRIPTIONS |
40 | .nf | 44 | .nf |
41 | \fBpk\fP processor package number. | 45 | \fBpk\fP processor package number. |
42 | \fBcr\fP processor core number. | 46 | \fBcor\fP processor core number. |
43 | \fBCPU\fP Linux CPU (logical processor) number. | 47 | \fBCPU\fP Linux CPU (logical processor) number. |
48 | Note that multiple CPUs per core indicate support for Intel(R) Hyper-Threading Technology. | ||
44 | \fB%c0\fP percent of the interval that the CPU retired instructions. | 49 | \fB%c0\fP percent of the interval that the CPU retired instructions. |
45 | \fBGHz\fP average clock rate while the CPU was in c0 state. | 50 | \fBGHz\fP average clock rate while the CPU was in c0 state. |
46 | \fBTSC\fP average GHz that the TSC ran during the entire interval. | 51 | \fBTSC\fP average GHz that the TSC ran during the entire interval. |
47 | \fB%c1, %c3, %c6\fP show the percentage residency in hardware core idle states. | 52 | \fB%c1, %c3, %c6, %c7\fP show the percentage residency in hardware core idle states. |
48 | \fB%pc3, %pc6\fP percentage residency in hardware package idle states. | 53 | \fB%pc2, %pc3, %pc6, %pc7\fP percentage residency in hardware package idle states. |
49 | .fi | 54 | .fi |
50 | .PP | 55 | .PP |
51 | .SH EXAMPLE | 56 | .SH EXAMPLE |
@@ -53,25 +58,37 @@ Without any parameters, turbostat prints out counters ever 5 seconds. | |||
53 | (override interval with "-i sec" option, or specify a command | 58 | (override interval with "-i sec" option, or specify a command |
54 | for turbostat to fork). | 59 | for turbostat to fork). |
55 | 60 | ||
56 | The first row of statistics reflect the average for the entire system. | 61 | The first row of statistics is a summary for the entire system. |
62 | Note that the summary is a weighted average. | ||
57 | Subsequent rows show per-CPU statistics. | 63 | Subsequent rows show per-CPU statistics. |
58 | 64 | ||
59 | .nf | 65 | .nf |
60 | [root@x980]# ./turbostat | 66 | [root@x980]# ./turbostat |
61 | cr CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 | 67 | cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 |
62 | 0.04 1.62 3.38 0.11 0.00 99.85 0.00 95.07 | 68 | 0.60 1.63 3.38 2.91 0.00 96.49 0.00 76.64 |
63 | 0 0 0.04 1.62 3.38 0.06 0.00 99.90 0.00 95.07 | 69 | 0 0 0.59 1.62 3.38 4.51 0.00 94.90 0.00 76.64 |
64 | 0 6 0.02 1.62 3.38 0.08 0.00 99.90 0.00 95.07 | 70 | 0 6 1.13 1.64 3.38 3.97 0.00 94.90 0.00 76.64 |
65 | 1 2 0.10 1.62 3.38 0.29 0.00 99.61 0.00 95.07 | 71 | 1 2 0.08 1.62 3.38 0.07 0.00 99.85 0.00 76.64 |
66 | 1 8 0.11 1.62 3.38 0.28 0.00 99.61 0.00 95.07 | 72 | 1 8 0.03 1.62 3.38 0.12 0.00 99.85 0.00 76.64 |
67 | 2 4 0.01 1.62 3.38 0.01 0.00 99.98 0.00 95.07 | 73 | 2 4 0.01 1.62 3.38 0.06 0.00 99.93 0.00 76.64 |
68 | 2 10 0.01 1.61 3.38 0.02 0.00 99.98 0.00 95.07 | 74 | 2 10 0.04 1.62 3.38 0.02 0.00 99.93 0.00 76.64 |
69 | 8 1 0.07 1.62 3.38 0.15 0.00 99.78 0.00 95.07 | 75 | 8 1 2.85 1.62 3.38 11.71 0.00 85.44 0.00 76.64 |
70 | 8 7 0.03 1.62 3.38 0.19 0.00 99.78 0.00 95.07 | 76 | 8 7 1.98 1.62 3.38 12.58 0.00 85.44 0.00 76.64 |
71 | 9 3 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07 | 77 | 9 3 0.36 1.62 3.38 0.71 0.00 98.93 0.00 76.64 |
72 | 9 9 0.01 1.62 3.38 0.02 0.00 99.98 0.00 95.07 | 78 | 9 9 0.09 1.62 3.38 0.98 0.00 98.93 0.00 76.64 |
73 | 10 5 0.01 1.62 3.38 0.13 0.00 99.86 0.00 95.07 | 79 | 10 5 0.03 1.62 3.38 0.09 0.00 99.87 0.00 76.64 |
74 | 10 11 0.08 1.62 3.38 0.05 0.00 99.86 0.00 95.07 | 80 | 10 11 0.07 1.62 3.38 0.06 0.00 99.87 0.00 76.64 |
81 | .fi | ||
82 | .SH SUMMARY EXAMPLE | ||
83 | The "-s" option prints the column headers just once, | ||
84 | and then the one line system summary for each sample interval. | ||
85 | |||
86 | .nf | ||
87 | [root@x980]# ./turbostat -s | ||
88 | %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 | ||
89 | 0.61 1.89 3.38 5.95 0.00 93.44 0.00 66.33 | ||
90 | 0.52 1.62 3.38 6.83 0.00 92.65 0.00 61.11 | ||
91 | 0.62 1.92 3.38 5.47 0.00 93.91 0.00 67.31 | ||
75 | .fi | 92 | .fi |
76 | .SH VERBOSE EXAMPLE | 93 | .SH VERBOSE EXAMPLE |
77 | The "-v" option adds verbosity to the output: | 94 | The "-v" option adds verbosity to the output: |
@@ -101,33 +118,33 @@ until ^C while the other CPUs are mostly idle: | |||
101 | 118 | ||
102 | .nf | 119 | .nf |
103 | [root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null | 120 | [root@x980 lenb]# ./turbostat cat /dev/zero > /dev/null |
104 | 121 | ^C | |
105 | ^Ccr CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 | 122 | cor CPU %c0 GHz TSC %c1 %c3 %c6 %pc3 %pc6 |
106 | 8.49 3.63 3.38 16.23 0.66 74.63 0.00 0.00 | 123 | 8.63 3.64 3.38 14.46 0.49 76.42 0.00 0.00 |
107 | 0 0 1.22 3.62 3.38 32.18 0.00 66.60 0.00 0.00 | 124 | 0 0 0.34 3.36 3.38 99.66 0.00 0.00 0.00 0.00 |
108 | 0 6 0.40 3.61 3.38 33.00 0.00 66.60 0.00 0.00 | 125 | 0 6 99.96 3.64 3.38 0.04 0.00 0.00 0.00 0.00 |
109 | 1 2 0.11 3.14 3.38 0.19 3.95 95.75 0.00 0.00 | 126 | 1 2 0.14 3.50 3.38 1.75 2.04 96.07 0.00 0.00 |
110 | 1 8 0.05 2.88 3.38 0.25 3.95 95.75 0.00 0.00 | 127 | 1 8 0.38 3.57 3.38 1.51 2.04 96.07 0.00 0.00 |
111 | 2 4 0.00 3.13 3.38 0.02 0.00 99.98 0.00 0.00 | 128 | 2 4 0.01 2.65 3.38 0.06 0.00 99.93 0.00 0.00 |
112 | 2 10 0.00 3.09 3.38 0.02 0.00 99.98 0.00 0.00 | 129 | 2 10 0.03 2.12 3.38 0.04 0.00 99.93 0.00 0.00 |
113 | 8 1 0.04 3.50 3.38 14.43 0.00 85.54 0.00 0.00 | 130 | 8 1 0.91 3.59 3.38 35.27 0.92 62.90 0.00 0.00 |
114 | 8 7 0.03 2.98 3.38 14.43 0.00 85.54 0.00 0.00 | 131 | 8 7 1.61 3.63 3.38 34.57 0.92 62.90 0.00 0.00 |
115 | 9 3 0.00 3.16 3.38 100.00 0.00 0.00 0.00 0.00 | 132 | 9 3 0.04 3.38 3.38 0.20 0.00 99.76 0.00 0.00 |
116 | 9 9 99.93 3.63 3.38 0.06 0.00 0.00 0.00 0.00 | 133 | 9 9 0.04 3.29 3.38 0.20 0.00 99.76 0.00 0.00 |
117 | 10 5 0.01 2.82 3.38 0.08 0.00 99.91 0.00 0.00 | 134 | 10 5 0.03 3.08 3.38 0.12 0.00 99.85 0.00 0.00 |
118 | 10 11 0.02 3.36 3.38 0.06 0.00 99.91 0.00 0.00 | 135 | 10 11 0.05 3.07 3.38 0.10 0.00 99.85 0.00 0.00 |
119 | 6.950866 sec | 136 | 4.907015 sec |
120 | 137 | ||
121 | .fi | 138 | .fi |
122 | Above the cycle soaker drives cpu9 up 3.6 Ghz turbo limit | 139 | Above the cycle soaker drives cpu6 up 3.6 Ghz turbo limit |
123 | while the other processors are generally in various states of idle. | 140 | while the other processors are generally in various states of idle. |
124 | 141 | ||
125 | Note that cpu3 is an HT sibling sharing core9 | 142 | Note that cpu0 is an HT sibling sharing core0 |
126 | with cpu9, and thus it is unable to get to an idle state | 143 | with cpu6, and thus it is unable to get to an idle state |
127 | deeper than c1 while cpu9 is busy. | 144 | deeper than c1 while cpu6 is busy. |
128 | 145 | ||
129 | Note that turbostat reports average GHz of 3.61, while | 146 | Note that turbostat reports average GHz of 3.64, while |
130 | the arithmetic average of the GHz column above is 3.24. | 147 | the arithmetic average of the GHz column above is lower. |
131 | This is a weighted average, where the weight is %c0. ie. it is the total number of | 148 | This is a weighted average, where the weight is %c0. ie. it is the total number of |
132 | un-halted cycles elapsed per time divided by the number of CPUs. | 149 | un-halted cycles elapsed per time divided by the number of CPUs. |
133 | .SH NOTES | 150 | .SH NOTES |
@@ -167,6 +184,6 @@ http://www.intel.com/products/processor/manuals/ | |||
167 | .SH "SEE ALSO" | 184 | .SH "SEE ALSO" |
168 | msr(4), vmstat(8) | 185 | msr(4), vmstat(8) |
169 | .PP | 186 | .PP |
170 | .SH AUTHORS | 187 | .SH AUTHOR |
171 | .nf | 188 | .nf |
172 | Written by Len Brown <len.brown@intel.com> | 189 | Written by Len Brown <len.brown@intel.com> |
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 310d3dd5e547..ab2f682fd44c 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * turbostat -- show CPU frequency and C-state residency | 2 | * turbostat -- show CPU frequency and C-state residency |
3 | * on modern Intel turbo-capable processors. | 3 | * on modern Intel turbo-capable processors. |
4 | * | 4 | * |
5 | * Copyright (c) 2010, Intel Corporation. | 5 | * Copyright (c) 2012 Intel Corporation. |
6 | * Len Brown <len.brown@intel.com> | 6 | * Len Brown <len.brown@intel.com> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
@@ -19,6 +19,7 @@ | |||
19 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | 19 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. |
20 | */ | 20 | */ |
21 | 21 | ||
22 | #define _GNU_SOURCE | ||
22 | #include <stdio.h> | 23 | #include <stdio.h> |
23 | #include <unistd.h> | 24 | #include <unistd.h> |
24 | #include <sys/types.h> | 25 | #include <sys/types.h> |
@@ -32,6 +33,7 @@ | |||
32 | #include <dirent.h> | 33 | #include <dirent.h> |
33 | #include <string.h> | 34 | #include <string.h> |
34 | #include <ctype.h> | 35 | #include <ctype.h> |
36 | #include <sched.h> | ||
35 | 37 | ||
36 | #define MSR_TSC 0x10 | 38 | #define MSR_TSC 0x10 |
37 | #define MSR_NEHALEM_PLATFORM_INFO 0xCE | 39 | #define MSR_NEHALEM_PLATFORM_INFO 0xCE |
@@ -49,6 +51,7 @@ | |||
49 | char *proc_stat = "/proc/stat"; | 51 | char *proc_stat = "/proc/stat"; |
50 | unsigned int interval_sec = 5; /* set with -i interval_sec */ | 52 | unsigned int interval_sec = 5; /* set with -i interval_sec */ |
51 | unsigned int verbose; /* set with -v */ | 53 | unsigned int verbose; /* set with -v */ |
54 | unsigned int summary_only; /* set with -s */ | ||
52 | unsigned int skip_c0; | 55 | unsigned int skip_c0; |
53 | unsigned int skip_c1; | 56 | unsigned int skip_c1; |
54 | unsigned int do_nhm_cstates; | 57 | unsigned int do_nhm_cstates; |
@@ -68,9 +71,10 @@ unsigned int show_cpu; | |||
68 | int aperf_mperf_unstable; | 71 | int aperf_mperf_unstable; |
69 | int backwards_count; | 72 | int backwards_count; |
70 | char *progname; | 73 | char *progname; |
71 | int need_reinitialize; | ||
72 | 74 | ||
73 | int num_cpus; | 75 | int num_cpus; |
76 | cpu_set_t *cpu_mask; | ||
77 | size_t cpu_mask_size; | ||
74 | 78 | ||
75 | struct counters { | 79 | struct counters { |
76 | unsigned long long tsc; /* per thread */ | 80 | unsigned long long tsc; /* per thread */ |
@@ -99,44 +103,76 @@ struct timeval tv_even; | |||
99 | struct timeval tv_odd; | 103 | struct timeval tv_odd; |
100 | struct timeval tv_delta; | 104 | struct timeval tv_delta; |
101 | 105 | ||
102 | unsigned long long get_msr(int cpu, off_t offset) | 106 | /* |
107 | * cpu_mask_init(ncpus) | ||
108 | * | ||
109 | * allocate and clear cpu_mask | ||
110 | * set cpu_mask_size | ||
111 | */ | ||
112 | void cpu_mask_init(int ncpus) | ||
113 | { | ||
114 | cpu_mask = CPU_ALLOC(ncpus); | ||
115 | if (cpu_mask == NULL) { | ||
116 | perror("CPU_ALLOC"); | ||
117 | exit(3); | ||
118 | } | ||
119 | cpu_mask_size = CPU_ALLOC_SIZE(ncpus); | ||
120 | CPU_ZERO_S(cpu_mask_size, cpu_mask); | ||
121 | } | ||
122 | |||
123 | void cpu_mask_uninit() | ||
124 | { | ||
125 | CPU_FREE(cpu_mask); | ||
126 | cpu_mask = NULL; | ||
127 | cpu_mask_size = 0; | ||
128 | } | ||
129 | |||
130 | int cpu_migrate(int cpu) | ||
131 | { | ||
132 | CPU_ZERO_S(cpu_mask_size, cpu_mask); | ||
133 | CPU_SET_S(cpu, cpu_mask_size, cpu_mask); | ||
134 | if (sched_setaffinity(0, cpu_mask_size, cpu_mask) == -1) | ||
135 | return -1; | ||
136 | else | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | int get_msr(int cpu, off_t offset, unsigned long long *msr) | ||
103 | { | 141 | { |
104 | ssize_t retval; | 142 | ssize_t retval; |
105 | unsigned long long msr; | ||
106 | char pathname[32]; | 143 | char pathname[32]; |
107 | int fd; | 144 | int fd; |
108 | 145 | ||
109 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); | 146 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); |
110 | fd = open(pathname, O_RDONLY); | 147 | fd = open(pathname, O_RDONLY); |
111 | if (fd < 0) { | 148 | if (fd < 0) |
112 | perror(pathname); | 149 | return -1; |
113 | need_reinitialize = 1; | ||
114 | return 0; | ||
115 | } | ||
116 | |||
117 | retval = pread(fd, &msr, sizeof msr, offset); | ||
118 | if (retval != sizeof msr) { | ||
119 | fprintf(stderr, "cpu%d pread(..., 0x%zx) = %jd\n", | ||
120 | cpu, offset, retval); | ||
121 | exit(-2); | ||
122 | } | ||
123 | 150 | ||
151 | retval = pread(fd, msr, sizeof *msr, offset); | ||
124 | close(fd); | 152 | close(fd); |
125 | return msr; | 153 | |
154 | if (retval != sizeof *msr) | ||
155 | return -1; | ||
156 | |||
157 | return 0; | ||
126 | } | 158 | } |
127 | 159 | ||
128 | void print_header(void) | 160 | void print_header(void) |
129 | { | 161 | { |
130 | if (show_pkg) | 162 | if (show_pkg) |
131 | fprintf(stderr, "pk"); | 163 | fprintf(stderr, "pk"); |
164 | if (show_pkg) | ||
165 | fprintf(stderr, " "); | ||
132 | if (show_core) | 166 | if (show_core) |
133 | fprintf(stderr, " cr"); | 167 | fprintf(stderr, "cor"); |
134 | if (show_cpu) | 168 | if (show_cpu) |
135 | fprintf(stderr, " CPU"); | 169 | fprintf(stderr, " CPU"); |
170 | if (show_pkg || show_core || show_cpu) | ||
171 | fprintf(stderr, " "); | ||
136 | if (do_nhm_cstates) | 172 | if (do_nhm_cstates) |
137 | fprintf(stderr, " %%c0 "); | 173 | fprintf(stderr, " %%c0"); |
138 | if (has_aperf) | 174 | if (has_aperf) |
139 | fprintf(stderr, " GHz"); | 175 | fprintf(stderr, " GHz"); |
140 | fprintf(stderr, " TSC"); | 176 | fprintf(stderr, " TSC"); |
141 | if (do_nhm_cstates) | 177 | if (do_nhm_cstates) |
142 | fprintf(stderr, " %%c1"); | 178 | fprintf(stderr, " %%c1"); |
@@ -147,13 +183,13 @@ void print_header(void) | |||
147 | if (do_snb_cstates) | 183 | if (do_snb_cstates) |
148 | fprintf(stderr, " %%c7"); | 184 | fprintf(stderr, " %%c7"); |
149 | if (do_snb_cstates) | 185 | if (do_snb_cstates) |
150 | fprintf(stderr, " %%pc2"); | 186 | fprintf(stderr, " %%pc2"); |
151 | if (do_nhm_cstates) | 187 | if (do_nhm_cstates) |
152 | fprintf(stderr, " %%pc3"); | 188 | fprintf(stderr, " %%pc3"); |
153 | if (do_nhm_cstates) | 189 | if (do_nhm_cstates) |
154 | fprintf(stderr, " %%pc6"); | 190 | fprintf(stderr, " %%pc6"); |
155 | if (do_snb_cstates) | 191 | if (do_snb_cstates) |
156 | fprintf(stderr, " %%pc7"); | 192 | fprintf(stderr, " %%pc7"); |
157 | if (extra_msr_offset) | 193 | if (extra_msr_offset) |
158 | fprintf(stderr, " MSR 0x%x ", extra_msr_offset); | 194 | fprintf(stderr, " MSR 0x%x ", extra_msr_offset); |
159 | 195 | ||
@@ -187,6 +223,15 @@ void dump_list(struct counters *cnt) | |||
187 | dump_cnt(cnt); | 223 | dump_cnt(cnt); |
188 | } | 224 | } |
189 | 225 | ||
226 | /* | ||
227 | * column formatting convention & formats | ||
228 | * package: "pk" 2 columns %2d | ||
229 | * core: "cor" 3 columns %3d | ||
230 | * CPU: "CPU" 3 columns %3d | ||
231 | * GHz: "GHz" 3 columns %3.2 | ||
232 | * TSC: "TSC" 3 columns %3.2 | ||
233 | * percentage " %pc3" %6.2 | ||
234 | */ | ||
190 | void print_cnt(struct counters *p) | 235 | void print_cnt(struct counters *p) |
191 | { | 236 | { |
192 | double interval_float; | 237 | double interval_float; |
@@ -196,39 +241,45 @@ void print_cnt(struct counters *p) | |||
196 | /* topology columns, print blanks on 1st (average) line */ | 241 | /* topology columns, print blanks on 1st (average) line */ |
197 | if (p == cnt_average) { | 242 | if (p == cnt_average) { |
198 | if (show_pkg) | 243 | if (show_pkg) |
244 | fprintf(stderr, " "); | ||
245 | if (show_pkg && show_core) | ||
199 | fprintf(stderr, " "); | 246 | fprintf(stderr, " "); |
200 | if (show_core) | 247 | if (show_core) |
201 | fprintf(stderr, " "); | 248 | fprintf(stderr, " "); |
202 | if (show_cpu) | 249 | if (show_cpu) |
203 | fprintf(stderr, " "); | 250 | fprintf(stderr, " " " "); |
204 | } else { | 251 | } else { |
205 | if (show_pkg) | 252 | if (show_pkg) |
206 | fprintf(stderr, "%d", p->pkg); | 253 | fprintf(stderr, "%2d", p->pkg); |
254 | if (show_pkg && show_core) | ||
255 | fprintf(stderr, " "); | ||
207 | if (show_core) | 256 | if (show_core) |
208 | fprintf(stderr, "%4d", p->core); | 257 | fprintf(stderr, "%3d", p->core); |
209 | if (show_cpu) | 258 | if (show_cpu) |
210 | fprintf(stderr, "%4d", p->cpu); | 259 | fprintf(stderr, " %3d", p->cpu); |
211 | } | 260 | } |
212 | 261 | ||
213 | /* %c0 */ | 262 | /* %c0 */ |
214 | if (do_nhm_cstates) { | 263 | if (do_nhm_cstates) { |
264 | if (show_pkg || show_core || show_cpu) | ||
265 | fprintf(stderr, " "); | ||
215 | if (!skip_c0) | 266 | if (!skip_c0) |
216 | fprintf(stderr, "%7.2f", 100.0 * p->mperf/p->tsc); | 267 | fprintf(stderr, "%6.2f", 100.0 * p->mperf/p->tsc); |
217 | else | 268 | else |
218 | fprintf(stderr, " ****"); | 269 | fprintf(stderr, " ****"); |
219 | } | 270 | } |
220 | 271 | ||
221 | /* GHz */ | 272 | /* GHz */ |
222 | if (has_aperf) { | 273 | if (has_aperf) { |
223 | if (!aperf_mperf_unstable) { | 274 | if (!aperf_mperf_unstable) { |
224 | fprintf(stderr, "%5.2f", | 275 | fprintf(stderr, " %3.2f", |
225 | 1.0 * p->tsc / units * p->aperf / | 276 | 1.0 * p->tsc / units * p->aperf / |
226 | p->mperf / interval_float); | 277 | p->mperf / interval_float); |
227 | } else { | 278 | } else { |
228 | if (p->aperf > p->tsc || p->mperf > p->tsc) { | 279 | if (p->aperf > p->tsc || p->mperf > p->tsc) { |
229 | fprintf(stderr, " ****"); | 280 | fprintf(stderr, " ***"); |
230 | } else { | 281 | } else { |
231 | fprintf(stderr, "%4.1f*", | 282 | fprintf(stderr, "%3.1f*", |
232 | 1.0 * p->tsc / | 283 | 1.0 * p->tsc / |
233 | units * p->aperf / | 284 | units * p->aperf / |
234 | p->mperf / interval_float); | 285 | p->mperf / interval_float); |
@@ -241,7 +292,7 @@ void print_cnt(struct counters *p) | |||
241 | 292 | ||
242 | if (do_nhm_cstates) { | 293 | if (do_nhm_cstates) { |
243 | if (!skip_c1) | 294 | if (!skip_c1) |
244 | fprintf(stderr, "%7.2f", 100.0 * p->c1/p->tsc); | 295 | fprintf(stderr, " %6.2f", 100.0 * p->c1/p->tsc); |
245 | else | 296 | else |
246 | fprintf(stderr, " ****"); | 297 | fprintf(stderr, " ****"); |
247 | } | 298 | } |
@@ -252,13 +303,13 @@ void print_cnt(struct counters *p) | |||
252 | if (do_snb_cstates) | 303 | if (do_snb_cstates) |
253 | fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc); | 304 | fprintf(stderr, " %6.2f", 100.0 * p->c7/p->tsc); |
254 | if (do_snb_cstates) | 305 | if (do_snb_cstates) |
255 | fprintf(stderr, " %5.2f", 100.0 * p->pc2/p->tsc); | 306 | fprintf(stderr, " %6.2f", 100.0 * p->pc2/p->tsc); |
256 | if (do_nhm_cstates) | 307 | if (do_nhm_cstates) |
257 | fprintf(stderr, " %5.2f", 100.0 * p->pc3/p->tsc); | 308 | fprintf(stderr, " %6.2f", 100.0 * p->pc3/p->tsc); |
258 | if (do_nhm_cstates) | 309 | if (do_nhm_cstates) |
259 | fprintf(stderr, " %5.2f", 100.0 * p->pc6/p->tsc); | 310 | fprintf(stderr, " %6.2f", 100.0 * p->pc6/p->tsc); |
260 | if (do_snb_cstates) | 311 | if (do_snb_cstates) |
261 | fprintf(stderr, " %5.2f", 100.0 * p->pc7/p->tsc); | 312 | fprintf(stderr, " %6.2f", 100.0 * p->pc7/p->tsc); |
262 | if (extra_msr_offset) | 313 | if (extra_msr_offset) |
263 | fprintf(stderr, " 0x%016llx", p->extra_msr); | 314 | fprintf(stderr, " 0x%016llx", p->extra_msr); |
264 | putc('\n', stderr); | 315 | putc('\n', stderr); |
@@ -267,12 +318,20 @@ void print_cnt(struct counters *p) | |||
267 | void print_counters(struct counters *counters) | 318 | void print_counters(struct counters *counters) |
268 | { | 319 | { |
269 | struct counters *cnt; | 320 | struct counters *cnt; |
321 | static int printed; | ||
322 | |||
270 | 323 | ||
271 | print_header(); | 324 | if (!printed || !summary_only) |
325 | print_header(); | ||
272 | 326 | ||
273 | if (num_cpus > 1) | 327 | if (num_cpus > 1) |
274 | print_cnt(cnt_average); | 328 | print_cnt(cnt_average); |
275 | 329 | ||
330 | printed = 1; | ||
331 | |||
332 | if (summary_only) | ||
333 | return; | ||
334 | |||
276 | for (cnt = counters; cnt != NULL; cnt = cnt->next) | 335 | for (cnt = counters; cnt != NULL; cnt = cnt->next) |
277 | print_cnt(cnt); | 336 | print_cnt(cnt); |
278 | 337 | ||
@@ -440,31 +499,51 @@ void compute_average(struct counters *delta, struct counters *avg) | |||
440 | free(sum); | 499 | free(sum); |
441 | } | 500 | } |
442 | 501 | ||
443 | void get_counters(struct counters *cnt) | 502 | int get_counters(struct counters *cnt) |
444 | { | 503 | { |
445 | for ( ; cnt; cnt = cnt->next) { | 504 | for ( ; cnt; cnt = cnt->next) { |
446 | cnt->tsc = get_msr(cnt->cpu, MSR_TSC); | 505 | |
447 | if (do_nhm_cstates) | 506 | if (cpu_migrate(cnt->cpu)) |
448 | cnt->c3 = get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY); | 507 | return -1; |
449 | if (do_nhm_cstates) | 508 | |
450 | cnt->c6 = get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY); | 509 | if (get_msr(cnt->cpu, MSR_TSC, &cnt->tsc)) |
451 | if (do_snb_cstates) | 510 | return -1; |
452 | cnt->c7 = get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY); | 511 | |
453 | if (has_aperf) | 512 | if (has_aperf) { |
454 | cnt->aperf = get_msr(cnt->cpu, MSR_APERF); | 513 | if (get_msr(cnt->cpu, MSR_APERF, &cnt->aperf)) |
455 | if (has_aperf) | 514 | return -1; |
456 | cnt->mperf = get_msr(cnt->cpu, MSR_MPERF); | 515 | if (get_msr(cnt->cpu, MSR_MPERF, &cnt->mperf)) |
457 | if (do_snb_cstates) | 516 | return -1; |
458 | cnt->pc2 = get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY); | 517 | } |
459 | if (do_nhm_cstates) | 518 | |
460 | cnt->pc3 = get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY); | 519 | if (do_nhm_cstates) { |
461 | if (do_nhm_cstates) | 520 | if (get_msr(cnt->cpu, MSR_CORE_C3_RESIDENCY, &cnt->c3)) |
462 | cnt->pc6 = get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY); | 521 | return -1; |
522 | if (get_msr(cnt->cpu, MSR_CORE_C6_RESIDENCY, &cnt->c6)) | ||
523 | return -1; | ||
524 | } | ||
525 | |||
463 | if (do_snb_cstates) | 526 | if (do_snb_cstates) |
464 | cnt->pc7 = get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY); | 527 | if (get_msr(cnt->cpu, MSR_CORE_C7_RESIDENCY, &cnt->c7)) |
528 | return -1; | ||
529 | |||
530 | if (do_nhm_cstates) { | ||
531 | if (get_msr(cnt->cpu, MSR_PKG_C3_RESIDENCY, &cnt->pc3)) | ||
532 | return -1; | ||
533 | if (get_msr(cnt->cpu, MSR_PKG_C6_RESIDENCY, &cnt->pc6)) | ||
534 | return -1; | ||
535 | } | ||
536 | if (do_snb_cstates) { | ||
537 | if (get_msr(cnt->cpu, MSR_PKG_C2_RESIDENCY, &cnt->pc2)) | ||
538 | return -1; | ||
539 | if (get_msr(cnt->cpu, MSR_PKG_C7_RESIDENCY, &cnt->pc7)) | ||
540 | return -1; | ||
541 | } | ||
465 | if (extra_msr_offset) | 542 | if (extra_msr_offset) |
466 | cnt->extra_msr = get_msr(cnt->cpu, extra_msr_offset); | 543 | if (get_msr(cnt->cpu, extra_msr_offset, &cnt->extra_msr)) |
544 | return -1; | ||
467 | } | 545 | } |
546 | return 0; | ||
468 | } | 547 | } |
469 | 548 | ||
470 | void print_nehalem_info(void) | 549 | void print_nehalem_info(void) |
@@ -475,7 +554,7 @@ void print_nehalem_info(void) | |||
475 | if (!do_nehalem_platform_info) | 554 | if (!do_nehalem_platform_info) |
476 | return; | 555 | return; |
477 | 556 | ||
478 | msr = get_msr(0, MSR_NEHALEM_PLATFORM_INFO); | 557 | get_msr(0, MSR_NEHALEM_PLATFORM_INFO, &msr); |
479 | 558 | ||
480 | ratio = (msr >> 40) & 0xFF; | 559 | ratio = (msr >> 40) & 0xFF; |
481 | fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", | 560 | fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency\n", |
@@ -491,7 +570,7 @@ void print_nehalem_info(void) | |||
491 | if (!do_nehalem_turbo_ratio_limit) | 570 | if (!do_nehalem_turbo_ratio_limit) |
492 | return; | 571 | return; |
493 | 572 | ||
494 | msr = get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT); | 573 | get_msr(0, MSR_NEHALEM_TURBO_RATIO_LIMIT, &msr); |
495 | 574 | ||
496 | ratio = (msr >> 24) & 0xFF; | 575 | ratio = (msr >> 24) & 0xFF; |
497 | if (ratio) | 576 | if (ratio) |
@@ -557,7 +636,8 @@ void insert_counters(struct counters **list, | |||
557 | return; | 636 | return; |
558 | } | 637 | } |
559 | 638 | ||
560 | show_cpu = 1; /* there is more than one CPU */ | 639 | if (!summary_only) |
640 | show_cpu = 1; /* there is more than one CPU */ | ||
561 | 641 | ||
562 | /* | 642 | /* |
563 | * insert on front of list. | 643 | * insert on front of list. |
@@ -575,13 +655,15 @@ void insert_counters(struct counters **list, | |||
575 | 655 | ||
576 | while (prev->next && (prev->next->pkg < new->pkg)) { | 656 | while (prev->next && (prev->next->pkg < new->pkg)) { |
577 | prev = prev->next; | 657 | prev = prev->next; |
578 | show_pkg = 1; /* there is more than 1 package */ | 658 | if (!summary_only) |
659 | show_pkg = 1; /* there is more than 1 package */ | ||
579 | } | 660 | } |
580 | 661 | ||
581 | while (prev->next && (prev->next->pkg == new->pkg) | 662 | while (prev->next && (prev->next->pkg == new->pkg) |
582 | && (prev->next->core < new->core)) { | 663 | && (prev->next->core < new->core)) { |
583 | prev = prev->next; | 664 | prev = prev->next; |
584 | show_core = 1; /* there is more than 1 core */ | 665 | if (!summary_only) |
666 | show_core = 1; /* there is more than 1 core */ | ||
585 | } | 667 | } |
586 | 668 | ||
587 | while (prev->next && (prev->next->pkg == new->pkg) | 669 | while (prev->next && (prev->next->pkg == new->pkg) |
@@ -681,7 +763,7 @@ int get_core_id(int cpu) | |||
681 | } | 763 | } |
682 | 764 | ||
683 | /* | 765 | /* |
684 | * run func(index, cpu) on every cpu in /proc/stat | 766 | * run func(pkg, core, cpu) on every cpu in /proc/stat |
685 | */ | 767 | */ |
686 | 768 | ||
687 | int for_all_cpus(void (func)(int, int, int)) | 769 | int for_all_cpus(void (func)(int, int, int)) |
@@ -717,18 +799,18 @@ int for_all_cpus(void (func)(int, int, int)) | |||
717 | 799 | ||
718 | void re_initialize(void) | 800 | void re_initialize(void) |
719 | { | 801 | { |
720 | printf("turbostat: topology changed, re-initializing.\n"); | ||
721 | free_all_counters(); | 802 | free_all_counters(); |
722 | num_cpus = for_all_cpus(alloc_new_counters); | 803 | num_cpus = for_all_cpus(alloc_new_counters); |
723 | need_reinitialize = 0; | 804 | cpu_mask_uninit(); |
724 | printf("num_cpus is now %d\n", num_cpus); | 805 | cpu_mask_init(num_cpus); |
806 | printf("turbostat: re-initialized with num_cpus %d\n", num_cpus); | ||
725 | } | 807 | } |
726 | 808 | ||
727 | void dummy(int pkg, int core, int cpu) { return; } | 809 | void dummy(int pkg, int core, int cpu) { return; } |
728 | /* | 810 | /* |
729 | * check to see if a cpu came on-line | 811 | * check to see if a cpu came on-line |
730 | */ | 812 | */ |
731 | void verify_num_cpus(void) | 813 | int verify_num_cpus(void) |
732 | { | 814 | { |
733 | int new_num_cpus; | 815 | int new_num_cpus; |
734 | 816 | ||
@@ -738,8 +820,9 @@ void verify_num_cpus(void) | |||
738 | if (verbose) | 820 | if (verbose) |
739 | printf("num_cpus was %d, is now %d\n", | 821 | printf("num_cpus was %d, is now %d\n", |
740 | num_cpus, new_num_cpus); | 822 | num_cpus, new_num_cpus); |
741 | need_reinitialize = 1; | 823 | return -1; |
742 | } | 824 | } |
825 | return 0; | ||
743 | } | 826 | } |
744 | 827 | ||
745 | void turbostat_loop() | 828 | void turbostat_loop() |
@@ -749,25 +832,25 @@ restart: | |||
749 | gettimeofday(&tv_even, (struct timezone *)NULL); | 832 | gettimeofday(&tv_even, (struct timezone *)NULL); |
750 | 833 | ||
751 | while (1) { | 834 | while (1) { |
752 | verify_num_cpus(); | 835 | if (verify_num_cpus()) { |
753 | if (need_reinitialize) { | ||
754 | re_initialize(); | 836 | re_initialize(); |
755 | goto restart; | 837 | goto restart; |
756 | } | 838 | } |
757 | sleep(interval_sec); | 839 | sleep(interval_sec); |
758 | get_counters(cnt_odd); | 840 | if (get_counters(cnt_odd)) { |
841 | re_initialize(); | ||
842 | goto restart; | ||
843 | } | ||
759 | gettimeofday(&tv_odd, (struct timezone *)NULL); | 844 | gettimeofday(&tv_odd, (struct timezone *)NULL); |
760 | |||
761 | compute_delta(cnt_odd, cnt_even, cnt_delta); | 845 | compute_delta(cnt_odd, cnt_even, cnt_delta); |
762 | timersub(&tv_odd, &tv_even, &tv_delta); | 846 | timersub(&tv_odd, &tv_even, &tv_delta); |
763 | compute_average(cnt_delta, cnt_average); | 847 | compute_average(cnt_delta, cnt_average); |
764 | print_counters(cnt_delta); | 848 | print_counters(cnt_delta); |
765 | if (need_reinitialize) { | 849 | sleep(interval_sec); |
850 | if (get_counters(cnt_even)) { | ||
766 | re_initialize(); | 851 | re_initialize(); |
767 | goto restart; | 852 | goto restart; |
768 | } | 853 | } |
769 | sleep(interval_sec); | ||
770 | get_counters(cnt_even); | ||
771 | gettimeofday(&tv_even, (struct timezone *)NULL); | 854 | gettimeofday(&tv_even, (struct timezone *)NULL); |
772 | compute_delta(cnt_even, cnt_odd, cnt_delta); | 855 | compute_delta(cnt_even, cnt_odd, cnt_delta); |
773 | timersub(&tv_even, &tv_odd, &tv_delta); | 856 | timersub(&tv_even, &tv_odd, &tv_delta); |
@@ -953,6 +1036,7 @@ void turbostat_init() | |||
953 | check_super_user(); | 1036 | check_super_user(); |
954 | 1037 | ||
955 | num_cpus = for_all_cpus(alloc_new_counters); | 1038 | num_cpus = for_all_cpus(alloc_new_counters); |
1039 | cpu_mask_init(num_cpus); | ||
956 | 1040 | ||
957 | if (verbose) | 1041 | if (verbose) |
958 | print_nehalem_info(); | 1042 | print_nehalem_info(); |
@@ -1005,8 +1089,11 @@ void cmdline(int argc, char **argv) | |||
1005 | 1089 | ||
1006 | progname = argv[0]; | 1090 | progname = argv[0]; |
1007 | 1091 | ||
1008 | while ((opt = getopt(argc, argv, "+vi:M:")) != -1) { | 1092 | while ((opt = getopt(argc, argv, "+svi:M:")) != -1) { |
1009 | switch (opt) { | 1093 | switch (opt) { |
1094 | case 's': | ||
1095 | summary_only++; | ||
1096 | break; | ||
1010 | case 'v': | 1097 | case 'v': |
1011 | verbose++; | 1098 | verbose++; |
1012 | break; | 1099 | break; |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 4ec84018cc13..28bc57ee757c 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -1,10 +1,15 @@ | |||
1 | TARGETS = breakpoints | 1 | TARGETS = breakpoints vm |
2 | 2 | ||
3 | all: | 3 | all: |
4 | for TARGET in $(TARGETS); do \ | 4 | for TARGET in $(TARGETS); do \ |
5 | make -C $$TARGET; \ | 5 | make -C $$TARGET; \ |
6 | done; | 6 | done; |
7 | 7 | ||
8 | run_tests: all | ||
9 | for TARGET in $(TARGETS); do \ | ||
10 | make -C $$TARGET run_tests; \ | ||
11 | done; | ||
12 | |||
8 | clean: | 13 | clean: |
9 | for TARGET in $(TARGETS); do \ | 14 | for TARGET in $(TARGETS); do \ |
10 | make -C $$TARGET clean; \ | 15 | make -C $$TARGET clean; \ |
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile index f362722cdce7..931278035f5c 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile | |||
@@ -11,10 +11,13 @@ endif | |||
11 | 11 | ||
12 | all: | 12 | all: |
13 | ifeq ($(ARCH),x86) | 13 | ifeq ($(ARCH),x86) |
14 | gcc breakpoint_test.c -o run_test | 14 | gcc breakpoint_test.c -o breakpoint_test |
15 | else | 15 | else |
16 | echo "Not an x86 target, can't build breakpoints selftests" | 16 | echo "Not an x86 target, can't build breakpoints selftests" |
17 | endif | 17 | endif |
18 | 18 | ||
19 | run_tests: | ||
20 | ./breakpoint_test | ||
21 | |||
19 | clean: | 22 | clean: |
20 | rm -fr run_test | 23 | rm -fr breakpoint_test |
diff --git a/tools/testing/selftests/run_tests b/tools/testing/selftests/run_tests deleted file mode 100644 index 320718a4e6bf..000000000000 --- a/tools/testing/selftests/run_tests +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | TARGETS=breakpoints | ||
4 | |||
5 | for TARGET in $TARGETS | ||
6 | do | ||
7 | $TARGET/run_test | ||
8 | done | ||
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile new file mode 100644 index 000000000000..b336b24aa6c0 --- /dev/null +++ b/tools/testing/selftests/vm/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | # Makefile for vm selftests | ||
2 | |||
3 | CC = $(CROSS_COMPILE)gcc | ||
4 | CFLAGS = -Wall -Wextra | ||
5 | |||
6 | all: hugepage-mmap hugepage-shm map_hugetlb | ||
7 | %: %.c | ||
8 | $(CC) $(CFLAGS) -o $@ $^ | ||
9 | |||
10 | run_tests: all | ||
11 | /bin/sh ./run_vmtests | ||
12 | |||
13 | clean: | ||
14 | $(RM) hugepage-mmap hugepage-shm map_hugetlb | ||
diff --git a/tools/testing/selftests/vm/hugepage-mmap.c b/tools/testing/selftests/vm/hugepage-mmap.c new file mode 100644 index 000000000000..a10f310d2362 --- /dev/null +++ b/tools/testing/selftests/vm/hugepage-mmap.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * hugepage-mmap: | ||
3 | * | ||
4 | * Example of using huge page memory in a user application using the mmap | ||
5 | * system call. Before running this application, make sure that the | ||
6 | * administrator has mounted the hugetlbfs filesystem (on some directory | ||
7 | * like /mnt) using the command mount -t hugetlbfs nodev /mnt. In this | ||
8 | * example, the app is requesting memory of size 256MB that is backed by | ||
9 | * huge pages. | ||
10 | * | ||
11 | * For the ia64 architecture, the Linux kernel reserves Region number 4 for | ||
12 | * huge pages. That means that if one requires a fixed address, a huge page | ||
13 | * aligned address starting with 0x800000... will be required. If a fixed | ||
14 | * address is not required, the kernel will select an address in the proper | ||
15 | * range. | ||
16 | * Other architectures, such as ppc64, i386 or x86_64 are not so constrained. | ||
17 | */ | ||
18 | |||
19 | #include <stdlib.h> | ||
20 | #include <stdio.h> | ||
21 | #include <unistd.h> | ||
22 | #include <sys/mman.h> | ||
23 | #include <fcntl.h> | ||
24 | |||
25 | #define FILE_NAME "huge/hugepagefile" | ||
26 | #define LENGTH (256UL*1024*1024) | ||
27 | #define PROTECTION (PROT_READ | PROT_WRITE) | ||
28 | |||
29 | /* Only ia64 requires this */ | ||
30 | #ifdef __ia64__ | ||
31 | #define ADDR (void *)(0x8000000000000000UL) | ||
32 | #define FLAGS (MAP_SHARED | MAP_FIXED) | ||
33 | #else | ||
34 | #define ADDR (void *)(0x0UL) | ||
35 | #define FLAGS (MAP_SHARED) | ||
36 | #endif | ||
37 | |||
38 | static void check_bytes(char *addr) | ||
39 | { | ||
40 | printf("First hex is %x\n", *((unsigned int *)addr)); | ||
41 | } | ||
42 | |||
43 | static void write_bytes(char *addr) | ||
44 | { | ||
45 | unsigned long i; | ||
46 | |||
47 | for (i = 0; i < LENGTH; i++) | ||
48 | *(addr + i) = (char)i; | ||
49 | } | ||
50 | |||
51 | static int read_bytes(char *addr) | ||
52 | { | ||
53 | unsigned long i; | ||
54 | |||
55 | check_bytes(addr); | ||
56 | for (i = 0; i < LENGTH; i++) | ||
57 | if (*(addr + i) != (char)i) { | ||
58 | printf("Mismatch at %lu\n", i); | ||
59 | return 1; | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | int main(void) | ||
65 | { | ||
66 | void *addr; | ||
67 | int fd, ret; | ||
68 | |||
69 | fd = open(FILE_NAME, O_CREAT | O_RDWR, 0755); | ||
70 | if (fd < 0) { | ||
71 | perror("Open failed"); | ||
72 | exit(1); | ||
73 | } | ||
74 | |||
75 | addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, fd, 0); | ||
76 | if (addr == MAP_FAILED) { | ||
77 | perror("mmap"); | ||
78 | unlink(FILE_NAME); | ||
79 | exit(1); | ||
80 | } | ||
81 | |||
82 | printf("Returned address is %p\n", addr); | ||
83 | check_bytes(addr); | ||
84 | write_bytes(addr); | ||
85 | ret = read_bytes(addr); | ||
86 | |||
87 | munmap(addr, LENGTH); | ||
88 | close(fd); | ||
89 | unlink(FILE_NAME); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
diff --git a/tools/testing/selftests/vm/hugepage-shm.c b/tools/testing/selftests/vm/hugepage-shm.c new file mode 100644 index 000000000000..0d0ef4fc0c04 --- /dev/null +++ b/tools/testing/selftests/vm/hugepage-shm.c | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * hugepage-shm: | ||
3 | * | ||
4 | * Example of using huge page memory in a user application using Sys V shared | ||
5 | * memory system calls. In this example the app is requesting 256MB of | ||
6 | * memory that is backed by huge pages. The application uses the flag | ||
7 | * SHM_HUGETLB in the shmget system call to inform the kernel that it is | ||
8 | * requesting huge pages. | ||
9 | * | ||
10 | * For the ia64 architecture, the Linux kernel reserves Region number 4 for | ||
11 | * huge pages. That means that if one requires a fixed address, a huge page | ||
12 | * aligned address starting with 0x800000... will be required. If a fixed | ||
13 | * address is not required, the kernel will select an address in the proper | ||
14 | * range. | ||
15 | * Other architectures, such as ppc64, i386 or x86_64 are not so constrained. | ||
16 | * | ||
17 | * Note: The default shared memory limit is quite low on many kernels, | ||
18 | * you may need to increase it via: | ||
19 | * | ||
20 | * echo 268435456 > /proc/sys/kernel/shmmax | ||
21 | * | ||
22 | * This will increase the maximum size per shared memory segment to 256MB. | ||
23 | * The other limit that you will hit eventually is shmall which is the | ||
24 | * total amount of shared memory in pages. To set it to 16GB on a system | ||
25 | * with a 4kB pagesize do: | ||
26 | * | ||
27 | * echo 4194304 > /proc/sys/kernel/shmall | ||
28 | */ | ||
29 | |||
30 | #include <stdlib.h> | ||
31 | #include <stdio.h> | ||
32 | #include <sys/types.h> | ||
33 | #include <sys/ipc.h> | ||
34 | #include <sys/shm.h> | ||
35 | #include <sys/mman.h> | ||
36 | |||
37 | #ifndef SHM_HUGETLB | ||
38 | #define SHM_HUGETLB 04000 | ||
39 | #endif | ||
40 | |||
41 | #define LENGTH (256UL*1024*1024) | ||
42 | |||
43 | #define dprintf(x) printf(x) | ||
44 | |||
45 | /* Only ia64 requires this */ | ||
46 | #ifdef __ia64__ | ||
47 | #define ADDR (void *)(0x8000000000000000UL) | ||
48 | #define SHMAT_FLAGS (SHM_RND) | ||
49 | #else | ||
50 | #define ADDR (void *)(0x0UL) | ||
51 | #define SHMAT_FLAGS (0) | ||
52 | #endif | ||
53 | |||
54 | int main(void) | ||
55 | { | ||
56 | int shmid; | ||
57 | unsigned long i; | ||
58 | char *shmaddr; | ||
59 | |||
60 | shmid = shmget(2, LENGTH, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W); | ||
61 | if (shmid < 0) { | ||
62 | perror("shmget"); | ||
63 | exit(1); | ||
64 | } | ||
65 | printf("shmid: 0x%x\n", shmid); | ||
66 | |||
67 | shmaddr = shmat(shmid, ADDR, SHMAT_FLAGS); | ||
68 | if (shmaddr == (char *)-1) { | ||
69 | perror("Shared memory attach failure"); | ||
70 | shmctl(shmid, IPC_RMID, NULL); | ||
71 | exit(2); | ||
72 | } | ||
73 | printf("shmaddr: %p\n", shmaddr); | ||
74 | |||
75 | dprintf("Starting the writes:\n"); | ||
76 | for (i = 0; i < LENGTH; i++) { | ||
77 | shmaddr[i] = (char)(i); | ||
78 | if (!(i % (1024 * 1024))) | ||
79 | dprintf("."); | ||
80 | } | ||
81 | dprintf("\n"); | ||
82 | |||
83 | dprintf("Starting the Check..."); | ||
84 | for (i = 0; i < LENGTH; i++) | ||
85 | if (shmaddr[i] != (char)i) { | ||
86 | printf("\nIndex %lu mismatched\n", i); | ||
87 | exit(3); | ||
88 | } | ||
89 | dprintf("Done.\n"); | ||
90 | |||
91 | if (shmdt((const void *)shmaddr) != 0) { | ||
92 | perror("Detach failure"); | ||
93 | shmctl(shmid, IPC_RMID, NULL); | ||
94 | exit(4); | ||
95 | } | ||
96 | |||
97 | shmctl(shmid, IPC_RMID, NULL); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
diff --git a/tools/testing/selftests/vm/map_hugetlb.c b/tools/testing/selftests/vm/map_hugetlb.c new file mode 100644 index 000000000000..ac56639dd4a9 --- /dev/null +++ b/tools/testing/selftests/vm/map_hugetlb.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * Example of using hugepage memory in a user application using the mmap | ||
3 | * system call with MAP_HUGETLB flag. Before running this program make | ||
4 | * sure the administrator has allocated enough default sized huge pages | ||
5 | * to cover the 256 MB allocation. | ||
6 | * | ||
7 | * For ia64 architecture, Linux kernel reserves Region number 4 for hugepages. | ||
8 | * That means the addresses starting with 0x800000... will need to be | ||
9 | * specified. Specifying a fixed address is not required on ppc64, i386 | ||
10 | * or x86_64. | ||
11 | */ | ||
12 | #include <stdlib.h> | ||
13 | #include <stdio.h> | ||
14 | #include <unistd.h> | ||
15 | #include <sys/mman.h> | ||
16 | #include <fcntl.h> | ||
17 | |||
18 | #define LENGTH (256UL*1024*1024) | ||
19 | #define PROTECTION (PROT_READ | PROT_WRITE) | ||
20 | |||
21 | #ifndef MAP_HUGETLB | ||
22 | #define MAP_HUGETLB 0x40000 /* arch specific */ | ||
23 | #endif | ||
24 | |||
25 | /* Only ia64 requires this */ | ||
26 | #ifdef __ia64__ | ||
27 | #define ADDR (void *)(0x8000000000000000UL) | ||
28 | #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_FIXED) | ||
29 | #else | ||
30 | #define ADDR (void *)(0x0UL) | ||
31 | #define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB) | ||
32 | #endif | ||
33 | |||
34 | static void check_bytes(char *addr) | ||
35 | { | ||
36 | printf("First hex is %x\n", *((unsigned int *)addr)); | ||
37 | } | ||
38 | |||
39 | static void write_bytes(char *addr) | ||
40 | { | ||
41 | unsigned long i; | ||
42 | |||
43 | for (i = 0; i < LENGTH; i++) | ||
44 | *(addr + i) = (char)i; | ||
45 | } | ||
46 | |||
47 | static int read_bytes(char *addr) | ||
48 | { | ||
49 | unsigned long i; | ||
50 | |||
51 | check_bytes(addr); | ||
52 | for (i = 0; i < LENGTH; i++) | ||
53 | if (*(addr + i) != (char)i) { | ||
54 | printf("Mismatch at %lu\n", i); | ||
55 | return 1; | ||
56 | } | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | int main(void) | ||
61 | { | ||
62 | void *addr; | ||
63 | int ret; | ||
64 | |||
65 | addr = mmap(ADDR, LENGTH, PROTECTION, FLAGS, 0, 0); | ||
66 | if (addr == MAP_FAILED) { | ||
67 | perror("mmap"); | ||
68 | exit(1); | ||
69 | } | ||
70 | |||
71 | printf("Returned address is %p\n", addr); | ||
72 | check_bytes(addr); | ||
73 | write_bytes(addr); | ||
74 | ret = read_bytes(addr); | ||
75 | |||
76 | munmap(addr, LENGTH); | ||
77 | |||
78 | return ret; | ||
79 | } | ||
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests new file mode 100644 index 000000000000..8b40bd5e5cc2 --- /dev/null +++ b/tools/testing/selftests/vm/run_vmtests | |||
@@ -0,0 +1,77 @@ | |||
1 | #!/bin/bash | ||
2 | #please run as root | ||
3 | |||
4 | #we need 256M, below is the size in kB | ||
5 | needmem=262144 | ||
6 | mnt=./huge | ||
7 | |||
8 | #get pagesize and freepages from /proc/meminfo | ||
9 | while read name size unit; do | ||
10 | if [ "$name" = "HugePages_Free:" ]; then | ||
11 | freepgs=$size | ||
12 | fi | ||
13 | if [ "$name" = "Hugepagesize:" ]; then | ||
14 | pgsize=$size | ||
15 | fi | ||
16 | done < /proc/meminfo | ||
17 | |||
18 | #set proper nr_hugepages | ||
19 | if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then | ||
20 | nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` | ||
21 | needpgs=`expr $needmem / $pgsize` | ||
22 | if [ $freepgs -lt $needpgs ]; then | ||
23 | lackpgs=$(( $needpgs - $freepgs )) | ||
24 | echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages | ||
25 | if [ $? -ne 0 ]; then | ||
26 | echo "Please run this test as root" | ||
27 | exit 1 | ||
28 | fi | ||
29 | fi | ||
30 | else | ||
31 | echo "no hugetlbfs support in kernel?" | ||
32 | exit 1 | ||
33 | fi | ||
34 | |||
35 | mkdir $mnt | ||
36 | mount -t hugetlbfs none $mnt | ||
37 | |||
38 | echo "--------------------" | ||
39 | echo "runing hugepage-mmap" | ||
40 | echo "--------------------" | ||
41 | ./hugepage-mmap | ||
42 | if [ $? -ne 0 ]; then | ||
43 | echo "[FAIL]" | ||
44 | else | ||
45 | echo "[PASS]" | ||
46 | fi | ||
47 | |||
48 | shmmax=`cat /proc/sys/kernel/shmmax` | ||
49 | shmall=`cat /proc/sys/kernel/shmall` | ||
50 | echo 268435456 > /proc/sys/kernel/shmmax | ||
51 | echo 4194304 > /proc/sys/kernel/shmall | ||
52 | echo "--------------------" | ||
53 | echo "runing hugepage-shm" | ||
54 | echo "--------------------" | ||
55 | ./hugepage-shm | ||
56 | if [ $? -ne 0 ]; then | ||
57 | echo "[FAIL]" | ||
58 | else | ||
59 | echo "[PASS]" | ||
60 | fi | ||
61 | echo $shmmax > /proc/sys/kernel/shmmax | ||
62 | echo $shmall > /proc/sys/kernel/shmall | ||
63 | |||
64 | echo "--------------------" | ||
65 | echo "runing map_hugetlb" | ||
66 | echo "--------------------" | ||
67 | ./map_hugetlb | ||
68 | if [ $? -ne 0 ]; then | ||
69 | echo "[FAIL]" | ||
70 | else | ||
71 | echo "[PASS]" | ||
72 | fi | ||
73 | |||
74 | #cleanup | ||
75 | umount $mnt | ||
76 | rm -rf $mnt | ||
77 | echo $nr_hugepgs > /proc/sys/vm/nr_hugepages | ||
diff --git a/tools/virtio/linux/hrtimer.h b/tools/virtio/linux/hrtimer.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/virtio/linux/hrtimer.h | |||
diff --git a/tools/virtio/linux/module.h b/tools/virtio/linux/module.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/virtio/linux/module.h | |||
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h index b4fbc91c41b4..7579f19e61e0 100644 --- a/tools/virtio/linux/virtio.h +++ b/tools/virtio/linux/virtio.h | |||
@@ -181,6 +181,9 @@ struct virtqueue { | |||
181 | #define smp_mb() mb() | 181 | #define smp_mb() mb() |
182 | # define smp_rmb() barrier() | 182 | # define smp_rmb() barrier() |
183 | # define smp_wmb() barrier() | 183 | # define smp_wmb() barrier() |
184 | /* Weak barriers should be used. If not - it's a bug */ | ||
185 | # define rmb() abort() | ||
186 | # define wmb() abort() | ||
184 | #else | 187 | #else |
185 | #error Please fill in barrier macros | 188 | #error Please fill in barrier macros |
186 | #endif | 189 | #endif |
diff --git a/tools/vm/Makefile b/tools/vm/Makefile new file mode 100644 index 000000000000..8e30e5c40f8a --- /dev/null +++ b/tools/vm/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | # Makefile for vm tools | ||
2 | |||
3 | CC = $(CROSS_COMPILE)gcc | ||
4 | CFLAGS = -Wall -Wextra | ||
5 | |||
6 | all: page-types slabinfo | ||
7 | %: %.c | ||
8 | $(CC) $(CFLAGS) -o $@ $^ | ||
9 | |||
10 | clean: | ||
11 | $(RM) page-types slabinfo | ||
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c new file mode 100644 index 000000000000..7dab7b25b5c6 --- /dev/null +++ b/tools/vm/page-types.c | |||
@@ -0,0 +1,1102 @@ | |||
1 | /* | ||
2 | * page-types: Tool for querying page flags | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the Free | ||
6 | * Software Foundation; version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should find a copy of v2 of the GNU General Public License somewhere on | ||
14 | * your Linux system; if not, write to the Free Software Foundation, Inc., 59 | ||
15 | * Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
16 | * | ||
17 | * Copyright (C) 2009 Intel corporation | ||
18 | * | ||
19 | * Authors: Wu Fengguang <fengguang.wu@intel.com> | ||
20 | */ | ||
21 | |||
22 | #define _LARGEFILE64_SOURCE | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <unistd.h> | ||
26 | #include <stdint.h> | ||
27 | #include <stdarg.h> | ||
28 | #include <string.h> | ||
29 | #include <getopt.h> | ||
30 | #include <limits.h> | ||
31 | #include <assert.h> | ||
32 | #include <sys/types.h> | ||
33 | #include <sys/errno.h> | ||
34 | #include <sys/fcntl.h> | ||
35 | #include <sys/mount.h> | ||
36 | #include <sys/statfs.h> | ||
37 | #include "../../include/linux/magic.h" | ||
38 | |||
39 | |||
40 | #ifndef MAX_PATH | ||
41 | # define MAX_PATH 256 | ||
42 | #endif | ||
43 | |||
44 | #ifndef STR | ||
45 | # define _STR(x) #x | ||
46 | # define STR(x) _STR(x) | ||
47 | #endif | ||
48 | |||
49 | /* | ||
50 | * pagemap kernel ABI bits | ||
51 | */ | ||
52 | |||
53 | #define PM_ENTRY_BYTES sizeof(uint64_t) | ||
54 | #define PM_STATUS_BITS 3 | ||
55 | #define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) | ||
56 | #define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET) | ||
57 | #define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK) | ||
58 | #define PM_PSHIFT_BITS 6 | ||
59 | #define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) | ||
60 | #define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) | ||
61 | #define PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) | ||
62 | #define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) | ||
63 | #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) | ||
64 | |||
65 | #define PM_PRESENT PM_STATUS(4LL) | ||
66 | #define PM_SWAP PM_STATUS(2LL) | ||
67 | |||
68 | |||
69 | /* | ||
70 | * kernel page flags | ||
71 | */ | ||
72 | |||
73 | #define KPF_BYTES 8 | ||
74 | #define PROC_KPAGEFLAGS "/proc/kpageflags" | ||
75 | |||
76 | /* copied from kpageflags_read() */ | ||
77 | #define KPF_LOCKED 0 | ||
78 | #define KPF_ERROR 1 | ||
79 | #define KPF_REFERENCED 2 | ||
80 | #define KPF_UPTODATE 3 | ||
81 | #define KPF_DIRTY 4 | ||
82 | #define KPF_LRU 5 | ||
83 | #define KPF_ACTIVE 6 | ||
84 | #define KPF_SLAB 7 | ||
85 | #define KPF_WRITEBACK 8 | ||
86 | #define KPF_RECLAIM 9 | ||
87 | #define KPF_BUDDY 10 | ||
88 | |||
89 | /* [11-20] new additions in 2.6.31 */ | ||
90 | #define KPF_MMAP 11 | ||
91 | #define KPF_ANON 12 | ||
92 | #define KPF_SWAPCACHE 13 | ||
93 | #define KPF_SWAPBACKED 14 | ||
94 | #define KPF_COMPOUND_HEAD 15 | ||
95 | #define KPF_COMPOUND_TAIL 16 | ||
96 | #define KPF_HUGE 17 | ||
97 | #define KPF_UNEVICTABLE 18 | ||
98 | #define KPF_HWPOISON 19 | ||
99 | #define KPF_NOPAGE 20 | ||
100 | #define KPF_KSM 21 | ||
101 | #define KPF_THP 22 | ||
102 | |||
103 | /* [32-] kernel hacking assistances */ | ||
104 | #define KPF_RESERVED 32 | ||
105 | #define KPF_MLOCKED 33 | ||
106 | #define KPF_MAPPEDTODISK 34 | ||
107 | #define KPF_PRIVATE 35 | ||
108 | #define KPF_PRIVATE_2 36 | ||
109 | #define KPF_OWNER_PRIVATE 37 | ||
110 | #define KPF_ARCH 38 | ||
111 | #define KPF_UNCACHED 39 | ||
112 | |||
113 | /* [48-] take some arbitrary free slots for expanding overloaded flags | ||
114 | * not part of kernel API | ||
115 | */ | ||
116 | #define KPF_READAHEAD 48 | ||
117 | #define KPF_SLOB_FREE 49 | ||
118 | #define KPF_SLUB_FROZEN 50 | ||
119 | #define KPF_SLUB_DEBUG 51 | ||
120 | |||
121 | #define KPF_ALL_BITS ((uint64_t)~0ULL) | ||
122 | #define KPF_HACKERS_BITS (0xffffULL << 32) | ||
123 | #define KPF_OVERLOADED_BITS (0xffffULL << 48) | ||
124 | #define BIT(name) (1ULL << KPF_##name) | ||
125 | #define BITS_COMPOUND (BIT(COMPOUND_HEAD) | BIT(COMPOUND_TAIL)) | ||
126 | |||
127 | static const char * const page_flag_names[] = { | ||
128 | [KPF_LOCKED] = "L:locked", | ||
129 | [KPF_ERROR] = "E:error", | ||
130 | [KPF_REFERENCED] = "R:referenced", | ||
131 | [KPF_UPTODATE] = "U:uptodate", | ||
132 | [KPF_DIRTY] = "D:dirty", | ||
133 | [KPF_LRU] = "l:lru", | ||
134 | [KPF_ACTIVE] = "A:active", | ||
135 | [KPF_SLAB] = "S:slab", | ||
136 | [KPF_WRITEBACK] = "W:writeback", | ||
137 | [KPF_RECLAIM] = "I:reclaim", | ||
138 | [KPF_BUDDY] = "B:buddy", | ||
139 | |||
140 | [KPF_MMAP] = "M:mmap", | ||
141 | [KPF_ANON] = "a:anonymous", | ||
142 | [KPF_SWAPCACHE] = "s:swapcache", | ||
143 | [KPF_SWAPBACKED] = "b:swapbacked", | ||
144 | [KPF_COMPOUND_HEAD] = "H:compound_head", | ||
145 | [KPF_COMPOUND_TAIL] = "T:compound_tail", | ||
146 | [KPF_HUGE] = "G:huge", | ||
147 | [KPF_UNEVICTABLE] = "u:unevictable", | ||
148 | [KPF_HWPOISON] = "X:hwpoison", | ||
149 | [KPF_NOPAGE] = "n:nopage", | ||
150 | [KPF_KSM] = "x:ksm", | ||
151 | [KPF_THP] = "t:thp", | ||
152 | |||
153 | [KPF_RESERVED] = "r:reserved", | ||
154 | [KPF_MLOCKED] = "m:mlocked", | ||
155 | [KPF_MAPPEDTODISK] = "d:mappedtodisk", | ||
156 | [KPF_PRIVATE] = "P:private", | ||
157 | [KPF_PRIVATE_2] = "p:private_2", | ||
158 | [KPF_OWNER_PRIVATE] = "O:owner_private", | ||
159 | [KPF_ARCH] = "h:arch", | ||
160 | [KPF_UNCACHED] = "c:uncached", | ||
161 | |||
162 | [KPF_READAHEAD] = "I:readahead", | ||
163 | [KPF_SLOB_FREE] = "P:slob_free", | ||
164 | [KPF_SLUB_FROZEN] = "A:slub_frozen", | ||
165 | [KPF_SLUB_DEBUG] = "E:slub_debug", | ||
166 | }; | ||
167 | |||
168 | |||
169 | static const char * const debugfs_known_mountpoints[] = { | ||
170 | "/sys/kernel/debug", | ||
171 | "/debug", | ||
172 | 0, | ||
173 | }; | ||
174 | |||
175 | /* | ||
176 | * data structures | ||
177 | */ | ||
178 | |||
179 | static int opt_raw; /* for kernel developers */ | ||
180 | static int opt_list; /* list pages (in ranges) */ | ||
181 | static int opt_no_summary; /* don't show summary */ | ||
182 | static pid_t opt_pid; /* process to walk */ | ||
183 | |||
184 | #define MAX_ADDR_RANGES 1024 | ||
185 | static int nr_addr_ranges; | ||
186 | static unsigned long opt_offset[MAX_ADDR_RANGES]; | ||
187 | static unsigned long opt_size[MAX_ADDR_RANGES]; | ||
188 | |||
189 | #define MAX_VMAS 10240 | ||
190 | static int nr_vmas; | ||
191 | static unsigned long pg_start[MAX_VMAS]; | ||
192 | static unsigned long pg_end[MAX_VMAS]; | ||
193 | |||
194 | #define MAX_BIT_FILTERS 64 | ||
195 | static int nr_bit_filters; | ||
196 | static uint64_t opt_mask[MAX_BIT_FILTERS]; | ||
197 | static uint64_t opt_bits[MAX_BIT_FILTERS]; | ||
198 | |||
199 | static int page_size; | ||
200 | |||
201 | static int pagemap_fd; | ||
202 | static int kpageflags_fd; | ||
203 | |||
204 | static int opt_hwpoison; | ||
205 | static int opt_unpoison; | ||
206 | |||
207 | static char hwpoison_debug_fs[MAX_PATH+1]; | ||
208 | static int hwpoison_inject_fd; | ||
209 | static int hwpoison_forget_fd; | ||
210 | |||
211 | #define HASH_SHIFT 13 | ||
212 | #define HASH_SIZE (1 << HASH_SHIFT) | ||
213 | #define HASH_MASK (HASH_SIZE - 1) | ||
214 | #define HASH_KEY(flags) (flags & HASH_MASK) | ||
215 | |||
216 | static unsigned long total_pages; | ||
217 | static unsigned long nr_pages[HASH_SIZE]; | ||
218 | static uint64_t page_flags[HASH_SIZE]; | ||
219 | |||
220 | |||
221 | /* | ||
222 | * helper functions | ||
223 | */ | ||
224 | |||
225 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
226 | |||
227 | #define min_t(type, x, y) ({ \ | ||
228 | type __min1 = (x); \ | ||
229 | type __min2 = (y); \ | ||
230 | __min1 < __min2 ? __min1 : __min2; }) | ||
231 | |||
232 | #define max_t(type, x, y) ({ \ | ||
233 | type __max1 = (x); \ | ||
234 | type __max2 = (y); \ | ||
235 | __max1 > __max2 ? __max1 : __max2; }) | ||
236 | |||
237 | static unsigned long pages2mb(unsigned long pages) | ||
238 | { | ||
239 | return (pages * page_size) >> 20; | ||
240 | } | ||
241 | |||
242 | static void fatal(const char *x, ...) | ||
243 | { | ||
244 | va_list ap; | ||
245 | |||
246 | va_start(ap, x); | ||
247 | vfprintf(stderr, x, ap); | ||
248 | va_end(ap); | ||
249 | exit(EXIT_FAILURE); | ||
250 | } | ||
251 | |||
252 | static int checked_open(const char *pathname, int flags) | ||
253 | { | ||
254 | int fd = open(pathname, flags); | ||
255 | |||
256 | if (fd < 0) { | ||
257 | perror(pathname); | ||
258 | exit(EXIT_FAILURE); | ||
259 | } | ||
260 | |||
261 | return fd; | ||
262 | } | ||
263 | |||
264 | /* | ||
265 | * pagemap/kpageflags routines | ||
266 | */ | ||
267 | |||
268 | static unsigned long do_u64_read(int fd, char *name, | ||
269 | uint64_t *buf, | ||
270 | unsigned long index, | ||
271 | unsigned long count) | ||
272 | { | ||
273 | long bytes; | ||
274 | |||
275 | if (index > ULONG_MAX / 8) | ||
276 | fatal("index overflow: %lu\n", index); | ||
277 | |||
278 | if (lseek(fd, index * 8, SEEK_SET) < 0) { | ||
279 | perror(name); | ||
280 | exit(EXIT_FAILURE); | ||
281 | } | ||
282 | |||
283 | bytes = read(fd, buf, count * 8); | ||
284 | if (bytes < 0) { | ||
285 | perror(name); | ||
286 | exit(EXIT_FAILURE); | ||
287 | } | ||
288 | if (bytes % 8) | ||
289 | fatal("partial read: %lu bytes\n", bytes); | ||
290 | |||
291 | return bytes / 8; | ||
292 | } | ||
293 | |||
294 | static unsigned long kpageflags_read(uint64_t *buf, | ||
295 | unsigned long index, | ||
296 | unsigned long pages) | ||
297 | { | ||
298 | return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages); | ||
299 | } | ||
300 | |||
301 | static unsigned long pagemap_read(uint64_t *buf, | ||
302 | unsigned long index, | ||
303 | unsigned long pages) | ||
304 | { | ||
305 | return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages); | ||
306 | } | ||
307 | |||
308 | static unsigned long pagemap_pfn(uint64_t val) | ||
309 | { | ||
310 | unsigned long pfn; | ||
311 | |||
312 | if (val & PM_PRESENT) | ||
313 | pfn = PM_PFRAME(val); | ||
314 | else | ||
315 | pfn = 0; | ||
316 | |||
317 | return pfn; | ||
318 | } | ||
319 | |||
320 | |||
321 | /* | ||
322 | * page flag names | ||
323 | */ | ||
324 | |||
325 | static char *page_flag_name(uint64_t flags) | ||
326 | { | ||
327 | static char buf[65]; | ||
328 | int present; | ||
329 | int i, j; | ||
330 | |||
331 | for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { | ||
332 | present = (flags >> i) & 1; | ||
333 | if (!page_flag_names[i]) { | ||
334 | if (present) | ||
335 | fatal("unknown flag bit %d\n", i); | ||
336 | continue; | ||
337 | } | ||
338 | buf[j++] = present ? page_flag_names[i][0] : '_'; | ||
339 | } | ||
340 | |||
341 | return buf; | ||
342 | } | ||
343 | |||
344 | static char *page_flag_longname(uint64_t flags) | ||
345 | { | ||
346 | static char buf[1024]; | ||
347 | int i, n; | ||
348 | |||
349 | for (i = 0, n = 0; i < ARRAY_SIZE(page_flag_names); i++) { | ||
350 | if (!page_flag_names[i]) | ||
351 | continue; | ||
352 | if ((flags >> i) & 1) | ||
353 | n += snprintf(buf + n, sizeof(buf) - n, "%s,", | ||
354 | page_flag_names[i] + 2); | ||
355 | } | ||
356 | if (n) | ||
357 | n--; | ||
358 | buf[n] = '\0'; | ||
359 | |||
360 | return buf; | ||
361 | } | ||
362 | |||
363 | |||
364 | /* | ||
365 | * page list and summary | ||
366 | */ | ||
367 | |||
368 | static void show_page_range(unsigned long voffset, | ||
369 | unsigned long offset, uint64_t flags) | ||
370 | { | ||
371 | static uint64_t flags0; | ||
372 | static unsigned long voff; | ||
373 | static unsigned long index; | ||
374 | static unsigned long count; | ||
375 | |||
376 | if (flags == flags0 && offset == index + count && | ||
377 | (!opt_pid || voffset == voff + count)) { | ||
378 | count++; | ||
379 | return; | ||
380 | } | ||
381 | |||
382 | if (count) { | ||
383 | if (opt_pid) | ||
384 | printf("%lx\t", voff); | ||
385 | printf("%lx\t%lx\t%s\n", | ||
386 | index, count, page_flag_name(flags0)); | ||
387 | } | ||
388 | |||
389 | flags0 = flags; | ||
390 | index = offset; | ||
391 | voff = voffset; | ||
392 | count = 1; | ||
393 | } | ||
394 | |||
395 | static void show_page(unsigned long voffset, | ||
396 | unsigned long offset, uint64_t flags) | ||
397 | { | ||
398 | if (opt_pid) | ||
399 | printf("%lx\t", voffset); | ||
400 | printf("%lx\t%s\n", offset, page_flag_name(flags)); | ||
401 | } | ||
402 | |||
403 | static void show_summary(void) | ||
404 | { | ||
405 | int i; | ||
406 | |||
407 | printf(" flags\tpage-count MB" | ||
408 | " symbolic-flags\t\t\tlong-symbolic-flags\n"); | ||
409 | |||
410 | for (i = 0; i < ARRAY_SIZE(nr_pages); i++) { | ||
411 | if (nr_pages[i]) | ||
412 | printf("0x%016llx\t%10lu %8lu %s\t%s\n", | ||
413 | (unsigned long long)page_flags[i], | ||
414 | nr_pages[i], | ||
415 | pages2mb(nr_pages[i]), | ||
416 | page_flag_name(page_flags[i]), | ||
417 | page_flag_longname(page_flags[i])); | ||
418 | } | ||
419 | |||
420 | printf(" total\t%10lu %8lu\n", | ||
421 | total_pages, pages2mb(total_pages)); | ||
422 | } | ||
423 | |||
424 | |||
425 | /* | ||
426 | * page flag filters | ||
427 | */ | ||
428 | |||
429 | static int bit_mask_ok(uint64_t flags) | ||
430 | { | ||
431 | int i; | ||
432 | |||
433 | for (i = 0; i < nr_bit_filters; i++) { | ||
434 | if (opt_bits[i] == KPF_ALL_BITS) { | ||
435 | if ((flags & opt_mask[i]) == 0) | ||
436 | return 0; | ||
437 | } else { | ||
438 | if ((flags & opt_mask[i]) != opt_bits[i]) | ||
439 | return 0; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | return 1; | ||
444 | } | ||
445 | |||
446 | static uint64_t expand_overloaded_flags(uint64_t flags) | ||
447 | { | ||
448 | /* SLOB/SLUB overload several page flags */ | ||
449 | if (flags & BIT(SLAB)) { | ||
450 | if (flags & BIT(PRIVATE)) | ||
451 | flags ^= BIT(PRIVATE) | BIT(SLOB_FREE); | ||
452 | if (flags & BIT(ACTIVE)) | ||
453 | flags ^= BIT(ACTIVE) | BIT(SLUB_FROZEN); | ||
454 | if (flags & BIT(ERROR)) | ||
455 | flags ^= BIT(ERROR) | BIT(SLUB_DEBUG); | ||
456 | } | ||
457 | |||
458 | /* PG_reclaim is overloaded as PG_readahead in the read path */ | ||
459 | if ((flags & (BIT(RECLAIM) | BIT(WRITEBACK))) == BIT(RECLAIM)) | ||
460 | flags ^= BIT(RECLAIM) | BIT(READAHEAD); | ||
461 | |||
462 | return flags; | ||
463 | } | ||
464 | |||
465 | static uint64_t well_known_flags(uint64_t flags) | ||
466 | { | ||
467 | /* hide flags intended only for kernel hacker */ | ||
468 | flags &= ~KPF_HACKERS_BITS; | ||
469 | |||
470 | /* hide non-hugeTLB compound pages */ | ||
471 | if ((flags & BITS_COMPOUND) && !(flags & BIT(HUGE))) | ||
472 | flags &= ~BITS_COMPOUND; | ||
473 | |||
474 | return flags; | ||
475 | } | ||
476 | |||
477 | static uint64_t kpageflags_flags(uint64_t flags) | ||
478 | { | ||
479 | flags = expand_overloaded_flags(flags); | ||
480 | |||
481 | if (!opt_raw) | ||
482 | flags = well_known_flags(flags); | ||
483 | |||
484 | return flags; | ||
485 | } | ||
486 | |||
487 | /* verify that a mountpoint is actually a debugfs instance */ | ||
488 | static int debugfs_valid_mountpoint(const char *debugfs) | ||
489 | { | ||
490 | struct statfs st_fs; | ||
491 | |||
492 | if (statfs(debugfs, &st_fs) < 0) | ||
493 | return -ENOENT; | ||
494 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
495 | return -ENOENT; | ||
496 | |||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | /* find the path to the mounted debugfs */ | ||
501 | static const char *debugfs_find_mountpoint(void) | ||
502 | { | ||
503 | const char **ptr; | ||
504 | char type[100]; | ||
505 | FILE *fp; | ||
506 | |||
507 | ptr = debugfs_known_mountpoints; | ||
508 | while (*ptr) { | ||
509 | if (debugfs_valid_mountpoint(*ptr) == 0) { | ||
510 | strcpy(hwpoison_debug_fs, *ptr); | ||
511 | return hwpoison_debug_fs; | ||
512 | } | ||
513 | ptr++; | ||
514 | } | ||
515 | |||
516 | /* give up and parse /proc/mounts */ | ||
517 | fp = fopen("/proc/mounts", "r"); | ||
518 | if (fp == NULL) | ||
519 | perror("Can't open /proc/mounts for read"); | ||
520 | |||
521 | while (fscanf(fp, "%*s %" | ||
522 | STR(MAX_PATH) | ||
523 | "s %99s %*s %*d %*d\n", | ||
524 | hwpoison_debug_fs, type) == 2) { | ||
525 | if (strcmp(type, "debugfs") == 0) | ||
526 | break; | ||
527 | } | ||
528 | fclose(fp); | ||
529 | |||
530 | if (strcmp(type, "debugfs") != 0) | ||
531 | return NULL; | ||
532 | |||
533 | return hwpoison_debug_fs; | ||
534 | } | ||
535 | |||
536 | /* mount the debugfs somewhere if it's not mounted */ | ||
537 | |||
538 | static void debugfs_mount(void) | ||
539 | { | ||
540 | const char **ptr; | ||
541 | |||
542 | /* see if it's already mounted */ | ||
543 | if (debugfs_find_mountpoint()) | ||
544 | return; | ||
545 | |||
546 | ptr = debugfs_known_mountpoints; | ||
547 | while (*ptr) { | ||
548 | if (mount(NULL, *ptr, "debugfs", 0, NULL) == 0) { | ||
549 | /* save the mountpoint */ | ||
550 | strcpy(hwpoison_debug_fs, *ptr); | ||
551 | break; | ||
552 | } | ||
553 | ptr++; | ||
554 | } | ||
555 | |||
556 | if (*ptr == NULL) { | ||
557 | perror("mount debugfs"); | ||
558 | exit(EXIT_FAILURE); | ||
559 | } | ||
560 | } | ||
561 | |||
562 | /* | ||
563 | * page actions | ||
564 | */ | ||
565 | |||
566 | static void prepare_hwpoison_fd(void) | ||
567 | { | ||
568 | char buf[MAX_PATH + 1]; | ||
569 | |||
570 | debugfs_mount(); | ||
571 | |||
572 | if (opt_hwpoison && !hwpoison_inject_fd) { | ||
573 | snprintf(buf, MAX_PATH, "%s/hwpoison/corrupt-pfn", | ||
574 | hwpoison_debug_fs); | ||
575 | hwpoison_inject_fd = checked_open(buf, O_WRONLY); | ||
576 | } | ||
577 | |||
578 | if (opt_unpoison && !hwpoison_forget_fd) { | ||
579 | snprintf(buf, MAX_PATH, "%s/hwpoison/unpoison-pfn", | ||
580 | hwpoison_debug_fs); | ||
581 | hwpoison_forget_fd = checked_open(buf, O_WRONLY); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static int hwpoison_page(unsigned long offset) | ||
586 | { | ||
587 | char buf[100]; | ||
588 | int len; | ||
589 | |||
590 | len = sprintf(buf, "0x%lx\n", offset); | ||
591 | len = write(hwpoison_inject_fd, buf, len); | ||
592 | if (len < 0) { | ||
593 | perror("hwpoison inject"); | ||
594 | return len; | ||
595 | } | ||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int unpoison_page(unsigned long offset) | ||
600 | { | ||
601 | char buf[100]; | ||
602 | int len; | ||
603 | |||
604 | len = sprintf(buf, "0x%lx\n", offset); | ||
605 | len = write(hwpoison_forget_fd, buf, len); | ||
606 | if (len < 0) { | ||
607 | perror("hwpoison forget"); | ||
608 | return len; | ||
609 | } | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | /* | ||
614 | * page frame walker | ||
615 | */ | ||
616 | |||
617 | static int hash_slot(uint64_t flags) | ||
618 | { | ||
619 | int k = HASH_KEY(flags); | ||
620 | int i; | ||
621 | |||
622 | /* Explicitly reserve slot 0 for flags 0: the following logic | ||
623 | * cannot distinguish an unoccupied slot from slot (flags==0). | ||
624 | */ | ||
625 | if (flags == 0) | ||
626 | return 0; | ||
627 | |||
628 | /* search through the remaining (HASH_SIZE-1) slots */ | ||
629 | for (i = 1; i < ARRAY_SIZE(page_flags); i++, k++) { | ||
630 | if (!k || k >= ARRAY_SIZE(page_flags)) | ||
631 | k = 1; | ||
632 | if (page_flags[k] == 0) { | ||
633 | page_flags[k] = flags; | ||
634 | return k; | ||
635 | } | ||
636 | if (page_flags[k] == flags) | ||
637 | return k; | ||
638 | } | ||
639 | |||
640 | fatal("hash table full: bump up HASH_SHIFT?\n"); | ||
641 | exit(EXIT_FAILURE); | ||
642 | } | ||
643 | |||
644 | static void add_page(unsigned long voffset, | ||
645 | unsigned long offset, uint64_t flags) | ||
646 | { | ||
647 | flags = kpageflags_flags(flags); | ||
648 | |||
649 | if (!bit_mask_ok(flags)) | ||
650 | return; | ||
651 | |||
652 | if (opt_hwpoison) | ||
653 | hwpoison_page(offset); | ||
654 | if (opt_unpoison) | ||
655 | unpoison_page(offset); | ||
656 | |||
657 | if (opt_list == 1) | ||
658 | show_page_range(voffset, offset, flags); | ||
659 | else if (opt_list == 2) | ||
660 | show_page(voffset, offset, flags); | ||
661 | |||
662 | nr_pages[hash_slot(flags)]++; | ||
663 | total_pages++; | ||
664 | } | ||
665 | |||
666 | #define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */ | ||
667 | static void walk_pfn(unsigned long voffset, | ||
668 | unsigned long index, | ||
669 | unsigned long count) | ||
670 | { | ||
671 | uint64_t buf[KPAGEFLAGS_BATCH]; | ||
672 | unsigned long batch; | ||
673 | long pages; | ||
674 | unsigned long i; | ||
675 | |||
676 | while (count) { | ||
677 | batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH); | ||
678 | pages = kpageflags_read(buf, index, batch); | ||
679 | if (pages == 0) | ||
680 | break; | ||
681 | |||
682 | for (i = 0; i < pages; i++) | ||
683 | add_page(voffset + i, index + i, buf[i]); | ||
684 | |||
685 | index += pages; | ||
686 | count -= pages; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | #define PAGEMAP_BATCH (64 << 10) | ||
691 | static void walk_vma(unsigned long index, unsigned long count) | ||
692 | { | ||
693 | uint64_t buf[PAGEMAP_BATCH]; | ||
694 | unsigned long batch; | ||
695 | unsigned long pages; | ||
696 | unsigned long pfn; | ||
697 | unsigned long i; | ||
698 | |||
699 | while (count) { | ||
700 | batch = min_t(unsigned long, count, PAGEMAP_BATCH); | ||
701 | pages = pagemap_read(buf, index, batch); | ||
702 | if (pages == 0) | ||
703 | break; | ||
704 | |||
705 | for (i = 0; i < pages; i++) { | ||
706 | pfn = pagemap_pfn(buf[i]); | ||
707 | if (pfn) | ||
708 | walk_pfn(index + i, pfn, 1); | ||
709 | } | ||
710 | |||
711 | index += pages; | ||
712 | count -= pages; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | static void walk_task(unsigned long index, unsigned long count) | ||
717 | { | ||
718 | const unsigned long end = index + count; | ||
719 | unsigned long start; | ||
720 | int i = 0; | ||
721 | |||
722 | while (index < end) { | ||
723 | |||
724 | while (pg_end[i] <= index) | ||
725 | if (++i >= nr_vmas) | ||
726 | return; | ||
727 | if (pg_start[i] >= end) | ||
728 | return; | ||
729 | |||
730 | start = max_t(unsigned long, pg_start[i], index); | ||
731 | index = min_t(unsigned long, pg_end[i], end); | ||
732 | |||
733 | assert(start < index); | ||
734 | walk_vma(start, index - start); | ||
735 | } | ||
736 | } | ||
737 | |||
738 | static void add_addr_range(unsigned long offset, unsigned long size) | ||
739 | { | ||
740 | if (nr_addr_ranges >= MAX_ADDR_RANGES) | ||
741 | fatal("too many addr ranges\n"); | ||
742 | |||
743 | opt_offset[nr_addr_ranges] = offset; | ||
744 | opt_size[nr_addr_ranges] = min_t(unsigned long, size, ULONG_MAX-offset); | ||
745 | nr_addr_ranges++; | ||
746 | } | ||
747 | |||
748 | static void walk_addr_ranges(void) | ||
749 | { | ||
750 | int i; | ||
751 | |||
752 | kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY); | ||
753 | |||
754 | if (!nr_addr_ranges) | ||
755 | add_addr_range(0, ULONG_MAX); | ||
756 | |||
757 | for (i = 0; i < nr_addr_ranges; i++) | ||
758 | if (!opt_pid) | ||
759 | walk_pfn(0, opt_offset[i], opt_size[i]); | ||
760 | else | ||
761 | walk_task(opt_offset[i], opt_size[i]); | ||
762 | |||
763 | close(kpageflags_fd); | ||
764 | } | ||
765 | |||
766 | |||
767 | /* | ||
768 | * user interface | ||
769 | */ | ||
770 | |||
771 | static const char *page_flag_type(uint64_t flag) | ||
772 | { | ||
773 | if (flag & KPF_HACKERS_BITS) | ||
774 | return "(r)"; | ||
775 | if (flag & KPF_OVERLOADED_BITS) | ||
776 | return "(o)"; | ||
777 | return " "; | ||
778 | } | ||
779 | |||
780 | static void usage(void) | ||
781 | { | ||
782 | int i, j; | ||
783 | |||
784 | printf( | ||
785 | "page-types [options]\n" | ||
786 | " -r|--raw Raw mode, for kernel developers\n" | ||
787 | " -d|--describe flags Describe flags\n" | ||
788 | " -a|--addr addr-spec Walk a range of pages\n" | ||
789 | " -b|--bits bits-spec Walk pages with specified bits\n" | ||
790 | " -p|--pid pid Walk process address space\n" | ||
791 | #if 0 /* planned features */ | ||
792 | " -f|--file filename Walk file address space\n" | ||
793 | #endif | ||
794 | " -l|--list Show page details in ranges\n" | ||
795 | " -L|--list-each Show page details one by one\n" | ||
796 | " -N|--no-summary Don't show summary info\n" | ||
797 | " -X|--hwpoison hwpoison pages\n" | ||
798 | " -x|--unpoison unpoison pages\n" | ||
799 | " -h|--help Show this usage message\n" | ||
800 | "flags:\n" | ||
801 | " 0x10 bitfield format, e.g.\n" | ||
802 | " anon bit-name, e.g.\n" | ||
803 | " 0x10,anon comma-separated list, e.g.\n" | ||
804 | "addr-spec:\n" | ||
805 | " N one page at offset N (unit: pages)\n" | ||
806 | " N+M pages range from N to N+M-1\n" | ||
807 | " N,M pages range from N to M-1\n" | ||
808 | " N, pages range from N to end\n" | ||
809 | " ,M pages range from 0 to M-1\n" | ||
810 | "bits-spec:\n" | ||
811 | " bit1,bit2 (flags & (bit1|bit2)) != 0\n" | ||
812 | " bit1,bit2=bit1 (flags & (bit1|bit2)) == bit1\n" | ||
813 | " bit1,~bit2 (flags & (bit1|bit2)) == bit1\n" | ||
814 | " =bit1,bit2 flags == (bit1|bit2)\n" | ||
815 | "bit-names:\n" | ||
816 | ); | ||
817 | |||
818 | for (i = 0, j = 0; i < ARRAY_SIZE(page_flag_names); i++) { | ||
819 | if (!page_flag_names[i]) | ||
820 | continue; | ||
821 | printf("%16s%s", page_flag_names[i] + 2, | ||
822 | page_flag_type(1ULL << i)); | ||
823 | if (++j > 3) { | ||
824 | j = 0; | ||
825 | putchar('\n'); | ||
826 | } | ||
827 | } | ||
828 | printf("\n " | ||
829 | "(r) raw mode bits (o) overloaded bits\n"); | ||
830 | } | ||
831 | |||
832 | static unsigned long long parse_number(const char *str) | ||
833 | { | ||
834 | unsigned long long n; | ||
835 | |||
836 | n = strtoll(str, NULL, 0); | ||
837 | |||
838 | if (n == 0 && str[0] != '0') | ||
839 | fatal("invalid name or number: %s\n", str); | ||
840 | |||
841 | return n; | ||
842 | } | ||
843 | |||
844 | static void parse_pid(const char *str) | ||
845 | { | ||
846 | FILE *file; | ||
847 | char buf[5000]; | ||
848 | |||
849 | opt_pid = parse_number(str); | ||
850 | |||
851 | sprintf(buf, "/proc/%d/pagemap", opt_pid); | ||
852 | pagemap_fd = checked_open(buf, O_RDONLY); | ||
853 | |||
854 | sprintf(buf, "/proc/%d/maps", opt_pid); | ||
855 | file = fopen(buf, "r"); | ||
856 | if (!file) { | ||
857 | perror(buf); | ||
858 | exit(EXIT_FAILURE); | ||
859 | } | ||
860 | |||
861 | while (fgets(buf, sizeof(buf), file) != NULL) { | ||
862 | unsigned long vm_start; | ||
863 | unsigned long vm_end; | ||
864 | unsigned long long pgoff; | ||
865 | int major, minor; | ||
866 | char r, w, x, s; | ||
867 | unsigned long ino; | ||
868 | int n; | ||
869 | |||
870 | n = sscanf(buf, "%lx-%lx %c%c%c%c %llx %x:%x %lu", | ||
871 | &vm_start, | ||
872 | &vm_end, | ||
873 | &r, &w, &x, &s, | ||
874 | &pgoff, | ||
875 | &major, &minor, | ||
876 | &ino); | ||
877 | if (n < 10) { | ||
878 | fprintf(stderr, "unexpected line: %s\n", buf); | ||
879 | continue; | ||
880 | } | ||
881 | pg_start[nr_vmas] = vm_start / page_size; | ||
882 | pg_end[nr_vmas] = vm_end / page_size; | ||
883 | if (++nr_vmas >= MAX_VMAS) { | ||
884 | fprintf(stderr, "too many VMAs\n"); | ||
885 | break; | ||
886 | } | ||
887 | } | ||
888 | fclose(file); | ||
889 | } | ||
890 | |||
891 | static void parse_file(const char *name) | ||
892 | { | ||
893 | } | ||
894 | |||
895 | static void parse_addr_range(const char *optarg) | ||
896 | { | ||
897 | unsigned long offset; | ||
898 | unsigned long size; | ||
899 | char *p; | ||
900 | |||
901 | p = strchr(optarg, ','); | ||
902 | if (!p) | ||
903 | p = strchr(optarg, '+'); | ||
904 | |||
905 | if (p == optarg) { | ||
906 | offset = 0; | ||
907 | size = parse_number(p + 1); | ||
908 | } else if (p) { | ||
909 | offset = parse_number(optarg); | ||
910 | if (p[1] == '\0') | ||
911 | size = ULONG_MAX; | ||
912 | else { | ||
913 | size = parse_number(p + 1); | ||
914 | if (*p == ',') { | ||
915 | if (size < offset) | ||
916 | fatal("invalid range: %lu,%lu\n", | ||
917 | offset, size); | ||
918 | size -= offset; | ||
919 | } | ||
920 | } | ||
921 | } else { | ||
922 | offset = parse_number(optarg); | ||
923 | size = 1; | ||
924 | } | ||
925 | |||
926 | add_addr_range(offset, size); | ||
927 | } | ||
928 | |||
929 | static void add_bits_filter(uint64_t mask, uint64_t bits) | ||
930 | { | ||
931 | if (nr_bit_filters >= MAX_BIT_FILTERS) | ||
932 | fatal("too much bit filters\n"); | ||
933 | |||
934 | opt_mask[nr_bit_filters] = mask; | ||
935 | opt_bits[nr_bit_filters] = bits; | ||
936 | nr_bit_filters++; | ||
937 | } | ||
938 | |||
939 | static uint64_t parse_flag_name(const char *str, int len) | ||
940 | { | ||
941 | int i; | ||
942 | |||
943 | if (!*str || !len) | ||
944 | return 0; | ||
945 | |||
946 | if (len <= 8 && !strncmp(str, "compound", len)) | ||
947 | return BITS_COMPOUND; | ||
948 | |||
949 | for (i = 0; i < ARRAY_SIZE(page_flag_names); i++) { | ||
950 | if (!page_flag_names[i]) | ||
951 | continue; | ||
952 | if (!strncmp(str, page_flag_names[i] + 2, len)) | ||
953 | return 1ULL << i; | ||
954 | } | ||
955 | |||
956 | return parse_number(str); | ||
957 | } | ||
958 | |||
959 | static uint64_t parse_flag_names(const char *str, int all) | ||
960 | { | ||
961 | const char *p = str; | ||
962 | uint64_t flags = 0; | ||
963 | |||
964 | while (1) { | ||
965 | if (*p == ',' || *p == '=' || *p == '\0') { | ||
966 | if ((*str != '~') || (*str == '~' && all && *++str)) | ||
967 | flags |= parse_flag_name(str, p - str); | ||
968 | if (*p != ',') | ||
969 | break; | ||
970 | str = p + 1; | ||
971 | } | ||
972 | p++; | ||
973 | } | ||
974 | |||
975 | return flags; | ||
976 | } | ||
977 | |||
978 | static void parse_bits_mask(const char *optarg) | ||
979 | { | ||
980 | uint64_t mask; | ||
981 | uint64_t bits; | ||
982 | const char *p; | ||
983 | |||
984 | p = strchr(optarg, '='); | ||
985 | if (p == optarg) { | ||
986 | mask = KPF_ALL_BITS; | ||
987 | bits = parse_flag_names(p + 1, 0); | ||
988 | } else if (p) { | ||
989 | mask = parse_flag_names(optarg, 0); | ||
990 | bits = parse_flag_names(p + 1, 0); | ||
991 | } else if (strchr(optarg, '~')) { | ||
992 | mask = parse_flag_names(optarg, 1); | ||
993 | bits = parse_flag_names(optarg, 0); | ||
994 | } else { | ||
995 | mask = parse_flag_names(optarg, 0); | ||
996 | bits = KPF_ALL_BITS; | ||
997 | } | ||
998 | |||
999 | add_bits_filter(mask, bits); | ||
1000 | } | ||
1001 | |||
1002 | static void describe_flags(const char *optarg) | ||
1003 | { | ||
1004 | uint64_t flags = parse_flag_names(optarg, 0); | ||
1005 | |||
1006 | printf("0x%016llx\t%s\t%s\n", | ||
1007 | (unsigned long long)flags, | ||
1008 | page_flag_name(flags), | ||
1009 | page_flag_longname(flags)); | ||
1010 | } | ||
1011 | |||
1012 | static const struct option opts[] = { | ||
1013 | { "raw" , 0, NULL, 'r' }, | ||
1014 | { "pid" , 1, NULL, 'p' }, | ||
1015 | { "file" , 1, NULL, 'f' }, | ||
1016 | { "addr" , 1, NULL, 'a' }, | ||
1017 | { "bits" , 1, NULL, 'b' }, | ||
1018 | { "describe" , 1, NULL, 'd' }, | ||
1019 | { "list" , 0, NULL, 'l' }, | ||
1020 | { "list-each" , 0, NULL, 'L' }, | ||
1021 | { "no-summary", 0, NULL, 'N' }, | ||
1022 | { "hwpoison" , 0, NULL, 'X' }, | ||
1023 | { "unpoison" , 0, NULL, 'x' }, | ||
1024 | { "help" , 0, NULL, 'h' }, | ||
1025 | { NULL , 0, NULL, 0 } | ||
1026 | }; | ||
1027 | |||
1028 | int main(int argc, char *argv[]) | ||
1029 | { | ||
1030 | int c; | ||
1031 | |||
1032 | page_size = getpagesize(); | ||
1033 | |||
1034 | while ((c = getopt_long(argc, argv, | ||
1035 | "rp:f:a:b:d:lLNXxh", opts, NULL)) != -1) { | ||
1036 | switch (c) { | ||
1037 | case 'r': | ||
1038 | opt_raw = 1; | ||
1039 | break; | ||
1040 | case 'p': | ||
1041 | parse_pid(optarg); | ||
1042 | break; | ||
1043 | case 'f': | ||
1044 | parse_file(optarg); | ||
1045 | break; | ||
1046 | case 'a': | ||
1047 | parse_addr_range(optarg); | ||
1048 | break; | ||
1049 | case 'b': | ||
1050 | parse_bits_mask(optarg); | ||
1051 | break; | ||
1052 | case 'd': | ||
1053 | describe_flags(optarg); | ||
1054 | exit(0); | ||
1055 | case 'l': | ||
1056 | opt_list = 1; | ||
1057 | break; | ||
1058 | case 'L': | ||
1059 | opt_list = 2; | ||
1060 | break; | ||
1061 | case 'N': | ||
1062 | opt_no_summary = 1; | ||
1063 | break; | ||
1064 | case 'X': | ||
1065 | opt_hwpoison = 1; | ||
1066 | prepare_hwpoison_fd(); | ||
1067 | break; | ||
1068 | case 'x': | ||
1069 | opt_unpoison = 1; | ||
1070 | prepare_hwpoison_fd(); | ||
1071 | break; | ||
1072 | case 'h': | ||
1073 | usage(); | ||
1074 | exit(0); | ||
1075 | default: | ||
1076 | usage(); | ||
1077 | exit(1); | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | if (opt_list && opt_pid) | ||
1082 | printf("voffset\t"); | ||
1083 | if (opt_list == 1) | ||
1084 | printf("offset\tlen\tflags\n"); | ||
1085 | if (opt_list == 2) | ||
1086 | printf("offset\tflags\n"); | ||
1087 | |||
1088 | walk_addr_ranges(); | ||
1089 | |||
1090 | if (opt_list == 1) | ||
1091 | show_page_range(0, 0, 0); /* drain the buffer */ | ||
1092 | |||
1093 | if (opt_no_summary) | ||
1094 | return 0; | ||
1095 | |||
1096 | if (opt_list) | ||
1097 | printf("\n\n"); | ||
1098 | |||
1099 | show_summary(); | ||
1100 | |||
1101 | return 0; | ||
1102 | } | ||
diff --git a/tools/slub/slabinfo.c b/tools/vm/slabinfo.c index 164cbcf61106..164cbcf61106 100644 --- a/tools/slub/slabinfo.c +++ b/tools/vm/slabinfo.c | |||