9100d218 |
1 | /* test-async-tsc.c |
2 | * |
3 | * test async tsc on AMD. |
4 | */ |
5 | |
6 | |
7 | #include <asm/atomic.h> |
8 | #include <linux/module.h> |
9 | #include <asm/timex.h> |
10 | |
11 | //LTT #define LTT_MIN_PROBE_DURATION 400 |
12 | //get_cycles |
13 | #define LTT_MIN_PROBE_DURATION 200 |
14 | |
15 | static atomic_long_t ltt_last_tsc = ATOMIC_LONG_INIT(0); |
16 | |
17 | /* When the local TSC is discovered to lag behind the highest TSC counter, we |
18 | * increment the TSC count of an amount that should be, ideally, lower than the |
19 | * execution time of this routine, in cycles : this is the granularity we look |
20 | * for : we must be able to order the events. */ |
21 | |
22 | cycles_t ltt_tsc_read(void) |
23 | { |
24 | cycles_t new_tsc; |
25 | cycles_t last_tsc; |
26 | |
27 | new_tsc = get_cycles_sync(); |
28 | if (cpu_has(&cpu_data[smp_processor_id()], X86_FEATURE_CONSTANT_TSC)) |
29 | return new_tsc; |
30 | |
31 | do { |
32 | last_tsc = atomic_long_read(<t_last_tsc); |
33 | if (new_tsc < last_tsc) { |
34 | /* last_tsc may only have incremented since last read, |
35 | * therefore the condition new_tsc < last_tsc still |
36 | * applies even if it has been updated. Therefore, we |
37 | * can use add_return, cheaper than cmpxchg here. */ |
38 | new_tsc = atomic_long_add_return(LTT_MIN_PROBE_DURATION, |
39 | <t_last_tsc); |
40 | break; |
41 | } |
42 | /* cmpxchg will fail if ltt_last_tsc has been concurrently |
43 | * updated by add_return or set to a lower tsc value by a |
44 | * concurrent CPU at the same time. cmpxchg will succeed if |
45 | * the other CPUs update the ltt_last_tsc with a cmpxchg or |
46 | * add_return to a value higher than the new_tsc : it's ok |
47 | * since the current get_cycles happened before the one that |
48 | * causes the ltt_last_tsc to become higher than new_tsc. |
49 | * It also succeeds if we write to the memory location |
50 | * successfully without concurrent modification. */ |
51 | } while (atomic_long_cmpxchg(<t_last_tsc, last_tsc, new_tsc) |
52 | < new_tsc); |
53 | return new_tsc; |
54 | } |
55 | |
56 | static int __init test_init(void) |
57 | { |
58 | int i; |
59 | cycles_t time1, time2; |
60 | volatile cycles_t myval; |
61 | |
62 | time1 = get_cycles(); |
63 | for (i=0; i<200; i++) { |
64 | //printk("time %llu\n", ltt_tsc_read()); |
65 | //myval = ltt_tsc_read(); |
66 | myval = get_cycles_sync(); |
67 | } |
68 | time2 = get_cycles(); |
69 | printk("timediff %llu\n", time2-time1); |
70 | return -EPERM; |
71 | } |
72 | |
73 | static void __exit test_exit(void) |
74 | { |
75 | } |
76 | |
77 | module_init(test_init); |
78 | module_exit(test_exit); |
79 | |
80 | MODULE_LICENSE("GPL"); |
81 | MODULE_AUTHOR("Mathieu Desnoyers"); |
82 | MODULE_DESCRIPTION("sync async tsc"); |
83 | |