diff options
| author | Ingo Molnar <mingo@kernel.org> | 2018-10-23 06:30:19 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2018-10-23 06:30:19 -0400 |
| commit | dda93b45389f025fd3422d22cc31cc1ea6040305 (patch) | |
| tree | 44a856744843e24ed1baf6ca4edb1be04809a606 /tools/testing/selftests | |
| parent | 2e62024c265aa69315ed02835623740030435380 (diff) | |
| parent | b61b8bba18fe2b63d38fdaf9b83de25e2d787dfe (diff) | |
Merge branch 'x86/cache' into perf/core, to pick up fixes
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/testing/selftests')
| -rw-r--r-- | tools/testing/selftests/rseq/param_test.c | 19 | ||||
| -rw-r--r-- | tools/testing/selftests/x86/test_vdso.c | 172 |
2 files changed, 182 insertions, 9 deletions
diff --git a/tools/testing/selftests/rseq/param_test.c b/tools/testing/selftests/rseq/param_test.c index 642d4e12abea..eec2663261f2 100644 --- a/tools/testing/selftests/rseq/param_test.c +++ b/tools/testing/selftests/rseq/param_test.c | |||
| @@ -56,15 +56,13 @@ unsigned int yield_mod_cnt, nr_abort; | |||
| 56 | printf(fmt, ## __VA_ARGS__); \ | 56 | printf(fmt, ## __VA_ARGS__); \ |
| 57 | } while (0) | 57 | } while (0) |
| 58 | 58 | ||
| 59 | #if defined(__x86_64__) || defined(__i386__) | 59 | #ifdef __i386__ |
| 60 | 60 | ||
| 61 | #define INJECT_ASM_REG "eax" | 61 | #define INJECT_ASM_REG "eax" |
| 62 | 62 | ||
| 63 | #define RSEQ_INJECT_CLOBBER \ | 63 | #define RSEQ_INJECT_CLOBBER \ |
| 64 | , INJECT_ASM_REG | 64 | , INJECT_ASM_REG |
| 65 | 65 | ||
| 66 | #ifdef __i386__ | ||
| 67 | |||
| 68 | #define RSEQ_INJECT_ASM(n) \ | 66 | #define RSEQ_INJECT_ASM(n) \ |
| 69 | "mov asm_loop_cnt_" #n ", %%" INJECT_ASM_REG "\n\t" \ | 67 | "mov asm_loop_cnt_" #n ", %%" INJECT_ASM_REG "\n\t" \ |
| 70 | "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ | 68 | "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ |
| @@ -76,9 +74,16 @@ unsigned int yield_mod_cnt, nr_abort; | |||
| 76 | 74 | ||
| 77 | #elif defined(__x86_64__) | 75 | #elif defined(__x86_64__) |
| 78 | 76 | ||
| 77 | #define INJECT_ASM_REG_P "rax" | ||
| 78 | #define INJECT_ASM_REG "eax" | ||
| 79 | |||
| 80 | #define RSEQ_INJECT_CLOBBER \ | ||
| 81 | , INJECT_ASM_REG_P \ | ||
| 82 | , INJECT_ASM_REG | ||
| 83 | |||
| 79 | #define RSEQ_INJECT_ASM(n) \ | 84 | #define RSEQ_INJECT_ASM(n) \ |
| 80 | "lea asm_loop_cnt_" #n "(%%rip), %%" INJECT_ASM_REG "\n\t" \ | 85 | "lea asm_loop_cnt_" #n "(%%rip), %%" INJECT_ASM_REG_P "\n\t" \ |
| 81 | "mov (%%" INJECT_ASM_REG "), %%" INJECT_ASM_REG "\n\t" \ | 86 | "mov (%%" INJECT_ASM_REG_P "), %%" INJECT_ASM_REG "\n\t" \ |
| 82 | "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ | 87 | "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ |
| 83 | "jz 333f\n\t" \ | 88 | "jz 333f\n\t" \ |
| 84 | "222:\n\t" \ | 89 | "222:\n\t" \ |
| @@ -86,10 +91,6 @@ unsigned int yield_mod_cnt, nr_abort; | |||
| 86 | "jnz 222b\n\t" \ | 91 | "jnz 222b\n\t" \ |
| 87 | "333:\n\t" | 92 | "333:\n\t" |
| 88 | 93 | ||
| 89 | #else | ||
| 90 | #error "Unsupported architecture" | ||
| 91 | #endif | ||
| 92 | |||
| 93 | #elif defined(__s390__) | 94 | #elif defined(__s390__) |
| 94 | 95 | ||
| 95 | #define RSEQ_INJECT_INPUT \ | 96 | #define RSEQ_INJECT_INPUT \ |
diff --git a/tools/testing/selftests/x86/test_vdso.c b/tools/testing/selftests/x86/test_vdso.c index 235259011704..35edd61d1663 100644 --- a/tools/testing/selftests/x86/test_vdso.c +++ b/tools/testing/selftests/x86/test_vdso.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <errno.h> | 17 | #include <errno.h> |
| 18 | #include <sched.h> | 18 | #include <sched.h> |
| 19 | #include <stdbool.h> | 19 | #include <stdbool.h> |
| 20 | #include <limits.h> | ||
| 20 | 21 | ||
| 21 | #ifndef SYS_getcpu | 22 | #ifndef SYS_getcpu |
| 22 | # ifdef __x86_64__ | 23 | # ifdef __x86_64__ |
| @@ -31,6 +32,14 @@ | |||
| 31 | 32 | ||
| 32 | int nerrs = 0; | 33 | int nerrs = 0; |
| 33 | 34 | ||
| 35 | typedef int (*vgettime_t)(clockid_t, struct timespec *); | ||
| 36 | |||
| 37 | vgettime_t vdso_clock_gettime; | ||
| 38 | |||
| 39 | typedef long (*vgtod_t)(struct timeval *tv, struct timezone *tz); | ||
| 40 | |||
| 41 | vgtod_t vdso_gettimeofday; | ||
| 42 | |||
| 34 | typedef long (*getcpu_t)(unsigned *, unsigned *, void *); | 43 | typedef long (*getcpu_t)(unsigned *, unsigned *, void *); |
| 35 | 44 | ||
| 36 | getcpu_t vgetcpu; | 45 | getcpu_t vgetcpu; |
| @@ -95,6 +104,15 @@ static void fill_function_pointers() | |||
| 95 | printf("Warning: failed to find getcpu in vDSO\n"); | 104 | printf("Warning: failed to find getcpu in vDSO\n"); |
| 96 | 105 | ||
| 97 | vgetcpu = (getcpu_t) vsyscall_getcpu(); | 106 | vgetcpu = (getcpu_t) vsyscall_getcpu(); |
| 107 | |||
| 108 | vdso_clock_gettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); | ||
| 109 | if (!vdso_clock_gettime) | ||
| 110 | printf("Warning: failed to find clock_gettime in vDSO\n"); | ||
| 111 | |||
| 112 | vdso_gettimeofday = (vgtod_t)dlsym(vdso, "__vdso_gettimeofday"); | ||
| 113 | if (!vdso_gettimeofday) | ||
| 114 | printf("Warning: failed to find gettimeofday in vDSO\n"); | ||
| 115 | |||
| 98 | } | 116 | } |
| 99 | 117 | ||
| 100 | static long sys_getcpu(unsigned * cpu, unsigned * node, | 118 | static long sys_getcpu(unsigned * cpu, unsigned * node, |
| @@ -103,6 +121,16 @@ static long sys_getcpu(unsigned * cpu, unsigned * node, | |||
| 103 | return syscall(__NR_getcpu, cpu, node, cache); | 121 | return syscall(__NR_getcpu, cpu, node, cache); |
| 104 | } | 122 | } |
| 105 | 123 | ||
| 124 | static inline int sys_clock_gettime(clockid_t id, struct timespec *ts) | ||
| 125 | { | ||
| 126 | return syscall(__NR_clock_gettime, id, ts); | ||
| 127 | } | ||
| 128 | |||
| 129 | static inline int sys_gettimeofday(struct timeval *tv, struct timezone *tz) | ||
| 130 | { | ||
| 131 | return syscall(__NR_gettimeofday, tv, tz); | ||
| 132 | } | ||
| 133 | |||
| 106 | static void test_getcpu(void) | 134 | static void test_getcpu(void) |
| 107 | { | 135 | { |
| 108 | printf("[RUN]\tTesting getcpu...\n"); | 136 | printf("[RUN]\tTesting getcpu...\n"); |
| @@ -155,10 +183,154 @@ static void test_getcpu(void) | |||
| 155 | } | 183 | } |
| 156 | } | 184 | } |
| 157 | 185 | ||
| 186 | static bool ts_leq(const struct timespec *a, const struct timespec *b) | ||
| 187 | { | ||
| 188 | if (a->tv_sec != b->tv_sec) | ||
| 189 | return a->tv_sec < b->tv_sec; | ||
| 190 | else | ||
| 191 | return a->tv_nsec <= b->tv_nsec; | ||
| 192 | } | ||
| 193 | |||
| 194 | static bool tv_leq(const struct timeval *a, const struct timeval *b) | ||
| 195 | { | ||
| 196 | if (a->tv_sec != b->tv_sec) | ||
| 197 | return a->tv_sec < b->tv_sec; | ||
| 198 | else | ||
| 199 | return a->tv_usec <= b->tv_usec; | ||
| 200 | } | ||
| 201 | |||
| 202 | static char const * const clocknames[] = { | ||
| 203 | [0] = "CLOCK_REALTIME", | ||
| 204 | [1] = "CLOCK_MONOTONIC", | ||
| 205 | [2] = "CLOCK_PROCESS_CPUTIME_ID", | ||
| 206 | [3] = "CLOCK_THREAD_CPUTIME_ID", | ||
| 207 | [4] = "CLOCK_MONOTONIC_RAW", | ||
| 208 | [5] = "CLOCK_REALTIME_COARSE", | ||
| 209 | [6] = "CLOCK_MONOTONIC_COARSE", | ||
| 210 | [7] = "CLOCK_BOOTTIME", | ||
| 211 | [8] = "CLOCK_REALTIME_ALARM", | ||
| 212 | [9] = "CLOCK_BOOTTIME_ALARM", | ||
| 213 | [10] = "CLOCK_SGI_CYCLE", | ||
| 214 | [11] = "CLOCK_TAI", | ||
| 215 | }; | ||
| 216 | |||
| 217 | static void test_one_clock_gettime(int clock, const char *name) | ||
| 218 | { | ||
| 219 | struct timespec start, vdso, end; | ||
| 220 | int vdso_ret, end_ret; | ||
| 221 | |||
| 222 | printf("[RUN]\tTesting clock_gettime for clock %s (%d)...\n", name, clock); | ||
| 223 | |||
| 224 | if (sys_clock_gettime(clock, &start) < 0) { | ||
| 225 | if (errno == EINVAL) { | ||
| 226 | vdso_ret = vdso_clock_gettime(clock, &vdso); | ||
| 227 | if (vdso_ret == -EINVAL) { | ||
| 228 | printf("[OK]\tNo such clock.\n"); | ||
| 229 | } else { | ||
| 230 | printf("[FAIL]\tNo such clock, but __vdso_clock_gettime returned %d\n", vdso_ret); | ||
| 231 | nerrs++; | ||
| 232 | } | ||
| 233 | } else { | ||
| 234 | printf("[WARN]\t clock_gettime(%d) syscall returned error %d\n", clock, errno); | ||
| 235 | } | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | |||
| 239 | vdso_ret = vdso_clock_gettime(clock, &vdso); | ||
| 240 | end_ret = sys_clock_gettime(clock, &end); | ||
| 241 | |||
| 242 | if (vdso_ret != 0 || end_ret != 0) { | ||
| 243 | printf("[FAIL]\tvDSO returned %d, syscall errno=%d\n", | ||
| 244 | vdso_ret, errno); | ||
| 245 | nerrs++; | ||
| 246 | return; | ||
| 247 | } | ||
| 248 | |||
| 249 | printf("\t%llu.%09ld %llu.%09ld %llu.%09ld\n", | ||
| 250 | (unsigned long long)start.tv_sec, start.tv_nsec, | ||
| 251 | (unsigned long long)vdso.tv_sec, vdso.tv_nsec, | ||
| 252 | (unsigned long long)end.tv_sec, end.tv_nsec); | ||
| 253 | |||
| 254 | if (!ts_leq(&start, &vdso) || !ts_leq(&vdso, &end)) { | ||
| 255 | printf("[FAIL]\tTimes are out of sequence\n"); | ||
| 256 | nerrs++; | ||
| 257 | } | ||
| 258 | } | ||
| 259 | |||
| 260 | static void test_clock_gettime(void) | ||
| 261 | { | ||
| 262 | for (int clock = 0; clock < sizeof(clocknames) / sizeof(clocknames[0]); | ||
| 263 | clock++) { | ||
| 264 | test_one_clock_gettime(clock, clocknames[clock]); | ||
| 265 | } | ||
| 266 | |||
| 267 | /* Also test some invalid clock ids */ | ||
| 268 | test_one_clock_gettime(-1, "invalid"); | ||
| 269 | test_one_clock_gettime(INT_MIN, "invalid"); | ||
| 270 | test_one_clock_gettime(INT_MAX, "invalid"); | ||
| 271 | } | ||
| 272 | |||
| 273 | static void test_gettimeofday(void) | ||
| 274 | { | ||
| 275 | struct timeval start, vdso, end; | ||
| 276 | struct timezone sys_tz, vdso_tz; | ||
| 277 | int vdso_ret, end_ret; | ||
| 278 | |||
| 279 | if (!vdso_gettimeofday) | ||
| 280 | return; | ||
| 281 | |||
| 282 | printf("[RUN]\tTesting gettimeofday...\n"); | ||
| 283 | |||
| 284 | if (sys_gettimeofday(&start, &sys_tz) < 0) { | ||
| 285 | printf("[FAIL]\tsys_gettimeofday failed (%d)\n", errno); | ||
| 286 | nerrs++; | ||
| 287 | return; | ||
| 288 | } | ||
| 289 | |||
| 290 | vdso_ret = vdso_gettimeofday(&vdso, &vdso_tz); | ||
| 291 | end_ret = sys_gettimeofday(&end, NULL); | ||
| 292 | |||
| 293 | if (vdso_ret != 0 || end_ret != 0) { | ||
| 294 | printf("[FAIL]\tvDSO returned %d, syscall errno=%d\n", | ||
| 295 | vdso_ret, errno); | ||
| 296 | nerrs++; | ||
| 297 | return; | ||
| 298 | } | ||
| 299 | |||
| 300 | printf("\t%llu.%06ld %llu.%06ld %llu.%06ld\n", | ||
| 301 | (unsigned long long)start.tv_sec, start.tv_usec, | ||
| 302 | (unsigned long long)vdso.tv_sec, vdso.tv_usec, | ||
| 303 | (unsigned long long)end.tv_sec, end.tv_usec); | ||
| 304 | |||
| 305 | if (!tv_leq(&start, &vdso) || !tv_leq(&vdso, &end)) { | ||
| 306 | printf("[FAIL]\tTimes are out of sequence\n"); | ||
| 307 | nerrs++; | ||
| 308 | } | ||
| 309 | |||
| 310 | if (sys_tz.tz_minuteswest == vdso_tz.tz_minuteswest && | ||
| 311 | sys_tz.tz_dsttime == vdso_tz.tz_dsttime) { | ||
| 312 | printf("[OK]\ttimezones match: minuteswest=%d, dsttime=%d\n", | ||
| 313 | sys_tz.tz_minuteswest, sys_tz.tz_dsttime); | ||
| 314 | } else { | ||
| 315 | printf("[FAIL]\ttimezones do not match\n"); | ||
| 316 | nerrs++; | ||
| 317 | } | ||
| 318 | |||
| 319 | /* And make sure that passing NULL for tz doesn't crash. */ | ||
| 320 | vdso_gettimeofday(&vdso, NULL); | ||
| 321 | } | ||
| 322 | |||
| 158 | int main(int argc, char **argv) | 323 | int main(int argc, char **argv) |
| 159 | { | 324 | { |
| 160 | fill_function_pointers(); | 325 | fill_function_pointers(); |
| 161 | 326 | ||
| 327 | test_clock_gettime(); | ||
| 328 | test_gettimeofday(); | ||
| 329 | |||
| 330 | /* | ||
| 331 | * Test getcpu() last so that, if something goes wrong setting affinity, | ||
| 332 | * we still run the other tests. | ||
| 333 | */ | ||
| 162 | test_getcpu(); | 334 | test_getcpu(); |
| 163 | 335 | ||
| 164 | return nerrs ? 1 : 0; | 336 | return nerrs ? 1 : 0; |
