0001
0002
0003
0004
0005
0006
0007 #include "lock_events.h"
0008
0009 #ifdef CONFIG_LOCK_EVENT_COUNTS
0010 #ifdef CONFIG_PARAVIRT_SPINLOCKS
0011
0012
0013
0014 #include <linux/sched.h>
0015 #include <linux/sched/clock.h>
0016 #include <linux/fs.h>
0017
0018 #define EVENT_COUNT(ev) lockevents[LOCKEVENT_ ## ev]
0019
0020
0021
0022
0023 static DEFINE_PER_CPU(u64, pv_kick_time);
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 ssize_t lockevent_read(struct file *file, char __user *user_buf,
0037 size_t count, loff_t *ppos)
0038 {
0039 char buf[64];
0040 int cpu, id, len;
0041 u64 sum = 0, kicks = 0;
0042
0043
0044
0045
0046 id = (long)file_inode(file)->i_private;
0047
0048 if (id >= lockevent_num)
0049 return -EBADF;
0050
0051 for_each_possible_cpu(cpu) {
0052 sum += per_cpu(lockevents[id], cpu);
0053
0054
0055
0056 switch (id) {
0057
0058 case LOCKEVENT_pv_latency_kick:
0059 case LOCKEVENT_pv_hash_hops:
0060 kicks += per_cpu(EVENT_COUNT(pv_kick_unlock), cpu);
0061 break;
0062
0063 case LOCKEVENT_pv_latency_wake:
0064 kicks += per_cpu(EVENT_COUNT(pv_kick_wake), cpu);
0065 break;
0066 }
0067 }
0068
0069 if (id == LOCKEVENT_pv_hash_hops) {
0070 u64 frac = 0;
0071
0072 if (kicks) {
0073 frac = 100ULL * do_div(sum, kicks);
0074 frac = DIV_ROUND_CLOSEST_ULL(frac, kicks);
0075 }
0076
0077
0078
0079
0080 len = snprintf(buf, sizeof(buf) - 1, "%llu.%02llu\n",
0081 sum, frac);
0082 } else {
0083
0084
0085
0086 if ((id == LOCKEVENT_pv_latency_kick) ||
0087 (id == LOCKEVENT_pv_latency_wake)) {
0088 if (kicks)
0089 sum = DIV_ROUND_CLOSEST_ULL(sum, kicks);
0090 }
0091 len = snprintf(buf, sizeof(buf) - 1, "%llu\n", sum);
0092 }
0093
0094 return simple_read_from_buffer(user_buf, count, ppos, buf, len);
0095 }
0096
0097
0098
0099
0100 static inline void lockevent_pv_hop(int hopcnt)
0101 {
0102 this_cpu_add(EVENT_COUNT(pv_hash_hops), hopcnt);
0103 }
0104
0105
0106
0107
0108 static inline void __pv_kick(int cpu)
0109 {
0110 u64 start = sched_clock();
0111
0112 per_cpu(pv_kick_time, cpu) = start;
0113 pv_kick(cpu);
0114 this_cpu_add(EVENT_COUNT(pv_latency_kick), sched_clock() - start);
0115 }
0116
0117
0118
0119
0120 static inline void __pv_wait(u8 *ptr, u8 val)
0121 {
0122 u64 *pkick_time = this_cpu_ptr(&pv_kick_time);
0123
0124 *pkick_time = 0;
0125 pv_wait(ptr, val);
0126 if (*pkick_time) {
0127 this_cpu_add(EVENT_COUNT(pv_latency_wake),
0128 sched_clock() - *pkick_time);
0129 lockevent_inc(pv_kick_wake);
0130 }
0131 }
0132
0133 #define pv_kick(c) __pv_kick(c)
0134 #define pv_wait(p, v) __pv_wait(p, v)
0135
0136 #endif
0137
0138 #else
0139
0140 static inline void lockevent_pv_hop(int hopcnt) { }
0141
0142 #endif