]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
aef4a13f DL |
2 | /* |
3 | * testing log message generator | |
4 | * Copyright (C) 2019-2020 David Lamparter for NetDEF, Inc. | |
aef4a13f DL |
5 | */ |
6 | ||
7 | #include <zebra.h> | |
8 | ||
9 | #include "vty.h" | |
10 | #include "command.h" | |
11 | #include "prefix.h" | |
12 | #include "nexthop.h" | |
13 | #include "log.h" | |
14 | #include "thread.h" | |
15 | #include "vrf.h" | |
16 | #include "zclient.h" | |
17 | #include "frr_pthread.h" | |
18 | ||
19 | #include "sharpd/sharp_vty.h" | |
20 | ||
21 | /* this is quite hacky, but then again it's a test tool and it does its job. */ | |
22 | static struct frr_pthread *lpt; | |
23 | ||
24 | static unsigned long lp_duration; | |
25 | static unsigned lp_frequency; | |
26 | static unsigned lp_burst; | |
27 | static size_t lp_ctr, lp_expect; | |
28 | static struct rusage lp_rusage; | |
29 | static struct vty *lp_vty; | |
30 | ||
31 | extern struct thread_master *master; | |
32 | ||
cc9f21da | 33 | static void logpump_done(struct thread *thread) |
aef4a13f DL |
34 | { |
35 | double x; | |
36 | ||
37 | vty_out(lp_vty, "\nlogpump done\n"); | |
38 | vty_out(lp_vty, "%9zu messages written\n", lp_ctr); | |
39 | x = (double)lp_ctr / (double)lp_expect * 100.; | |
40 | vty_out(lp_vty, "%9zu messages targeted = %5.1lf%%\n", lp_expect, x); | |
41 | ||
42 | x = lp_rusage.ru_utime.tv_sec * 1000000 + lp_rusage.ru_utime.tv_usec; | |
43 | x /= (double)lp_ctr; | |
44 | vty_out(lp_vty, "%6llu.%06u usr %9.1lfns/msg\n", | |
45 | (unsigned long long)lp_rusage.ru_utime.tv_sec, | |
46 | (unsigned)lp_rusage.ru_utime.tv_usec, x * 1000.); | |
47 | ||
48 | x = lp_rusage.ru_stime.tv_sec * 1000000 + lp_rusage.ru_stime.tv_usec; | |
49 | x /= (double)lp_ctr; | |
50 | vty_out(lp_vty, "%6llu.%06u sys %9.1lfns/msg\n", | |
51 | (unsigned long long)lp_rusage.ru_stime.tv_sec, | |
52 | (unsigned)lp_rusage.ru_stime.tv_usec, x * 1000.); | |
53 | ||
54 | frr_pthread_stop(lpt, NULL); | |
55 | frr_pthread_destroy(lpt); | |
56 | lpt = NULL; | |
aef4a13f DL |
57 | } |
58 | ||
59 | static void *logpump_run(void *arg) | |
60 | { | |
61 | struct timespec start, next, now; | |
62 | unsigned long delta, period; | |
63 | ||
64 | period = 1000000000L / lp_frequency; | |
65 | ||
0bdeb5e5 DL |
66 | zlog_tls_buffer_init(); |
67 | ||
aef4a13f DL |
68 | clock_gettime(CLOCK_MONOTONIC, &start); |
69 | next = start; | |
70 | do { | |
71 | for (size_t inburst = 0; inburst < lp_burst; inburst++) | |
72 | zlog_debug("log pump: %zu (burst %zu)", | |
73 | lp_ctr++, inburst); | |
74 | ||
75 | clock_gettime(CLOCK_MONOTONIC, &now); | |
76 | delta = (now.tv_sec - start.tv_sec) * 1000000000L | |
77 | + (now.tv_nsec - start.tv_nsec); | |
78 | ||
79 | next.tv_nsec += period; | |
80 | if (next.tv_nsec > 1000000000L) { | |
81 | next.tv_sec++; | |
82 | next.tv_nsec -= 1000000000L; | |
83 | } | |
84 | #ifdef HAVE_CLOCK_NANOSLEEP | |
85 | clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); | |
86 | #else | |
87 | struct timespec slpdur; | |
88 | ||
89 | slpdur.tv_sec = next.tv_sec - now.tv_sec; | |
90 | slpdur.tv_nsec = next.tv_nsec - now.tv_nsec; | |
91 | if (slpdur.tv_nsec < 0) { | |
92 | slpdur.tv_sec--; | |
93 | slpdur.tv_nsec += 1000000000L; | |
94 | } | |
95 | ||
96 | nanosleep(&slpdur, NULL); | |
97 | #endif | |
98 | } while (delta < lp_duration); | |
99 | ||
0bdeb5e5 DL |
100 | zlog_tls_buffer_fini(); |
101 | ||
aef4a13f DL |
102 | #ifdef RUSAGE_THREAD |
103 | getrusage(RUSAGE_THREAD, &lp_rusage); | |
104 | #else | |
105 | getrusage(RUSAGE_SELF, &lp_rusage); | |
106 | #endif | |
107 | ||
108 | thread_add_timer_msec(master, logpump_done, NULL, 0, NULL); | |
109 | return NULL; | |
110 | } | |
111 | ||
112 | static int logpump_halt(struct frr_pthread *fpt, void **res) | |
113 | { | |
114 | return 0; | |
115 | } | |
116 | ||
117 | /* default frr_pthread attributes */ | |
118 | static const struct frr_pthread_attr attr = { | |
119 | .start = logpump_run, | |
120 | .stop = logpump_halt, | |
121 | }; | |
122 | ||
123 | void sharp_logpump_run(struct vty *vty, unsigned duration, unsigned frequency, | |
124 | unsigned burst) | |
125 | { | |
126 | if (lpt != NULL) { | |
127 | vty_out(vty, "logpump already running\n"); | |
128 | return; | |
129 | } | |
130 | ||
131 | vty_out(vty, "starting logpump...\n"); | |
132 | vty_out(vty, "keep this VTY open and press Enter to see results\n"); | |
133 | ||
134 | lp_vty = vty; | |
135 | lp_duration = duration * 1000000000UL; | |
136 | lp_frequency = frequency; | |
137 | lp_burst = burst; | |
138 | lp_expect = duration * frequency * burst; | |
139 | lp_ctr = 0; | |
140 | ||
141 | lpt = frr_pthread_new(&attr, "logpump", "logpump"); | |
142 | frr_pthread_run(lpt, NULL); | |
143 | } |