0001
0002 #include <linux/delay.h>
0003 #include <linux/module.h>
0004 #include <linux/kthread.h>
0005 #include <linux/trace_clock.h>
0006
0007 #define CREATE_TRACE_POINTS
0008 #include "trace_benchmark.h"
0009
0010 static struct task_struct *bm_event_thread;
0011
0012 static char bm_str[BENCHMARK_EVENT_STRLEN] = "START";
0013
0014 static u64 bm_total;
0015 static u64 bm_totalsq;
0016 static u64 bm_last;
0017 static u64 bm_max;
0018 static u64 bm_min;
0019 static u64 bm_first;
0020 static u64 bm_cnt;
0021 static u64 bm_stddev;
0022 static unsigned int bm_avg;
0023 static unsigned int bm_std;
0024
0025 static bool ok_to_run;
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037 static void trace_do_benchmark(void)
0038 {
0039 u64 start;
0040 u64 stop;
0041 u64 delta;
0042 u64 stddev;
0043 u64 seed;
0044 u64 last_seed;
0045 unsigned int avg;
0046 unsigned int std = 0;
0047
0048
0049 if (!trace_benchmark_event_enabled() || !tracing_is_on())
0050 return;
0051
0052 local_irq_disable();
0053 start = trace_clock_local();
0054 trace_benchmark_event(bm_str);
0055 stop = trace_clock_local();
0056 local_irq_enable();
0057
0058 bm_cnt++;
0059
0060 delta = stop - start;
0061
0062
0063
0064
0065
0066 if (bm_cnt == 1) {
0067 bm_first = delta;
0068 scnprintf(bm_str, BENCHMARK_EVENT_STRLEN,
0069 "first=%llu [COLD CACHED]", bm_first);
0070 return;
0071 }
0072
0073 bm_last = delta;
0074
0075 if (delta > bm_max)
0076 bm_max = delta;
0077 if (!bm_min || delta < bm_min)
0078 bm_min = delta;
0079
0080
0081
0082
0083
0084
0085 if (bm_cnt > UINT_MAX) {
0086 scnprintf(bm_str, BENCHMARK_EVENT_STRLEN,
0087 "last=%llu first=%llu max=%llu min=%llu ** avg=%u std=%d std^2=%lld",
0088 bm_last, bm_first, bm_max, bm_min, bm_avg, bm_std, bm_stddev);
0089 return;
0090 }
0091
0092 bm_total += delta;
0093 bm_totalsq += delta * delta;
0094
0095
0096 if (bm_cnt > 1) {
0097
0098
0099
0100
0101 stddev = (u64)bm_cnt * bm_totalsq - bm_total * bm_total;
0102 do_div(stddev, (u32)bm_cnt);
0103 do_div(stddev, (u32)bm_cnt - 1);
0104 } else
0105 stddev = 0;
0106
0107 delta = bm_total;
0108 do_div(delta, bm_cnt);
0109 avg = delta;
0110
0111 if (stddev > 0) {
0112 int i = 0;
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124 seed = avg;
0125 do {
0126 last_seed = seed;
0127 seed = stddev;
0128 if (!last_seed)
0129 break;
0130 do_div(seed, last_seed);
0131 seed += last_seed;
0132 do_div(seed, 2);
0133 } while (i++ < 10 && last_seed != seed);
0134
0135 std = seed;
0136 }
0137
0138 scnprintf(bm_str, BENCHMARK_EVENT_STRLEN,
0139 "last=%llu first=%llu max=%llu min=%llu avg=%u std=%d std^2=%lld",
0140 bm_last, bm_first, bm_max, bm_min, avg, std, stddev);
0141
0142 bm_std = std;
0143 bm_avg = avg;
0144 bm_stddev = stddev;
0145 }
0146
0147 static int benchmark_event_kthread(void *arg)
0148 {
0149
0150 msleep(100);
0151
0152 while (!kthread_should_stop()) {
0153
0154 trace_do_benchmark();
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 cond_resched_tasks_rcu_qs();
0169 }
0170
0171 return 0;
0172 }
0173
0174
0175
0176
0177
0178 int trace_benchmark_reg(void)
0179 {
0180 if (!ok_to_run) {
0181 pr_warn("trace benchmark cannot be started via kernel command line\n");
0182 return -EBUSY;
0183 }
0184
0185 bm_event_thread = kthread_run(benchmark_event_kthread,
0186 NULL, "event_benchmark");
0187 if (IS_ERR(bm_event_thread)) {
0188 pr_warn("trace benchmark failed to create kernel thread\n");
0189 return PTR_ERR(bm_event_thread);
0190 }
0191
0192 return 0;
0193 }
0194
0195
0196
0197
0198
0199
0200 void trace_benchmark_unreg(void)
0201 {
0202 if (!bm_event_thread)
0203 return;
0204
0205 kthread_stop(bm_event_thread);
0206 bm_event_thread = NULL;
0207
0208 strcpy(bm_str, "START");
0209 bm_total = 0;
0210 bm_totalsq = 0;
0211 bm_last = 0;
0212 bm_max = 0;
0213 bm_min = 0;
0214 bm_cnt = 0;
0215
0216 bm_first = 0;
0217 bm_std = 0;
0218 bm_avg = 0;
0219 bm_stddev = 0;
0220 }
0221
0222 static __init int ok_to_run_trace_benchmark(void)
0223 {
0224 ok_to_run = true;
0225
0226 return 0;
0227 }
0228
0229 early_initcall(ok_to_run_trace_benchmark);