Line data Source code
1 : /*
2 : * Copyright (c) 2021 EMnify.
3 : *
4 : * Licensed under the Apache License, Version 2.0 (the "License");
5 : * you may not use this file except in compliance with the License.
6 : * You may obtain a copy of the License at:
7 : *
8 : * http://www.apache.org/licenses/LICENSE-2.0
9 : *
10 : * Unless required by applicable law or agreed to in writing, software
11 : * distributed under the License is distributed on an "AS IS" BASIS,
12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : * See the License for the specific language governing permissions and
14 : * limitations under the License.
15 : */
16 : #include <vlib/vlib.h>
17 : #include <vppinfra/time.h>
18 : #include <vppinfra/cache.h>
19 : #include <vppinfra/error.h>
20 :
21 : #include <vlib/counter.h>
22 : #include <vlib/stats/stats.h>
23 :
24 : enum
25 : {
26 : type_simple = 0,
27 : type_combined,
28 : };
29 :
30 : enum
31 : {
32 : test_expand = 0,
33 : };
34 :
35 : /*
36 : * Return the stats segment epoch value.
37 : */
38 : static uint64_t
39 39 : get_stats_epoch ()
40 : {
41 39 : vlib_stats_segment_t *sm = vlib_stats_get_segment ();
42 39 : return sm->shared_header->epoch;
43 : }
44 :
45 : /* number of times to repeat the counter expand tests */
46 : #define EXPAND_TEST_ROUNDS 3
47 :
48 : /*
49 : * Let a simple counter vector grow and verify that
50 : * the stats epoch is increased only when the vector
51 : * is expanded.
52 : */
53 : static clib_error_t *
54 1 : test_simple_counter_expand (vlib_main_t *vm)
55 : {
56 1 : vlib_simple_counter_main_t counter = {
57 : .name = "test-simple-counter-expand",
58 : .stat_segment_name = "/vlib/test-simple-counter-expand",
59 : };
60 : int i, index;
61 : uint64_t epoch, new_epoch;
62 :
63 : // Create one counter to allocate the vector.
64 1 : vlib_validate_simple_counter (&counter, 0);
65 1 : epoch = get_stats_epoch ();
66 :
67 4 : for (i = 0; i < EXPAND_TEST_ROUNDS; i++)
68 : {
69 : // Check how many elements fit into the counter vector without expanding
70 : // that. The next validate calls should not increase the stats segment
71 : // epoch.
72 3 : int mem_size = vec_max_len (counter.counters[0]);
73 20 : for (index = 1; index <= mem_size - 1; index++)
74 : {
75 17 : vlib_validate_simple_counter (&counter, index);
76 17 : new_epoch = get_stats_epoch ();
77 17 : if (new_epoch != epoch)
78 0 : return clib_error_return (
79 : 0, "Stats segment epoch should not increase");
80 : }
81 :
82 : // The next counter index does not fit and it will extend the vector.
83 : // The stats segment epoch should increase.
84 3 : vlib_validate_simple_counter (&counter, index + 1);
85 3 : new_epoch = get_stats_epoch ();
86 3 : if (new_epoch == epoch)
87 0 : return clib_error_return (0,
88 : "Stats segment epoch should have increased");
89 3 : epoch = new_epoch;
90 : }
91 :
92 1 : vlib_free_simple_counter (&counter);
93 1 : vlib_validate_simple_counter (&counter, 0);
94 :
95 1 : return 0;
96 : }
97 :
98 : /*
99 : * Let a combined counter vector grow and verify that
100 : * the stats epoch is increased only when the vector
101 : * is expanded.
102 : */
103 : static clib_error_t *
104 1 : test_combined_counter_expand (vlib_main_t *vm)
105 : {
106 1 : vlib_combined_counter_main_t counter = {
107 : .name = "test-combined-counter-expand",
108 : .stat_segment_name = "/vlib/test-combined-counter-expand",
109 : };
110 : int i, index;
111 : uint64_t epoch, new_epoch;
112 :
113 : // Create one counter to allocate the vector.
114 1 : vlib_validate_combined_counter (&counter, 0);
115 1 : epoch = get_stats_epoch ();
116 :
117 4 : for (i = 0; i < EXPAND_TEST_ROUNDS; i++)
118 : {
119 : // Check how many elements fit into the counter vector without expanding
120 : // that. The next validate calls should not increase the stats segment
121 : // epoch.
122 3 : int mem_size = vec_max_len (counter.counters[0]);
123 17 : for (index = 1; index <= mem_size - 1; index++)
124 : {
125 14 : vlib_validate_combined_counter (&counter, index);
126 14 : new_epoch = get_stats_epoch ();
127 14 : if (new_epoch != epoch)
128 0 : return clib_error_return (
129 : 0, "Stats segment epoch should not increase");
130 : }
131 :
132 : // The next counter index does not fit and it will extend the vector.
133 : // The stats segment epoch should increase.
134 3 : vlib_validate_combined_counter (&counter, index + 1);
135 3 : new_epoch = get_stats_epoch ();
136 3 : if (new_epoch == epoch)
137 0 : return clib_error_return (0,
138 : "Stats segment epoch should have increased");
139 3 : epoch = new_epoch;
140 : }
141 :
142 1 : vlib_free_combined_counter (&counter);
143 1 : vlib_validate_combined_counter (&counter, 0);
144 :
145 1 : return 0;
146 : }
147 :
148 : static clib_error_t *
149 1 : test_simple_counter (vlib_main_t *vm, int test_case)
150 : {
151 : clib_error_t *error;
152 :
153 1 : switch (test_case)
154 : {
155 1 : case test_expand:
156 1 : error = test_simple_counter_expand (vm);
157 1 : break;
158 :
159 0 : default:
160 0 : return clib_error_return (0, "no such test");
161 : }
162 :
163 1 : return error;
164 : }
165 :
166 : static clib_error_t *
167 1 : test_combined_counter (vlib_main_t *vm, int test_case)
168 : {
169 : clib_error_t *error;
170 :
171 1 : switch (test_case)
172 : {
173 1 : case test_expand:
174 1 : error = test_combined_counter_expand (vm);
175 1 : break;
176 :
177 0 : default:
178 0 : return clib_error_return (0, "no such test");
179 : }
180 :
181 1 : return error;
182 : }
183 :
184 : static clib_error_t *
185 2 : test_counter_command_fn (vlib_main_t *vm, unformat_input_t *input,
186 : vlib_cli_command_t *cmd)
187 : {
188 : clib_error_t *error;
189 2 : int counter_type = -1;
190 2 : int test_case = -1;
191 :
192 6 : while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
193 : {
194 4 : if (unformat (input, "simple"))
195 1 : counter_type = type_simple;
196 3 : else if (unformat (input, "combined"))
197 1 : counter_type = type_combined;
198 2 : else if (unformat (input, "expand"))
199 2 : test_case = test_expand;
200 : else
201 0 : return clib_error_return (0, "unknown input '%U'",
202 : format_unformat_error, input);
203 : }
204 :
205 2 : if (test_case == -1)
206 0 : return clib_error_return (0, "no such test");
207 :
208 2 : switch (counter_type)
209 : {
210 1 : case type_simple:
211 1 : error = test_simple_counter (vm, test_case);
212 1 : break;
213 :
214 1 : case type_combined:
215 1 : error = test_combined_counter (vm, test_case);
216 1 : break;
217 :
218 0 : default:
219 0 : return clib_error_return (0, "no such test");
220 : }
221 :
222 2 : return error;
223 : }
224 :
225 16239 : VLIB_CLI_COMMAND (test_counter_command, static) = {
226 : .path = "test counter",
227 : .short_help = "test counter [simple | combined] expand",
228 : .function = test_counter_command_fn,
229 : };
230 :
231 : static clib_error_t *
232 559 : test_counter_init (vlib_main_t *vm)
233 : {
234 559 : return (0);
235 : }
236 :
237 6159 : VLIB_INIT_FUNCTION (test_counter_init);
238 :
239 : /*
240 : * fd.io coding-style-patch-verification: ON
241 : *
242 : * Local Variables:
243 : * eval: (c-set-style "gnu")
244 : * End:
245 : */
|