SoW-2020-0003: Trace Hit Counters
[lttng-tools.git] / src / bin / lttng-sessiond / map.c
1 /*
2 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8
9 #include "lttng/domain.h"
10 #include <common/kernel-ctl/kernel-ctl.h>
11 #include <lttng/map/map.h>
12 #include <lttng/map/map-internal.h>
13
14 #include "lttng-sessiond.h"
15 #include "lttng-ust-error.h"
16 #include "notification-thread-commands.h"
17 #include "trace-kernel.h"
18 #include "trace-ust.h"
19
20 #include "map.h"
21
22 enum lttng_error_code map_kernel_add(struct ltt_kernel_session *ksession,
23 struct lttng_map *map)
24 {
25 enum lttng_error_code ret;
26 struct ltt_kernel_map *kmap;
27 enum lttng_map_status map_status;
28 const char *map_name;
29
30 assert(lttng_map_get_domain(map) == LTTNG_DOMAIN_KERNEL);
31
32 map_status = lttng_map_get_name(map, &map_name);
33 if (map_status != LTTNG_MAP_STATUS_OK) {
34 ERR("Can't get map name");
35 ret = -1;
36 goto error;
37 }
38
39 kmap = trace_kernel_get_map_by_name(map_name, ksession);
40 if (kmap) {
41 DBG("Kernel map named \"%s\" already present", map_name);
42 ret = -1;
43 goto error;
44 }
45
46 kmap = trace_kernel_create_map(map);
47 assert(kmap);
48
49 ret = kernctl_create_session_counter(ksession->fd,
50 &kmap->counter_conf);
51 if (ret < 0) {
52 PERROR("ioctl kernel create session counter");
53 goto error;
54 }
55
56 kmap->fd = ret;
57
58 /* Prevent fd duplication after execlp() */
59 ret = fcntl(kmap->fd, F_SETFD, FD_CLOEXEC);
60 if (ret < 0) {
61 PERROR("fcntl session counter fd");
62 goto error;
63 }
64
65 kmap->map = map;
66 lttng_map_get(map);
67 cds_list_add(&kmap->list, &ksession->map_list.head);
68 ksession->map_count++;
69
70 DBG("Kernel session counter created (fd: %d)", kmap->fd);
71
72 ret = kernctl_enable(kmap->fd);
73 if (ret < 0) {
74 PERROR("Enable kernel map");
75 }
76
77 ret = LTTNG_OK;
78 error:
79 return ret;
80 }
81
82 enum lttng_error_code map_kernel_enable(struct ltt_kernel_session *ksess,
83 struct ltt_kernel_map *kmap)
84 {
85 enum lttng_error_code ret = LTTNG_OK;
86 const char *map_name;
87 enum lttng_map_status map_status;
88
89
90 assert(ksess);
91 assert(kmap);
92
93 map_status = lttng_map_get_name(kmap->map, &map_name);
94 if (map_status != LTTNG_MAP_STATUS_OK) {
95 ERR("Error getting kernel map name");
96 ret = -1;
97 goto end;
98 }
99
100 /* If already enabled, everything is OK */
101 if (kmap->enabled) {
102 DBG3("Map %s already enabled. Skipping", map_name);
103 ret = LTTNG_ERR_UST_MAP_EXIST;
104 goto end;
105 } else {
106 kmap->enabled = 1;
107 lttng_map_set_is_enabled(kmap->map, true);
108 DBG2("Map %s enabled successfully", map_name);
109 }
110
111 DBG2("Map %s being enabled in kernel domain", map_name);
112
113 /*
114 * Enable map for UST global domain on all applications. Ignore return
115 * value here since whatever error we got, it means that the map was
116 * not created on one or many registered applications and we can not report
117 * this to the user yet. However, at this stage, the map was
118 * successfully created on the session daemon side so the enable-map
119 * command is a success.
120 */
121
122 ret = kernctl_enable(kmap->fd);
123 if (ret < 0) {
124 PERROR("Enable kernel map");
125 }
126
127 ret = LTTNG_OK;
128 end:
129 return ret;
130 }
131
132 enum lttng_error_code map_kernel_disable(struct ltt_kernel_session *usess,
133 struct ltt_kernel_map *kmap)
134 {
135 enum lttng_error_code ret = LTTNG_OK;
136 enum lttng_map_status map_status;
137 const char *map_name = NULL;
138
139 assert(usess);
140 assert(kmap);
141
142 map_status = lttng_map_get_name(kmap->map, &map_name);
143 if (map_status != LTTNG_MAP_STATUS_OK) {
144 ERR("Error getting kernel map name");
145 ret = -1;
146 goto end;
147 }
148
149 /* Already disabled */
150 if (kmap->enabled == 0) {
151 DBG2("Map kernel %s already disabled", map_name);
152 ret = LTTNG_ERR_KERNEL_MAP_EXIST;
153 goto end;
154 }
155
156 kmap->enabled = 0;
157 lttng_map_set_is_enabled(kmap->map, false);
158
159 DBG2("Map %s being disabled in kernel global domain", map_name);
160
161 /* Disable map for global domain */
162 ret = kernctl_disable(kmap->fd);
163 if (ret < 0) {
164 ret = LTTNG_ERR_KERNEL_MAP_DISABLE_FAIL;
165 goto error;
166 }
167
168
169 DBG2("Map %s disabled successfully", map_name);
170
171 return LTTNG_OK;
172
173 end:
174 error:
175 return ret;
176 }
177
178 int map_ust_add(struct ltt_ust_session *usession, struct lttng_map *map)
179 {
180 int ret = 0;
181 struct ltt_ust_map *umap;
182 enum lttng_map_status map_status;
183 const char *map_name;
184 enum lttng_buffer_type buffer_type;
185
186 assert(lttng_map_get_domain(map) == LTTNG_DOMAIN_UST);
187
188 map_status = lttng_map_get_name(map, &map_name);
189 if (map_status != LTTNG_MAP_STATUS_OK) {
190 ERR("Can't get map name");
191 ret = -1;
192 goto end;
193 }
194
195 umap = trace_ust_find_map_by_name(usession->domain_global.maps,
196 map_name);
197 if (umap) {
198 DBG("UST map named \"%s\" already present", map_name);
199 ret = -1;
200 goto end;
201 }
202
203 buffer_type = lttng_map_get_buffer_type(map);
204
205 umap = trace_ust_create_map(map);
206 assert(umap);
207
208 umap->enabled = 1;
209 umap->id = trace_ust_get_next_chan_id(usession);
210 umap->map = map;
211 lttng_map_get(map);
212
213 lttng_map_set_is_enabled(umap->map, true);
214
215 DBG2("Map %s is being created for UST with buffer type %d and id %" PRIu64,
216 umap->name, buffer_type, umap->id);
217
218 /* Flag session buffer type. */
219 if (!usession->buffer_type_changed) {
220 usession->buffer_type = buffer_type;
221 usession->buffer_type_changed = 1;
222 } else if (usession->buffer_type != buffer_type) {
223 /* Buffer type was already set. Refuse to create channel. */
224 ret = LTTNG_ERR_BUFFER_TYPE_MISMATCH;
225 goto error_free_map;
226 }
227
228 rcu_read_lock();
229
230 /* Adding the map to the map hash table. */
231 lttng_ht_add_unique_str(usession->domain_global.maps, &umap->node);
232
233 rcu_read_unlock();
234
235 DBG2("Map %s created successfully", umap->name);
236
237 ret = 0;
238 goto end;
239
240 error_free_map:
241 trace_ust_destroy_map(umap);
242 end:
243 return ret;
244 }
245
246 /*
247 * Enable UST map for session and domain.
248 */
249 int map_ust_enable(struct ltt_ust_session *usess,
250 struct ltt_ust_map *umap)
251 {
252 int ret = LTTNG_OK;
253
254 assert(usess);
255 assert(umap);
256
257 /* If already enabled, everything is OK */
258 if (umap->enabled) {
259 DBG3("Map %s already enabled. Skipping", umap->name);
260 ret = LTTNG_ERR_UST_MAP_EXIST;
261 goto end;
262 } else {
263 umap->enabled = 1;
264 lttng_map_set_is_enabled(umap->map, true);
265 DBG2("Map %s enabled successfully", umap->name);
266 }
267
268 if (!usess->active) {
269 /*
270 * The map will be activated against the apps
271 * when the session is started as part of the
272 * application map "synchronize" operation.
273 */
274 goto end;
275 }
276
277 DBG2("Map %s being enabled in UST domain", umap->name);
278
279 /*
280 * Enable map for UST global domain on all applications. Ignore return
281 * value here since whatever error we got, it means that the map was
282 * not created on one or many registered applications and we can not report
283 * this to the user yet. However, at this stage, the map was
284 * successfully created on the session daemon side so the enable-map
285 * command is a success.
286 */
287 (void) ust_app_enable_map_glb(usess, umap);
288
289
290 end:
291 return ret;
292 }
293
294 int map_ust_disable(struct ltt_ust_session *usess,
295 struct ltt_ust_map *umap)
296 {
297 int ret = LTTNG_OK;
298
299 assert(usess);
300 assert(umap);
301
302 /* Already disabled */
303 if (umap->enabled == 0) {
304 DBG2("Map UST %s already disabled", umap->name);
305 ret = LTTNG_ERR_UST_MAP_EXIST;
306 goto end;
307 }
308
309 umap->enabled = 0;
310 lttng_map_set_is_enabled(umap->map, false);
311
312 /*
313 * If session is inactive we don't notify the tracer right away. We
314 * wait for the next synchronization.
315 */
316 if (!usess->active) {
317 goto end;
318 }
319
320 DBG2("Map %s being disabled in UST global domain", umap->name);
321
322 /* Disable map for global domain */
323 ret = ust_app_disable_map_glb(usess, umap);
324 if (ret < 0 && ret != -LTTNG_UST_ERR_EXIST) {
325 ret = LTTNG_ERR_UST_MAP_DISABLE_FAIL;
326 goto error;
327 }
328
329
330 DBG2("Map %s disabled successfully", umap->name);
331
332 return LTTNG_OK;
333
334 end:
335 error:
336 return ret;
337 }
338
339 void map_add_or_increment_map_values(struct lttng_ht *map_values, const char *key,
340 int64_t value, bool has_underflowed, bool has_overflowed)
341 {
342 struct map_kv_ht_entry *kv_entry;
343 struct lttng_ht_node_str *node;
344 struct lttng_ht_iter ht_iter;
345
346 lttng_ht_lookup(map_values, (void *) key, &ht_iter);
347 node = lttng_ht_iter_get_node_str(&ht_iter);
348 if (node == NULL) {
349 /*
350 * If the key is absent, the key value mapping.
351 */
352 kv_entry = zmalloc(sizeof(*kv_entry));
353 if (!kv_entry) {
354 abort();
355 }
356
357 kv_entry->key = strdup(key);
358 kv_entry->value = value;
359 kv_entry->has_underflowed = has_underflowed;
360 kv_entry->has_overflowed = has_overflowed;
361
362 lttng_ht_node_init_str(&kv_entry->node, (char *) kv_entry->key);
363 lttng_ht_add_unique_str(map_values, &kv_entry->node);
364
365 } else {
366 /*
367 * If the key is already present, increment the current value with the
368 * new value.
369 */
370 kv_entry = caa_container_of(node, typeof(*kv_entry), node);
371 kv_entry->value += value;
372 kv_entry->has_underflowed |= has_underflowed;
373 kv_entry->has_overflowed |= has_overflowed;
374 }
375 }
376
377 int map_new_content_section(struct lttng_map_content *map_content,
378 enum lttng_map_key_value_pair_list_type list_type,
379 bool summed_all_cpus, unsigned int identifier,
380 int cpu, struct lttng_ht *values)
381 {
382 int ret;
383 struct lttng_map_key_value_pair_list *kv_pair_list;
384 enum lttng_map_status map_status;
385 struct map_kv_ht_entry *kv_entry;
386 struct lttng_ht_iter key_iter;
387
388 kv_pair_list = lttng_map_key_value_pair_list_create(list_type,
389 summed_all_cpus);
390 switch (list_type) {
391 case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_PID:
392 case LTTNG_MAP_KEY_VALUE_PAIR_LIST_TYPE_UST_PER_UID:
393 map_status = lttng_map_key_value_pair_list_set_identifier(
394 kv_pair_list, identifier);
395 assert(map_status == LTTNG_MAP_STATUS_OK);
396 break;
397 default:
398 break;
399 }
400
401 if (!summed_all_cpus) {
402 map_status = lttng_map_key_value_pair_list_set_cpu(kv_pair_list,
403 cpu);
404 }
405
406 cds_lfht_for_each_entry(values->ht, &key_iter.iter, kv_entry, node.node) {
407 struct lttng_ht_iter entry_iter;
408
409 struct lttng_map_key_value_pair *pair =
410 lttng_map_key_value_pair_create(kv_entry->key,
411 kv_entry->value);
412 if (kv_entry->has_overflowed) {
413 lttng_map_key_value_pair_set_has_overflowed(pair);
414 }
415
416 if (kv_entry->has_underflowed) {
417 lttng_map_key_value_pair_set_has_underflowed(pair);
418 }
419
420 map_status = lttng_map_key_value_pair_list_append_key_value(
421 kv_pair_list, pair);
422
423 entry_iter.iter.node = &kv_entry->node.node;
424 lttng_ht_del(values, &entry_iter);
425
426 free(kv_entry->key);
427 free(kv_entry);
428 }
429
430 map_status = lttng_map_content_append_key_value_list(map_content,
431 kv_pair_list);
432 if (map_status != LTTNG_MAP_STATUS_OK) {
433 lttng_map_key_value_pair_list_destroy(kv_pair_list);
434 ret = -1;
435 ERR("Error appending key-value pair list to map content object");
436 goto end;
437 }
438 ret = 0;
439 end:
440 return ret;
441 }
442
This page took 0.038207 seconds and 5 git commands to generate.