diff options
Diffstat (limited to 'tools/testing')
28 files changed, 814 insertions, 15 deletions
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 55ab700f6ba5..bf1398180785 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl | |||
@@ -194,6 +194,7 @@ my $config_bisect_check; | |||
194 | 194 | ||
195 | my $patchcheck_type; | 195 | my $patchcheck_type; |
196 | my $patchcheck_start; | 196 | my $patchcheck_start; |
197 | my $patchcheck_cherry; | ||
197 | my $patchcheck_end; | 198 | my $patchcheck_end; |
198 | 199 | ||
199 | # set when a test is something other that just building or install | 200 | # set when a test is something other that just building or install |
@@ -320,6 +321,7 @@ my %option_map = ( | |||
320 | 321 | ||
321 | "PATCHCHECK_TYPE" => \$patchcheck_type, | 322 | "PATCHCHECK_TYPE" => \$patchcheck_type, |
322 | "PATCHCHECK_START" => \$patchcheck_start, | 323 | "PATCHCHECK_START" => \$patchcheck_start, |
324 | "PATCHCHECK_CHERRY" => \$patchcheck_cherry, | ||
323 | "PATCHCHECK_END" => \$patchcheck_end, | 325 | "PATCHCHECK_END" => \$patchcheck_end, |
324 | ); | 326 | ); |
325 | 327 | ||
@@ -1448,6 +1450,12 @@ sub wait_for_monitor { | |||
1448 | } | 1450 | } |
1449 | } | 1451 | } |
1450 | print "** Monitor flushed **\n"; | 1452 | print "** Monitor flushed **\n"; |
1453 | |||
1454 | # if stop is defined but wasn't hit, return error | ||
1455 | # used by reboot (which wants to see a reboot) | ||
1456 | if (defined($stop) && !$booted) { | ||
1457 | $bug = 1; | ||
1458 | } | ||
1451 | return $bug; | 1459 | return $bug; |
1452 | } | 1460 | } |
1453 | 1461 | ||
@@ -2336,15 +2344,17 @@ sub success { | |||
2336 | 2344 | ||
2337 | sub answer_bisect { | 2345 | sub answer_bisect { |
2338 | for (;;) { | 2346 | for (;;) { |
2339 | doprint "Pass or fail? [p/f]"; | 2347 | doprint "Pass, fail, or skip? [p/f/s]"; |
2340 | my $ans = <STDIN>; | 2348 | my $ans = <STDIN>; |
2341 | chomp $ans; | 2349 | chomp $ans; |
2342 | if ($ans eq "p" || $ans eq "P") { | 2350 | if ($ans eq "p" || $ans eq "P") { |
2343 | return 1; | 2351 | return 1; |
2344 | } elsif ($ans eq "f" || $ans eq "F") { | 2352 | } elsif ($ans eq "f" || $ans eq "F") { |
2345 | return 0; | 2353 | return 0; |
2354 | } elsif ($ans eq "s" || $ans eq "S") { | ||
2355 | return -1; | ||
2346 | } else { | 2356 | } else { |
2347 | print "Please answer 'P' or 'F'\n"; | 2357 | print "Please answer 'p', 'f', or 's'\n"; |
2348 | } | 2358 | } |
2349 | } | 2359 | } |
2350 | } | 2360 | } |
@@ -2726,15 +2736,17 @@ sub bisect { | |||
2726 | run_command "git bisect start$start_files" or | 2736 | run_command "git bisect start$start_files" or |
2727 | dodie "could not start bisect"; | 2737 | dodie "could not start bisect"; |
2728 | 2738 | ||
2729 | run_command "git bisect good $good" or | ||
2730 | dodie "could not set bisect good to $good"; | ||
2731 | |||
2732 | run_git_bisect "git bisect bad $bad" or | ||
2733 | dodie "could not set bisect bad to $bad"; | ||
2734 | |||
2735 | if (defined($replay)) { | 2739 | if (defined($replay)) { |
2736 | run_command "git bisect replay $replay" or | 2740 | run_command "git bisect replay $replay" or |
2737 | dodie "failed to run replay"; | 2741 | dodie "failed to run replay"; |
2742 | } else { | ||
2743 | |||
2744 | run_command "git bisect good $good" or | ||
2745 | dodie "could not set bisect good to $good"; | ||
2746 | |||
2747 | run_git_bisect "git bisect bad $bad" or | ||
2748 | dodie "could not set bisect bad to $bad"; | ||
2749 | |||
2738 | } | 2750 | } |
2739 | 2751 | ||
2740 | if (defined($start)) { | 2752 | if (defined($start)) { |
@@ -3181,9 +3193,16 @@ sub patchcheck { | |||
3181 | 3193 | ||
3182 | my $start = $patchcheck_start; | 3194 | my $start = $patchcheck_start; |
3183 | 3195 | ||
3196 | my $cherry = $patchcheck_cherry; | ||
3197 | if (!defined($cherry)) { | ||
3198 | $cherry = 0; | ||
3199 | } | ||
3200 | |||
3184 | my $end = "HEAD"; | 3201 | my $end = "HEAD"; |
3185 | if (defined($patchcheck_end)) { | 3202 | if (defined($patchcheck_end)) { |
3186 | $end = $patchcheck_end; | 3203 | $end = $patchcheck_end; |
3204 | } elsif ($cherry) { | ||
3205 | die "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n"; | ||
3187 | } | 3206 | } |
3188 | 3207 | ||
3189 | # Get the true sha1's since we can use things like HEAD~3 | 3208 | # Get the true sha1's since we can use things like HEAD~3 |
@@ -3197,24 +3216,38 @@ sub patchcheck { | |||
3197 | $type = "boot"; | 3216 | $type = "boot"; |
3198 | } | 3217 | } |
3199 | 3218 | ||
3200 | open (IN, "git log --pretty=oneline $end|") or | 3219 | if ($cherry) { |
3201 | dodie "could not get git list"; | 3220 | open (IN, "git cherry -v $start $end|") or |
3221 | dodie "could not get git list"; | ||
3222 | } else { | ||
3223 | open (IN, "git log --pretty=oneline $end|") or | ||
3224 | dodie "could not get git list"; | ||
3225 | } | ||
3202 | 3226 | ||
3203 | my @list; | 3227 | my @list; |
3204 | 3228 | ||
3205 | while (<IN>) { | 3229 | while (<IN>) { |
3206 | chomp; | 3230 | chomp; |
3231 | # git cherry adds a '+' we want to remove | ||
3232 | s/^\+ //; | ||
3207 | $list[$#list+1] = $_; | 3233 | $list[$#list+1] = $_; |
3208 | last if (/^$start/); | 3234 | last if (/^$start/); |
3209 | } | 3235 | } |
3210 | close(IN); | 3236 | close(IN); |
3211 | 3237 | ||
3212 | if ($list[$#list] !~ /^$start/) { | 3238 | if (!$cherry) { |
3213 | fail "SHA1 $start not found"; | 3239 | if ($list[$#list] !~ /^$start/) { |
3240 | fail "SHA1 $start not found"; | ||
3241 | } | ||
3242 | |||
3243 | # go backwards in the list | ||
3244 | @list = reverse @list; | ||
3214 | } | 3245 | } |
3215 | 3246 | ||
3216 | # go backwards in the list | 3247 | doprint("Going to test the following commits:\n"); |
3217 | @list = reverse @list; | 3248 | foreach my $l (@list) { |
3249 | doprint "$l\n"; | ||
3250 | } | ||
3218 | 3251 | ||
3219 | my $save_clean = $noclean; | 3252 | my $save_clean = $noclean; |
3220 | my %ignored_warnings; | 3253 | my %ignored_warnings; |
diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 911e45ad657a..6c58cd8bbbae 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf | |||
@@ -906,6 +906,16 @@ | |||
906 | # | 906 | # |
907 | # PATCHCHECK_END is the last patch to check (default HEAD) | 907 | # PATCHCHECK_END is the last patch to check (default HEAD) |
908 | # | 908 | # |
909 | # PATCHCHECK_CHERRY if set to non zero, then git cherry will be | ||
910 | # performed against PATCHCHECK_START and PATCHCHECK_END. That is | ||
911 | # | ||
912 | # git cherry ${PATCHCHECK_START} ${PATCHCHECK_END} | ||
913 | # | ||
914 | # Then the changes found will be tested. | ||
915 | # | ||
916 | # Note, PATCHCHECK_CHERRY requires PATCHCHECK_END to be defined. | ||
917 | # (default 0) | ||
918 | # | ||
909 | # PATCHCHECK_TYPE is required and is the type of test to run: | 919 | # PATCHCHECK_TYPE is required and is the type of test to run: |
910 | # build, boot, test. | 920 | # build, boot, test. |
911 | # | 921 | # |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 36ff2e4c7b6f..45f145c6f843 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -14,6 +14,7 @@ TARGETS += powerpc | |||
14 | TARGETS += user | 14 | TARGETS += user |
15 | TARGETS += sysctl | 15 | TARGETS += sysctl |
16 | TARGETS += firmware | 16 | TARGETS += firmware |
17 | TARGETS += ftrace | ||
17 | 18 | ||
18 | TARGETS_HOTPLUG = cpu-hotplug | 19 | TARGETS_HOTPLUG = cpu-hotplug |
19 | TARGETS_HOTPLUG += memory-hotplug | 20 | TARGETS_HOTPLUG += memory-hotplug |
diff --git a/tools/testing/selftests/ftrace/Makefile b/tools/testing/selftests/ftrace/Makefile new file mode 100644 index 000000000000..76cc9f156267 --- /dev/null +++ b/tools/testing/selftests/ftrace/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | all: | ||
2 | |||
3 | run_tests: | ||
4 | @/bin/sh ./ftracetest || echo "ftrace selftests: [FAIL]" | ||
5 | |||
6 | clean: | ||
7 | rm -rf logs/* | ||
diff --git a/tools/testing/selftests/ftrace/README b/tools/testing/selftests/ftrace/README new file mode 100644 index 000000000000..182e76fa4b82 --- /dev/null +++ b/tools/testing/selftests/ftrace/README | |||
@@ -0,0 +1,82 @@ | |||
1 | Linux Ftrace Testcases | ||
2 | |||
3 | This is a collection of testcases for ftrace tracing feature in the Linux | ||
4 | kernel. Since ftrace exports interfaces via the debugfs, we just need | ||
5 | shell scripts for testing. Feel free to add new test cases. | ||
6 | |||
7 | Running the ftrace testcases | ||
8 | ============================ | ||
9 | |||
10 | At first, you need to be the root user to run this script. | ||
11 | To run all testcases: | ||
12 | |||
13 | $ sudo ./ftracetest | ||
14 | |||
15 | To run specific testcases: | ||
16 | |||
17 | # ./ftracetest test.d/basic3.tc | ||
18 | |||
19 | Or you can also run testcases under given directory: | ||
20 | |||
21 | # ./ftracetest test.d/kprobe/ | ||
22 | |||
23 | Contributing new testcases | ||
24 | ========================== | ||
25 | |||
26 | Copy test.d/template to your testcase (whose filename must have *.tc | ||
27 | extension) and rewrite the test description line. | ||
28 | |||
29 | * The working directory of the script is <debugfs>/tracing/. | ||
30 | |||
31 | * Take care with side effects as the tests are run with root privilege. | ||
32 | |||
33 | * The tests should not run for a long period of time (more than 1 min.) | ||
34 | These are to be unit tests. | ||
35 | |||
36 | * You can add a directory for your testcases under test.d/ if needed. | ||
37 | |||
38 | * The test cases should run on dash (busybox shell) for testing on | ||
39 | minimal cross-build environments. | ||
40 | |||
41 | * Note that the tests are run with "set -e" (errexit) option. If any | ||
42 | command fails, the test will be terminated immediately. | ||
43 | |||
44 | * The tests can return some result codes instead of pass or fail by | ||
45 | using exit_unresolved, exit_untested, exit_unsupported and exit_xfail. | ||
46 | |||
47 | Result code | ||
48 | =========== | ||
49 | |||
50 | Ftracetest supports following result codes. | ||
51 | |||
52 | * PASS: The test succeeded as expected. The test which exits with 0 is | ||
53 | counted as passed test. | ||
54 | |||
55 | * FAIL: The test failed, but was expected to succeed. The test which exits | ||
56 | with !0 is counted as failed test. | ||
57 | |||
58 | * UNRESOLVED: The test produced unclear or intermidiate results. | ||
59 | for example, the test was interrupted | ||
60 | or the test depends on a previous test, which failed. | ||
61 | or the test was set up incorrectly | ||
62 | The test which is in above situation, must call exit_unresolved. | ||
63 | |||
64 | * UNTESTED: The test was not run, currently just a placeholder. | ||
65 | In this case, the test must call exit_untested. | ||
66 | |||
67 | * UNSUPPORTED: The test failed because of lack of feature. | ||
68 | In this case, the test must call exit_unsupported. | ||
69 | |||
70 | * XFAIL: The test failed, and was expected to fail. | ||
71 | To return XFAIL, call exit_xfail from the test. | ||
72 | |||
73 | There are some sample test scripts for result code under samples/. | ||
74 | You can also run samples as below: | ||
75 | |||
76 | # ./ftracetest samples/ | ||
77 | |||
78 | TODO | ||
79 | ==== | ||
80 | |||
81 | * Fancy colored output :) | ||
82 | |||
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest new file mode 100755 index 000000000000..a8f81c782856 --- /dev/null +++ b/tools/testing/selftests/ftrace/ftracetest | |||
@@ -0,0 +1,253 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # ftracetest - Ftrace test shell scripts | ||
4 | # | ||
5 | # Copyright (C) Hitachi Ltd., 2014 | ||
6 | # Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | ||
7 | # | ||
8 | # Released under the terms of the GPL v2. | ||
9 | |||
10 | usage() { # errno [message] | ||
11 | [ "$2" ] && echo $2 | ||
12 | echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]" | ||
13 | echo " Options:" | ||
14 | echo " -h|--help Show help message" | ||
15 | echo " -k|--keep Keep passed test logs" | ||
16 | echo " -d|--debug Debug mode (trace all shell commands)" | ||
17 | exit $1 | ||
18 | } | ||
19 | |||
20 | errexit() { # message | ||
21 | echo "Error: $1" 1>&2 | ||
22 | exit 1 | ||
23 | } | ||
24 | |||
25 | # Ensuring user privilege | ||
26 | if [ `id -u` -ne 0 ]; then | ||
27 | errexit "this must be run by root user" | ||
28 | fi | ||
29 | |||
30 | # Utilities | ||
31 | absdir() { # file_path | ||
32 | (cd `dirname $1`; pwd) | ||
33 | } | ||
34 | |||
35 | abspath() { | ||
36 | echo `absdir $1`/`basename $1` | ||
37 | } | ||
38 | |||
39 | find_testcases() { #directory | ||
40 | echo `find $1 -name \*.tc` | ||
41 | } | ||
42 | |||
43 | parse_opts() { # opts | ||
44 | local OPT_TEST_CASES= | ||
45 | local OPT_TEST_DIR= | ||
46 | |||
47 | while [ "$1" ]; do | ||
48 | case "$1" in | ||
49 | --help|-h) | ||
50 | usage 0 | ||
51 | ;; | ||
52 | --keep|-k) | ||
53 | KEEP_LOG=1 | ||
54 | shift 1 | ||
55 | ;; | ||
56 | --debug|-d) | ||
57 | DEBUG=1 | ||
58 | shift 1 | ||
59 | ;; | ||
60 | *.tc) | ||
61 | if [ -f "$1" ]; then | ||
62 | OPT_TEST_CASES="$OPT_TEST_CASES `abspath $1`" | ||
63 | shift 1 | ||
64 | else | ||
65 | usage 1 "$1 is not a testcase" | ||
66 | fi | ||
67 | ;; | ||
68 | *) | ||
69 | if [ -d "$1" ]; then | ||
70 | OPT_TEST_DIR=`abspath $1` | ||
71 | OPT_TEST_CASES="$OPT_TEST_CASES `find_testcases $OPT_TEST_DIR`" | ||
72 | shift 1 | ||
73 | else | ||
74 | usage 1 "Invalid option ($1)" | ||
75 | fi | ||
76 | ;; | ||
77 | esac | ||
78 | done | ||
79 | if [ "$OPT_TEST_CASES" ]; then | ||
80 | TEST_CASES=$OPT_TEST_CASES | ||
81 | fi | ||
82 | } | ||
83 | |||
84 | # Parameters | ||
85 | DEBUGFS_DIR=`grep debugfs /proc/mounts | cut -f2 -d' '` | ||
86 | TRACING_DIR=$DEBUGFS_DIR/tracing | ||
87 | TOP_DIR=`absdir $0` | ||
88 | TEST_DIR=$TOP_DIR/test.d | ||
89 | TEST_CASES=`find_testcases $TEST_DIR` | ||
90 | LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`/ | ||
91 | KEEP_LOG=0 | ||
92 | DEBUG=0 | ||
93 | # Parse command-line options | ||
94 | parse_opts $* | ||
95 | |||
96 | [ $DEBUG -ne 0 ] && set -x | ||
97 | |||
98 | # Verify parameters | ||
99 | if [ -z "$DEBUGFS_DIR" -o ! -d "$TRACING_DIR" ]; then | ||
100 | errexit "No ftrace directory found" | ||
101 | fi | ||
102 | |||
103 | # Preparing logs | ||
104 | LOG_FILE=$LOG_DIR/ftracetest.log | ||
105 | mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR" | ||
106 | date > $LOG_FILE | ||
107 | prlog() { # messages | ||
108 | echo "$@" | tee -a $LOG_FILE | ||
109 | } | ||
110 | catlog() { #file | ||
111 | cat $1 | tee -a $LOG_FILE | ||
112 | } | ||
113 | prlog "=== Ftrace unit tests ===" | ||
114 | |||
115 | |||
116 | # Testcase management | ||
117 | # Test result codes - Dejagnu extended code | ||
118 | PASS=0 # The test succeeded. | ||
119 | FAIL=1 # The test failed, but was expected to succeed. | ||
120 | UNRESOLVED=2 # The test produced indeterminate results. (e.g. interrupted) | ||
121 | UNTESTED=3 # The test was not run, currently just a placeholder. | ||
122 | UNSUPPORTED=4 # The test failed because of lack of feature. | ||
123 | XFAIL=5 # The test failed, and was expected to fail. | ||
124 | |||
125 | # Accumulations | ||
126 | PASSED_CASES= | ||
127 | FAILED_CASES= | ||
128 | UNRESOLVED_CASES= | ||
129 | UNTESTED_CASES= | ||
130 | UNSUPPORTED_CASES= | ||
131 | XFAILED_CASES= | ||
132 | UNDEFINED_CASES= | ||
133 | TOTAL_RESULT=0 | ||
134 | |||
135 | CASENO=0 | ||
136 | testcase() { # testfile | ||
137 | CASENO=$((CASENO+1)) | ||
138 | prlog -n "[$CASENO]"`grep "^#[ \t]*description:" $1 | cut -f2 -d:` | ||
139 | } | ||
140 | |||
141 | eval_result() { # retval sigval | ||
142 | local retval=$2 | ||
143 | if [ $2 -eq 0 ]; then | ||
144 | test $1 -ne 0 && retval=$FAIL | ||
145 | fi | ||
146 | case $retval in | ||
147 | $PASS) | ||
148 | prlog " [PASS]" | ||
149 | PASSED_CASES="$PASSED_CASES $CASENO" | ||
150 | return 0 | ||
151 | ;; | ||
152 | $FAIL) | ||
153 | prlog " [FAIL]" | ||
154 | FAILED_CASES="$FAILED_CASES $CASENO" | ||
155 | return 1 # this is a bug. | ||
156 | ;; | ||
157 | $UNRESOLVED) | ||
158 | prlog " [UNRESOLVED]" | ||
159 | UNRESOLVED_CASES="$UNRESOLVED_CASES $CASENO" | ||
160 | return 1 # this is a kind of bug.. something happened. | ||
161 | ;; | ||
162 | $UNTESTED) | ||
163 | prlog " [UNTESTED]" | ||
164 | UNTESTED_CASES="$UNTESTED_CASES $CASENO" | ||
165 | return 0 | ||
166 | ;; | ||
167 | $UNSUPPORTED) | ||
168 | prlog " [UNSUPPORTED]" | ||
169 | UNSUPPORTED_CASES="$UNSUPPORTED_CASES $CASENO" | ||
170 | return 1 # this is not a bug, but the result should be reported. | ||
171 | ;; | ||
172 | $XFAIL) | ||
173 | prlog " [XFAIL]" | ||
174 | XFAILED_CASES="$XFAILED_CASES $CASENO" | ||
175 | return 0 | ||
176 | ;; | ||
177 | *) | ||
178 | prlog " [UNDEFINED]" | ||
179 | UNDEFINED_CASES="$UNDEFINED_CASES $CASENO" | ||
180 | return 1 # this must be a test bug | ||
181 | ;; | ||
182 | esac | ||
183 | } | ||
184 | |||
185 | # Signal handling for result codes | ||
186 | SIG_RESULT= | ||
187 | SIG_BASE=36 # Use realtime signals | ||
188 | SIG_PID=$$ | ||
189 | |||
190 | SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED)) | ||
191 | exit_unresolved () { | ||
192 | kill -s $SIG_UNRESOLVED $SIG_PID | ||
193 | exit 0 | ||
194 | } | ||
195 | trap 'SIG_RESULT=$UNRESOLVED' $SIG_UNRESOLVED | ||
196 | |||
197 | SIG_UNTESTED=$((SIG_BASE + UNTESTED)) | ||
198 | exit_untested () { | ||
199 | kill -s $SIG_UNTESTED $SIG_PID | ||
200 | exit 0 | ||
201 | } | ||
202 | trap 'SIG_RESULT=$UNTESTED' $SIG_UNTESTED | ||
203 | |||
204 | SIG_UNSUPPORTED=$((SIG_BASE + UNSUPPORTED)) | ||
205 | exit_unsupported () { | ||
206 | kill -s $SIG_UNSUPPORTED $SIG_PID | ||
207 | exit 0 | ||
208 | } | ||
209 | trap 'SIG_RESULT=$UNSUPPORTED' $SIG_UNSUPPORTED | ||
210 | |||
211 | SIG_XFAIL=$((SIG_BASE + XFAIL)) | ||
212 | exit_xfail () { | ||
213 | kill -s $SIG_XFAIL $SIG_PID | ||
214 | exit 0 | ||
215 | } | ||
216 | trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL | ||
217 | |||
218 | # Run one test case | ||
219 | run_test() { # testfile | ||
220 | local testname=`basename $1` | ||
221 | local testlog=`mktemp --tmpdir=$LOG_DIR ${testname}-XXXXXX.log` | ||
222 | testcase $1 | ||
223 | echo "execute: "$1 > $testlog | ||
224 | SIG_RESULT=0 | ||
225 | # setup PID and PPID, $$ is not updated. | ||
226 | (cd $TRACING_DIR; read PID _ < /proc/self/stat ; | ||
227 | set -e; set -x; . $1) >> $testlog 2>&1 | ||
228 | eval_result $? $SIG_RESULT | ||
229 | if [ $? -eq 0 ]; then | ||
230 | # Remove test log if the test was done as it was expected. | ||
231 | [ $KEEP_LOG -eq 0 ] && rm $testlog | ||
232 | else | ||
233 | catlog $testlog | ||
234 | TOTAL_RESULT=1 | ||
235 | fi | ||
236 | } | ||
237 | |||
238 | # Main loop | ||
239 | for t in $TEST_CASES; do | ||
240 | run_test $t | ||
241 | done | ||
242 | |||
243 | prlog "" | ||
244 | prlog "# of passed: " `echo $PASSED_CASES | wc -w` | ||
245 | prlog "# of failed: " `echo $FAILED_CASES | wc -w` | ||
246 | prlog "# of unresolved: " `echo $UNRESOLVED_CASES | wc -w` | ||
247 | prlog "# of untested: " `echo $UNTESTED_CASES | wc -w` | ||
248 | prlog "# of unsupported: " `echo $UNSUPPORTED_CASES | wc -w` | ||
249 | prlog "# of xfailed: " `echo $XFAILED_CASES | wc -w` | ||
250 | prlog "# of undefined(test bug): " `echo $UNDEFINED_CASES | wc -w` | ||
251 | |||
252 | # if no error, return 0 | ||
253 | exit $TOTAL_RESULT | ||
diff --git a/tools/testing/selftests/ftrace/samples/fail.tc b/tools/testing/selftests/ftrace/samples/fail.tc new file mode 100644 index 000000000000..15e35b956e05 --- /dev/null +++ b/tools/testing/selftests/ftrace/samples/fail.tc | |||
@@ -0,0 +1,4 @@ | |||
1 | #!/bin/sh | ||
2 | # description: failure-case example | ||
3 | cat non-exist-file | ||
4 | echo "this is not executed" | ||
diff --git a/tools/testing/selftests/ftrace/samples/pass.tc b/tools/testing/selftests/ftrace/samples/pass.tc new file mode 100644 index 000000000000..d01549370041 --- /dev/null +++ b/tools/testing/selftests/ftrace/samples/pass.tc | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | # description: pass-case example | ||
3 | return 0 | ||
diff --git a/tools/testing/selftests/ftrace/samples/unresolved.tc b/tools/testing/selftests/ftrace/samples/unresolved.tc new file mode 100644 index 000000000000..41e99d3358d1 --- /dev/null +++ b/tools/testing/selftests/ftrace/samples/unresolved.tc | |||
@@ -0,0 +1,4 @@ | |||
1 | #!/bin/sh | ||
2 | # description: unresolved-case example | ||
3 | trap exit_unresolved INT | ||
4 | kill -INT $PID | ||
diff --git a/tools/testing/selftests/ftrace/samples/unsupported.tc b/tools/testing/selftests/ftrace/samples/unsupported.tc new file mode 100644 index 000000000000..45910ff13328 --- /dev/null +++ b/tools/testing/selftests/ftrace/samples/unsupported.tc | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | # description: unsupported-case example | ||
3 | exit_unsupported | ||
diff --git a/tools/testing/selftests/ftrace/samples/untested.tc b/tools/testing/selftests/ftrace/samples/untested.tc new file mode 100644 index 000000000000..35a45946ec60 --- /dev/null +++ b/tools/testing/selftests/ftrace/samples/untested.tc | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | # description: untested-case example | ||
3 | exit_untested | ||
diff --git a/tools/testing/selftests/ftrace/samples/xfail.tc b/tools/testing/selftests/ftrace/samples/xfail.tc new file mode 100644 index 000000000000..9dd395323259 --- /dev/null +++ b/tools/testing/selftests/ftrace/samples/xfail.tc | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | # description: xfail-case example | ||
3 | cat non-exist-file || exit_xfail | ||
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc new file mode 100644 index 000000000000..9980ff14ae44 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/00basic/basic1.tc | |||
@@ -0,0 +1,3 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Basic trace file check | ||
3 | test -f README -a -f trace -a -f tracing_on -a -f trace_pipe | ||
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc new file mode 100644 index 000000000000..bf9a7b037924 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/00basic/basic2.tc | |||
@@ -0,0 +1,7 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Basic test for tracers | ||
3 | test -f available_tracers | ||
4 | for t in `cat available_tracers`; do | ||
5 | echo $t > current_tracer | ||
6 | done | ||
7 | echo nop > current_tracer | ||
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc new file mode 100644 index 000000000000..bde6625d9785 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/00basic/basic3.tc | |||
@@ -0,0 +1,8 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Basic trace clock test | ||
3 | test -f trace_clock | ||
4 | for c in `cat trace_clock | tr -d \[\]`; do | ||
5 | echo $c > trace_clock | ||
6 | grep '\['$c'\]' trace_clock | ||
7 | done | ||
8 | echo local > trace_clock | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc new file mode 100644 index 000000000000..1b8b665ab2b3 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc | |||
@@ -0,0 +1,11 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Kprobe dynamic event - adding and removing | ||
3 | |||
4 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
5 | |||
6 | echo 0 > events/enable | ||
7 | echo > kprobe_events | ||
8 | echo p:myevent do_fork > kprobe_events | ||
9 | grep myevent kprobe_events | ||
10 | test -d events/kprobes/myevent | ||
11 | echo > kprobe_events | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc new file mode 100644 index 000000000000..b55c84003587 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc | |||
@@ -0,0 +1,13 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Kprobe dynamic event - busy event check | ||
3 | |||
4 | [ -f kprobe_events ] || exit_unsupported | ||
5 | |||
6 | echo 0 > events/enable | ||
7 | echo > kprobe_events | ||
8 | echo p:myevent do_fork > kprobe_events | ||
9 | test -d events/kprobes/myevent | ||
10 | echo 1 > events/kprobes/myevent/enable | ||
11 | echo > kprobe_events && exit 1 # this must fail | ||
12 | echo 0 > events/kprobes/myevent/enable | ||
13 | echo > kprobe_events # this must succeed | ||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc new file mode 100644 index 000000000000..a603d3f8db7b --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc | |||
@@ -0,0 +1,16 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Kprobe dynamic event with arguments | ||
3 | |||
4 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
5 | |||
6 | echo 0 > events/enable | ||
7 | echo > kprobe_events | ||
8 | echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events | ||
9 | grep testprobe kprobe_events | ||
10 | test -d events/kprobes/testprobe | ||
11 | echo 1 > events/kprobes/testprobe/enable | ||
12 | ( echo "forked") | ||
13 | echo 0 > events/kprobes/testprobe/enable | ||
14 | echo "-:testprobe" >> kprobe_events | ||
15 | test -d events/kprobes/testprobe && exit 1 || exit 0 | ||
16 | |||
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc new file mode 100644 index 000000000000..283c29e7f7c4 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc | |||
@@ -0,0 +1,15 @@ | |||
1 | #!/bin/sh | ||
2 | # description: Kretprobe dynamic event with arguments | ||
3 | |||
4 | [ -f kprobe_events ] || exit_unsupported # this is configurable | ||
5 | |||
6 | echo 0 > events/enable | ||
7 | echo > kprobe_events | ||
8 | echo 'r:testprobe2 do_fork $retval' > kprobe_events | ||
9 | grep testprobe2 kprobe_events | ||
10 | test -d events/kprobes/testprobe2 | ||
11 | echo 1 > events/kprobes/testprobe2/enable | ||
12 | ( echo "forked") | ||
13 | echo 0 > events/kprobes/testprobe2/enable | ||
14 | echo '-:testprobe2' >> kprobe_events | ||
15 | test -d events/kprobes/testprobe2 && exit 1 || exit 0 | ||
diff --git a/tools/testing/selftests/ftrace/test.d/template b/tools/testing/selftests/ftrace/test.d/template new file mode 100644 index 000000000000..5448f7abad5f --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/template | |||
@@ -0,0 +1,9 @@ | |||
1 | #!/bin/sh | ||
2 | # description: %HERE DESCRIBE WHAT THIS DOES% | ||
3 | # you have to add ".tc" extention for your testcase file | ||
4 | # Note that all tests are run with "errexit" option. | ||
5 | |||
6 | exit 0 # Return 0 if the test is passed, otherwise return !0 | ||
7 | # If the test could not run because of lack of feature, call exit_unsupported | ||
8 | # If the test returned unclear results, call exit_unresolved | ||
9 | # If the test is a dummy, or a placeholder, call exit_untested | ||
diff --git a/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index 74a78cedce37..f6ff90a76bd7 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile | |||
@@ -13,7 +13,7 @@ CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CUR | |||
13 | 13 | ||
14 | export CC CFLAGS | 14 | export CC CFLAGS |
15 | 15 | ||
16 | TARGETS = pmu copyloops mm tm | 16 | TARGETS = pmu copyloops mm tm primitives |
17 | 17 | ||
18 | endif | 18 | endif |
19 | 19 | ||
diff --git a/tools/testing/selftests/powerpc/primitives/Makefile b/tools/testing/selftests/powerpc/primitives/Makefile new file mode 100644 index 000000000000..ea737ca01732 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | CFLAGS += -I$(CURDIR) | ||
2 | |||
3 | PROGS := load_unaligned_zeropad | ||
4 | |||
5 | all: $(PROGS) | ||
6 | |||
7 | $(PROGS): ../harness.c | ||
8 | |||
9 | run_tests: all | ||
10 | @-for PROG in $(PROGS); do \ | ||
11 | ./$$PROG; \ | ||
12 | done; | ||
13 | |||
14 | clean: | ||
15 | rm -f $(PROGS) *.o | ||
16 | |||
17 | .PHONY: all run_tests clean | ||
diff --git a/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h new file mode 120000 index 000000000000..b14255e15a25 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h | |||
@@ -0,0 +1 @@ | |||
../.././../../../../arch/powerpc/include/asm/asm-compat.h \ No newline at end of file | |||
diff --git a/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/asm/ppc-opcode.h | |||
diff --git a/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c new file mode 100644 index 000000000000..d1b647509596 --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/load_unaligned_zeropad.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * Userspace test harness for load_unaligned_zeropad. Creates two | ||
3 | * pages and uses mprotect to prevent access to the second page and | ||
4 | * a SEGV handler that walks the exception tables and runs the fixup | ||
5 | * routine. | ||
6 | * | ||
7 | * The results are compared against a normal load that is that is | ||
8 | * performed while access to the second page is enabled via mprotect. | ||
9 | * | ||
10 | * Copyright (C) 2014 Anton Blanchard <anton@au.ibm.com>, IBM | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version | ||
15 | * 2 of the License, or (at your option) any later version. | ||
16 | */ | ||
17 | |||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdbool.h> | ||
22 | #include <signal.h> | ||
23 | #include <unistd.h> | ||
24 | #include <sys/mman.h> | ||
25 | |||
26 | #define FIXUP_SECTION ".ex_fixup" | ||
27 | |||
28 | #include "word-at-a-time.h" | ||
29 | |||
30 | #include "utils.h" | ||
31 | |||
32 | |||
33 | static int page_size; | ||
34 | static char *mem_region; | ||
35 | |||
36 | static int protect_region(void) | ||
37 | { | ||
38 | if (mprotect(mem_region + page_size, page_size, PROT_NONE)) { | ||
39 | perror("mprotect"); | ||
40 | return 1; | ||
41 | } | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int unprotect_region(void) | ||
47 | { | ||
48 | if (mprotect(mem_region + page_size, page_size, PROT_READ|PROT_WRITE)) { | ||
49 | perror("mprotect"); | ||
50 | return 1; | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | extern char __start___ex_table[]; | ||
57 | extern char __stop___ex_table[]; | ||
58 | |||
59 | #if defined(__powerpc64__) | ||
60 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.gp_regs[PT_NIP] | ||
61 | #elif defined(__powerpc__) | ||
62 | #define UCONTEXT_NIA(UC) (UC)->uc_mcontext.uc_regs->gregs[PT_NIP] | ||
63 | #else | ||
64 | #error implement UCONTEXT_NIA | ||
65 | #endif | ||
66 | |||
67 | static int segv_error; | ||
68 | |||
69 | static void segv_handler(int signr, siginfo_t *info, void *ptr) | ||
70 | { | ||
71 | ucontext_t *uc = (ucontext_t *)ptr; | ||
72 | unsigned long addr = (unsigned long)info->si_addr; | ||
73 | unsigned long *ip = &UCONTEXT_NIA(uc); | ||
74 | unsigned long *ex_p = (unsigned long *)__start___ex_table; | ||
75 | |||
76 | while (ex_p < (unsigned long *)__stop___ex_table) { | ||
77 | unsigned long insn, fixup; | ||
78 | |||
79 | insn = *ex_p++; | ||
80 | fixup = *ex_p++; | ||
81 | |||
82 | if (insn == *ip) { | ||
83 | *ip = fixup; | ||
84 | return; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | printf("No exception table match for NIA %lx ADDR %lx\n", *ip, addr); | ||
89 | segv_error++; | ||
90 | } | ||
91 | |||
92 | static void setup_segv_handler(void) | ||
93 | { | ||
94 | struct sigaction action; | ||
95 | |||
96 | memset(&action, 0, sizeof(action)); | ||
97 | action.sa_sigaction = segv_handler; | ||
98 | action.sa_flags = SA_SIGINFO; | ||
99 | sigaction(SIGSEGV, &action, NULL); | ||
100 | } | ||
101 | |||
102 | static int do_one_test(char *p, int page_offset) | ||
103 | { | ||
104 | unsigned long should; | ||
105 | unsigned long got; | ||
106 | |||
107 | FAIL_IF(unprotect_region()); | ||
108 | should = *(unsigned long *)p; | ||
109 | FAIL_IF(protect_region()); | ||
110 | |||
111 | got = load_unaligned_zeropad(p); | ||
112 | |||
113 | if (should != got) | ||
114 | printf("offset %u load_unaligned_zeropad returned 0x%lx, should be 0x%lx\n", page_offset, got, should); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int test_body(void) | ||
120 | { | ||
121 | unsigned long i; | ||
122 | |||
123 | page_size = getpagesize(); | ||
124 | mem_region = mmap(NULL, page_size * 2, PROT_READ|PROT_WRITE, | ||
125 | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | ||
126 | |||
127 | FAIL_IF(mem_region == MAP_FAILED); | ||
128 | |||
129 | for (i = 0; i < page_size; i++) | ||
130 | mem_region[i] = i; | ||
131 | |||
132 | memset(mem_region+page_size, 0, page_size); | ||
133 | |||
134 | setup_segv_handler(); | ||
135 | |||
136 | for (i = 0; i < page_size; i++) | ||
137 | FAIL_IF(do_one_test(mem_region+i, i)); | ||
138 | |||
139 | FAIL_IF(segv_error); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | int main(void) | ||
145 | { | ||
146 | return test_harness(test_body, "load_unaligned_zeropad"); | ||
147 | } | ||
diff --git a/tools/testing/selftests/powerpc/primitives/word-at-a-time.h b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h new file mode 120000 index 000000000000..eb74401b591f --- /dev/null +++ b/tools/testing/selftests/powerpc/primitives/word-at-a-time.h | |||
@@ -0,0 +1 @@ | |||
../../../../../arch/powerpc/include/asm/word-at-a-time.h \ No newline at end of file | |||
diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 3f94e1afd6cf..4c4b1f631ecf 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | CC = $(CROSS_COMPILE)gcc | 3 | CC = $(CROSS_COMPILE)gcc |
4 | CFLAGS = -Wall | 4 | CFLAGS = -Wall |
5 | BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest | 5 | BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest |
6 | BINARIES += transhuge-stress | ||
6 | 7 | ||
7 | all: $(BINARIES) | 8 | all: $(BINARIES) |
8 | %: %.c | 9 | %: %.c |
diff --git a/tools/testing/selftests/vm/transhuge-stress.c b/tools/testing/selftests/vm/transhuge-stress.c new file mode 100644 index 000000000000..fd7f1b4a96f9 --- /dev/null +++ b/tools/testing/selftests/vm/transhuge-stress.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * Stress test for transparent huge pages, memory compaction and migration. | ||
3 | * | ||
4 | * Authors: Konstantin Khlebnikov <koct9i@gmail.com> | ||
5 | * | ||
6 | * This is free and unencumbered software released into the public domain. | ||
7 | */ | ||
8 | |||
9 | #include <stdlib.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdint.h> | ||
12 | #include <err.h> | ||
13 | #include <time.h> | ||
14 | #include <unistd.h> | ||
15 | #include <fcntl.h> | ||
16 | #include <string.h> | ||
17 | #include <sys/mman.h> | ||
18 | |||
19 | #define PAGE_SHIFT 12 | ||
20 | #define HPAGE_SHIFT 21 | ||
21 | |||
22 | #define PAGE_SIZE (1 << PAGE_SHIFT) | ||
23 | #define HPAGE_SIZE (1 << HPAGE_SHIFT) | ||
24 | |||
25 | #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0) | ||
26 | #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1)) | ||
27 | |||
28 | int pagemap_fd; | ||
29 | |||
30 | int64_t allocate_transhuge(void *ptr) | ||
31 | { | ||
32 | uint64_t ent[2]; | ||
33 | |||
34 | /* drop pmd */ | ||
35 | if (mmap(ptr, HPAGE_SIZE, PROT_READ | PROT_WRITE, | ||
36 | MAP_FIXED | MAP_ANONYMOUS | | ||
37 | MAP_NORESERVE | MAP_PRIVATE, -1, 0) != ptr) | ||
38 | errx(2, "mmap transhuge"); | ||
39 | |||
40 | if (madvise(ptr, HPAGE_SIZE, MADV_HUGEPAGE)) | ||
41 | err(2, "MADV_HUGEPAGE"); | ||
42 | |||
43 | /* allocate transparent huge page */ | ||
44 | *(volatile void **)ptr = ptr; | ||
45 | |||
46 | if (pread(pagemap_fd, ent, sizeof(ent), | ||
47 | (uintptr_t)ptr >> (PAGE_SHIFT - 3)) != sizeof(ent)) | ||
48 | err(2, "read pagemap"); | ||
49 | |||
50 | if (PAGEMAP_PRESENT(ent[0]) && PAGEMAP_PRESENT(ent[1]) && | ||
51 | PAGEMAP_PFN(ent[0]) + 1 == PAGEMAP_PFN(ent[1]) && | ||
52 | !(PAGEMAP_PFN(ent[0]) & ((1 << (HPAGE_SHIFT - PAGE_SHIFT)) - 1))) | ||
53 | return PAGEMAP_PFN(ent[0]); | ||
54 | |||
55 | return -1; | ||
56 | } | ||
57 | |||
58 | int main(int argc, char **argv) | ||
59 | { | ||
60 | size_t ram, len; | ||
61 | void *ptr, *p; | ||
62 | struct timespec a, b; | ||
63 | double s; | ||
64 | uint8_t *map; | ||
65 | size_t map_len; | ||
66 | |||
67 | ram = sysconf(_SC_PHYS_PAGES); | ||
68 | if (ram > SIZE_MAX / sysconf(_SC_PAGESIZE) / 4) | ||
69 | ram = SIZE_MAX / 4; | ||
70 | else | ||
71 | ram *= sysconf(_SC_PAGESIZE); | ||
72 | |||
73 | if (argc == 1) | ||
74 | len = ram; | ||
75 | else if (!strcmp(argv[1], "-h")) | ||
76 | errx(1, "usage: %s [size in MiB]", argv[0]); | ||
77 | else | ||
78 | len = atoll(argv[1]) << 20; | ||
79 | |||
80 | warnx("allocate %zd transhuge pages, using %zd MiB virtual memory" | ||
81 | " and %zd MiB of ram", len >> HPAGE_SHIFT, len >> 20, | ||
82 | len >> (20 + HPAGE_SHIFT - PAGE_SHIFT - 1)); | ||
83 | |||
84 | pagemap_fd = open("/proc/self/pagemap", O_RDONLY); | ||
85 | if (pagemap_fd < 0) | ||
86 | err(2, "open pagemap"); | ||
87 | |||
88 | len -= len % HPAGE_SIZE; | ||
89 | ptr = mmap(NULL, len + HPAGE_SIZE, PROT_READ | PROT_WRITE, | ||
90 | MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0); | ||
91 | if (ptr == MAP_FAILED) | ||
92 | err(2, "initial mmap"); | ||
93 | ptr += HPAGE_SIZE - (uintptr_t)ptr % HPAGE_SIZE; | ||
94 | |||
95 | if (madvise(ptr, len, MADV_HUGEPAGE)) | ||
96 | err(2, "MADV_HUGEPAGE"); | ||
97 | |||
98 | map_len = ram >> (HPAGE_SHIFT - 1); | ||
99 | map = malloc(map_len); | ||
100 | if (!map) | ||
101 | errx(2, "map malloc"); | ||
102 | |||
103 | while (1) { | ||
104 | int nr_succeed = 0, nr_failed = 0, nr_pages = 0; | ||
105 | |||
106 | memset(map, 0, map_len); | ||
107 | |||
108 | clock_gettime(CLOCK_MONOTONIC, &a); | ||
109 | for (p = ptr; p < ptr + len; p += HPAGE_SIZE) { | ||
110 | int64_t pfn; | ||
111 | |||
112 | pfn = allocate_transhuge(p); | ||
113 | |||
114 | if (pfn < 0) { | ||
115 | nr_failed++; | ||
116 | } else { | ||
117 | size_t idx = pfn >> (HPAGE_SHIFT - PAGE_SHIFT); | ||
118 | |||
119 | nr_succeed++; | ||
120 | if (idx >= map_len) { | ||
121 | map = realloc(map, idx + 1); | ||
122 | if (!map) | ||
123 | errx(2, "map realloc"); | ||
124 | memset(map + map_len, 0, idx + 1 - map_len); | ||
125 | map_len = idx + 1; | ||
126 | } | ||
127 | if (!map[idx]) | ||
128 | nr_pages++; | ||
129 | map[idx] = 1; | ||
130 | } | ||
131 | |||
132 | /* split transhuge page, keep last page */ | ||
133 | if (madvise(p, HPAGE_SIZE - PAGE_SIZE, MADV_DONTNEED)) | ||
134 | err(2, "MADV_DONTNEED"); | ||
135 | } | ||
136 | clock_gettime(CLOCK_MONOTONIC, &b); | ||
137 | s = b.tv_sec - a.tv_sec + (b.tv_nsec - a.tv_nsec) / 1000000000.; | ||
138 | |||
139 | warnx("%.3f s/loop, %.3f ms/page, %10.3f MiB/s\t" | ||
140 | "%4d succeed, %4d failed, %4d different pages", | ||
141 | s, s * 1000 / (len >> HPAGE_SHIFT), len / s / (1 << 20), | ||
142 | nr_succeed, nr_failed, nr_pages); | ||
143 | } | ||
144 | } | ||