memaslap: fix global/period rate
[m6w6/libmemcached] / contrib / bin / memaslap / ms_stats.c
1 /*
2 +--------------------------------------------------------------------+
3 | libmemcached - C/C++ Client Library for memcached |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted under the terms of the BSD license. |
7 | You should have received a copy of the license in a bundled file |
8 | named LICENSE; in case you did not receive a copy you can review |
9 | the terms online at: https://opensource.org/licenses/BSD-3-Clause |
10 +--------------------------------------------------------------------+
11 | Copyright (c) 2006-2014 Brian Aker https://datadifferential.com/ |
12 | Copyright (c) 2020 Michael Wallner <mike@php.net> |
13 +--------------------------------------------------------------------+
14 */
15
16 #include "mem_config.h"
17
18 #include <inttypes.h>
19 #include "ms_stats.h"
20
21 #define array_size(x) (sizeof(x) / sizeof((x)[0]))
22
23 static int ms_local_log2(uint64_t value);
24 static uint64_t ms_get_events(ms_stat_t *stat);
25
26 /**
27 * get the index of local log2 array
28 *
29 * @param value
30 *
31 * @return return the index of local log2 array
32 */
33 static int ms_local_log2(uint64_t value) {
34 int result = 0;
35
36 while (result <= 63 && ((uint64_t) 1 << result) < value) {
37 result++;
38 }
39
40 return result;
41 } /* ms_local_log2 */
42
43 /**
44 * initialize statistic structure
45 *
46 * @param stat, pointer of the statistic structure
47 * @param name, name of the statistic
48 */
49 void ms_init_stats(ms_stat_t *stat, const char *name) {
50 memset(stat, 0, sizeof(*stat));
51
52 stat->name = (char *) name;
53 stat->min_time = (uint64_t) -1;
54 stat->max_time = 0;
55 stat->period_min_time = (uint64_t) -1;
56 stat->period_max_time = 0;
57 stat->log_product = 0;
58 stat->total_time = 0;
59 stat->pre_total_time = 0;
60 stat->squares = 0;
61 stat->pre_squares = 0;
62 stat->pre_events = 0;
63 stat->pre_log_product = 0;
64 stat->get_miss = 0;
65 stat->pre_get_miss = 0;
66 } /* ms_init_stats */
67
68 /**
69 * record one event
70 *
71 * @param stat, pointer of the statistic structure
72 * @param total_time, response time of the command
73 * @param get_miss, whether it gets miss
74 */
75 void ms_record_event(ms_stat_t *stat, uint64_t total_time, int get_miss) {
76 stat->total_time += total_time;
77
78 if (total_time < stat->min_time) {
79 stat->min_time = total_time;
80 }
81
82 if (total_time > stat->max_time) {
83 stat->max_time = total_time;
84 }
85
86 if (total_time < stat->period_min_time) {
87 stat->period_min_time = total_time;
88 }
89
90 if (total_time > stat->period_max_time) {
91 stat->period_max_time = total_time;
92 }
93
94 if (get_miss) {
95 stat->get_miss++;
96 }
97
98 stat->dist[ms_local_log2(total_time)]++;
99 stat->squares += (double) (total_time * total_time);
100
101 if (total_time) {
102 stat->log_product += log((double) total_time);
103 }
104 } /* ms_record_event */
105
106 /**
107 * get the events count
108 *
109 * @param stat, pointer of the statistic structure
110 *
111 * @return total events recorded
112 */
113 #if HAVE_TSAN
114 __attribute__ (( no_sanitize_thread, no_sanitize("thread")))
115 #endif
116 static uint64_t ms_get_events(ms_stat_t *stat) {
117 uint64_t events = 0;
118
119 for (uint32_t i = 0; i < array_size(stat->dist); i++) {
120 events += stat->dist[i];
121 }
122
123 return events;
124 } /* ms_get_events */
125
126 /**
127 * dump the statistics
128 *
129 * @param stat, pointer of the statistic structure
130 */
131 void ms_dump_stats(ms_stat_t *stat) {
132 uint64_t events = 0;
133 int max_non_zero = 0;
134 int min_non_zero = 0;
135 double average = 0;
136
137 for (uint32_t i = 0; i < array_size(stat->dist); i++) {
138 events += stat->dist[i];
139 if (stat->dist[i]) {
140 max_non_zero = (int) i;
141 }
142 }
143
144 if (events == 0) {
145 return;
146 }
147 average = (double) (stat->total_time / events);
148
149 printf("%s Statistics (%lld events)\n", stat->name, (long long) events);
150 printf(" Min: %8lld\n", (long long) stat->min_time);
151 printf(" Max: %8lld\n", (long long) stat->max_time);
152 printf(" Avg: %8lld\n", (long long) (stat->total_time / events));
153 printf(" Geo: %8.2lf\n", exp(stat->log_product / (double) events));
154
155 if (events > 1) {
156 printf(" Std: %8.2lf\n",
157 sqrt((stat->squares - (double) events * average * average) / ((double) events - 1)));
158 }
159 printf(" Log2 Dist:");
160
161 for (int i = 0; i <= max_non_zero - 4; i += 4) {
162 if ((stat->dist[i + 0]) || (stat->dist[i + 1]) || (stat->dist[i + 2])
163 || (stat->dist[i + 3]))
164 {
165 min_non_zero = i;
166 break;
167 }
168 }
169
170 for (int i = min_non_zero; i <= max_non_zero; i++) {
171 if ((i % 4) == 0) {
172 printf("\n %2d:", (int) i);
173 }
174 printf(" %6" PRIu64, stat->dist[i]);
175 }
176
177 printf("\n\n");
178 } /* ms_dump_stats */
179
180 /**
181 * dump the format statistics
182 *
183 * @param stat, pointer of the statistic structure
184 * @param run_time, the total run time
185 * @param freq, statistic frequency
186 * @param obj_size, average object size
187 */
188 #if HAVE_TSAN
189 __attribute__ (( no_sanitize_thread, no_sanitize("thread")))
190 #endif
191 void ms_dump_format_stats(ms_stat_t *stat, int run_time, int freq, int obj_size) {
192 uint64_t events = 0;
193 double global_average = 0;
194 uint64_t global_tps = 0;
195 double global_rate = 0;
196 double global_std = 0;
197 double global_log = 0;
198
199 double period_average = 0;
200 uint64_t period_tps = 0;
201 double period_rate = 0;
202 double period_std = 0;
203 double period_log = 0;
204
205 if ((events = ms_get_events(stat)) == 0) {
206 return;
207 }
208
209 global_average = (double) (stat->total_time / events);
210 global_tps = events / (uint64_t) run_time;
211 global_rate = (double) events * obj_size / 1024 / 1024 / run_time;
212 global_std = sqrt((stat->squares - (double) events * global_average * global_average)
213 / (double) (events - 1));
214 global_log = exp(stat->log_product / (double) events);
215
216 uint64_t diff_time = stat->total_time - stat->pre_total_time;
217 uint64_t diff_events = events - stat->pre_events;
218 if (diff_events >= 1) {
219 period_average = (double) (diff_time / diff_events);
220 period_tps = diff_events / (uint64_t) freq;
221 period_rate = (double) diff_events * obj_size / 1024 / 1024 / freq;
222 double diff_squares = (double) stat->squares - (double) stat->pre_squares;
223 period_std = sqrt((diff_squares - (double) diff_events * period_average * period_average)
224 / (double) (diff_events - 1));
225 double diff_log_product = stat->log_product - stat->pre_log_product;
226 period_log = exp(diff_log_product / (double) diff_events);
227 }
228
229 printf("%s Statistics\n", stat->name);
230 printf("%-8s %-8s %-12s %-12s %-10s %-10s %-8s %-10s %-10s %-10s %-10s\n", "Type", "Time(s)",
231 "Ops", "TPS(ops/s)", "Net(M/s)", "Get_miss", "Min(us)", "Max(us)", "Avg(us)", "Std_dev",
232 "Geo_dist");
233
234 printf("%-8s %-8d %-12llu %-12lld %-10.1f %-10lld %-8lld %-10lld %-10lld %-10.2f %.2f\n",
235 "Period", freq, (long long) diff_events, (long long) period_tps, period_rate,
236 (long long) (stat->get_miss - stat->pre_get_miss), (long long) stat->period_min_time,
237 (long long) stat->period_max_time, (long long) period_average, period_std, period_log);
238
239 printf("%-8s %-8d %-12llu %-12lld %-10.1f %-10lld %-8lld %-10lld %-10lld %-10.2f %.2f\n\n",
240 "Global", run_time, (long long) events, (long long) global_tps, global_rate,
241 (long long) stat->get_miss, (long long) stat->min_time, (long long) stat->max_time,
242 (long long) global_average, global_std, global_log);
243
244 stat->pre_events = events;
245 stat->pre_squares = (uint64_t) stat->squares;
246 stat->pre_total_time = stat->total_time;
247 stat->pre_log_product = stat->log_product;
248 stat->period_min_time = (uint64_t) -1;
249 stat->period_max_time = 0;
250 stat->pre_get_miss = stat->get_miss;
251 } /* ms_dump_format_stats */