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