linux/lib/percpu_test.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2#include <linux/module.h>
   3
   4/* validate @native and @pcp counter values match @expected */
   5#define CHECK(native, pcp, expected)                                    \
   6        do {                                                            \
   7                WARN((native) != (expected),                            \
   8                     "raw %ld (0x%lx) != expected %lld (0x%llx)",       \
   9                     (native), (native),                                \
  10                     (long long)(expected), (long long)(expected));     \
  11                WARN(__this_cpu_read(pcp) != (expected),                \
  12                     "pcp %ld (0x%lx) != expected %lld (0x%llx)",       \
  13                     __this_cpu_read(pcp), __this_cpu_read(pcp),        \
  14                     (long long)(expected), (long long)(expected));     \
  15        } while (0)
  16
  17static DEFINE_PER_CPU(long, long_counter);
  18static DEFINE_PER_CPU(unsigned long, ulong_counter);
  19
  20static int __init percpu_test_init(void)
  21{
  22        /*
  23         * volatile prevents compiler from optimizing it uses, otherwise the
  24         * +ul_one/-ul_one below would replace with inc/dec instructions.
  25         */
  26        volatile unsigned int ui_one = 1;
  27        long l = 0;
  28        unsigned long ul = 0;
  29
  30        pr_info("percpu test start\n");
  31
  32        preempt_disable();
  33
  34        l += -1;
  35        __this_cpu_add(long_counter, -1);
  36        CHECK(l, long_counter, -1);
  37
  38        l += 1;
  39        __this_cpu_add(long_counter, 1);
  40        CHECK(l, long_counter, 0);
  41
  42        ul = 0;
  43        __this_cpu_write(ulong_counter, 0);
  44
  45        ul += 1UL;
  46        __this_cpu_add(ulong_counter, 1UL);
  47        CHECK(ul, ulong_counter, 1);
  48
  49        ul += -1UL;
  50        __this_cpu_add(ulong_counter, -1UL);
  51        CHECK(ul, ulong_counter, 0);
  52
  53        ul += -(unsigned long)1;
  54        __this_cpu_add(ulong_counter, -(unsigned long)1);
  55        CHECK(ul, ulong_counter, -1);
  56
  57        ul = 0;
  58        __this_cpu_write(ulong_counter, 0);
  59
  60        ul -= 1;
  61        __this_cpu_dec(ulong_counter);
  62        CHECK(ul, ulong_counter, -1);
  63        CHECK(ul, ulong_counter, ULONG_MAX);
  64
  65        l += -ui_one;
  66        __this_cpu_add(long_counter, -ui_one);
  67        CHECK(l, long_counter, 0xffffffff);
  68
  69        l += ui_one;
  70        __this_cpu_add(long_counter, ui_one);
  71        CHECK(l, long_counter, (long)0x100000000LL);
  72
  73
  74        l = 0;
  75        __this_cpu_write(long_counter, 0);
  76
  77        l -= ui_one;
  78        __this_cpu_sub(long_counter, ui_one);
  79        CHECK(l, long_counter, -1);
  80
  81        l = 0;
  82        __this_cpu_write(long_counter, 0);
  83
  84        l += ui_one;
  85        __this_cpu_add(long_counter, ui_one);
  86        CHECK(l, long_counter, 1);
  87
  88        l += -ui_one;
  89        __this_cpu_add(long_counter, -ui_one);
  90        CHECK(l, long_counter, (long)0x100000000LL);
  91
  92        l = 0;
  93        __this_cpu_write(long_counter, 0);
  94
  95        l -= ui_one;
  96        this_cpu_sub(long_counter, ui_one);
  97        CHECK(l, long_counter, -1);
  98        CHECK(l, long_counter, ULONG_MAX);
  99
 100        ul = 0;
 101        __this_cpu_write(ulong_counter, 0);
 102
 103        ul += ui_one;
 104        __this_cpu_add(ulong_counter, ui_one);
 105        CHECK(ul, ulong_counter, 1);
 106
 107        ul = 0;
 108        __this_cpu_write(ulong_counter, 0);
 109
 110        ul -= ui_one;
 111        __this_cpu_sub(ulong_counter, ui_one);
 112        CHECK(ul, ulong_counter, -1);
 113        CHECK(ul, ulong_counter, ULONG_MAX);
 114
 115        ul = 3;
 116        __this_cpu_write(ulong_counter, 3);
 117
 118        ul = this_cpu_sub_return(ulong_counter, ui_one);
 119        CHECK(ul, ulong_counter, 2);
 120
 121        ul = __this_cpu_sub_return(ulong_counter, ui_one);
 122        CHECK(ul, ulong_counter, 1);
 123
 124        preempt_enable();
 125
 126        pr_info("percpu test done\n");
 127        return -EAGAIN;  /* Fail will directly unload the module */
 128}
 129
 130static void __exit percpu_test_exit(void)
 131{
 132}
 133
 134module_init(percpu_test_init)
 135module_exit(percpu_test_exit)
 136
 137MODULE_LICENSE("GPL");
 138MODULE_AUTHOR("Greg Thelen");
 139MODULE_DESCRIPTION("percpu operations test");
 140