2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <lttng/condition/condition-internal.h>
9 #include <lttng/condition/buffer-usage-internal.h>
10 #include <common/macros.h>
11 #include <common/error.h>
17 #define IS_USAGE_CONDITION(condition) ( \
18 lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW || \
19 lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH \
23 bool is_usage_evaluation(const struct lttng_evaluation
*evaluation
)
25 enum lttng_condition_type type
= lttng_evaluation_get_type(evaluation
);
27 return type
== LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
||
28 type
== LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
;
32 void lttng_condition_buffer_usage_destroy(struct lttng_condition
*condition
)
34 struct lttng_condition_buffer_usage
*usage
;
36 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
39 free(usage
->session_name
);
40 free(usage
->channel_name
);
45 bool lttng_condition_buffer_usage_validate(
46 const struct lttng_condition
*condition
)
49 struct lttng_condition_buffer_usage
*usage
;
55 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
57 if (!usage
->session_name
) {
58 ERR("Invalid buffer condition: a target session name must be set.");
61 if (!usage
->channel_name
) {
62 ERR("Invalid buffer condition: a target channel name must be set.");
65 if (!usage
->threshold_ratio
.set
&& !usage
->threshold_bytes
.set
) {
66 ERR("Invalid buffer condition: a threshold must be set.");
69 if (!usage
->domain
.set
) {
70 ERR("Invalid buffer usage condition: a domain must be set.");
80 int lttng_condition_buffer_usage_serialize(
81 const struct lttng_condition
*condition
,
82 struct lttng_payload
*payload
)
85 struct lttng_condition_buffer_usage
*usage
;
86 size_t session_name_len
, channel_name_len
;
87 struct lttng_condition_buffer_usage_comm usage_comm
;
89 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
94 DBG("Serializing buffer usage condition");
95 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
98 session_name_len
= strlen(usage
->session_name
) + 1;
99 channel_name_len
= strlen(usage
->channel_name
) + 1;
100 if (session_name_len
> LTTNG_NAME_MAX
||
101 channel_name_len
> LTTNG_NAME_MAX
) {
106 usage_comm
.threshold_set_in_bytes
= !!usage
->threshold_bytes
.set
;
107 usage_comm
.session_name_len
= session_name_len
;
108 usage_comm
.channel_name_len
= channel_name_len
;
109 usage_comm
.domain_type
= (int8_t) usage
->domain
.type
;
111 if (usage
->threshold_bytes
.set
) {
112 usage_comm
.threshold_bytes
= usage
->threshold_bytes
.value
;
114 usage_comm
.threshold_ratio
= usage
->threshold_ratio
.value
;
117 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &usage_comm
,
123 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, usage
->session_name
,
129 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, usage
->channel_name
,
139 bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition
*_a
,
140 const struct lttng_condition
*_b
)
142 bool is_equal
= false;
143 struct lttng_condition_buffer_usage
*a
, *b
;
145 a
= container_of(_a
, struct lttng_condition_buffer_usage
, parent
);
146 b
= container_of(_b
, struct lttng_condition_buffer_usage
, parent
);
148 if ((a
->threshold_ratio
.set
&& !b
->threshold_ratio
.set
) ||
149 (a
->threshold_bytes
.set
&& !b
->threshold_bytes
.set
)) {
153 if (a
->threshold_ratio
.set
&& b
->threshold_ratio
.set
) {
154 double a_value
, b_value
, diff
;
156 a_value
= a
->threshold_ratio
.value
;
157 b_value
= b
->threshold_ratio
.value
;
158 diff
= fabs(a_value
- b_value
);
160 if (diff
> DBL_EPSILON
) {
163 } else if (a
->threshold_bytes
.set
&& b
->threshold_bytes
.set
) {
164 uint64_t a_value
, b_value
;
166 a_value
= a
->threshold_bytes
.value
;
167 b_value
= b
->threshold_bytes
.value
;
168 if (a_value
!= b_value
) {
173 /* Condition is not valid if this is not true. */
174 assert(a
->session_name
);
175 assert(b
->session_name
);
176 if (strcmp(a
->session_name
, b
->session_name
)) {
180 assert(a
->channel_name
);
181 assert(b
->channel_name
);
182 if (strcmp(a
->channel_name
, b
->channel_name
)) {
186 assert(a
->domain
.set
);
187 assert(b
->domain
.set
);
188 if (a
->domain
.type
!= b
->domain
.type
) {
197 struct lttng_condition
*lttng_condition_buffer_usage_create(
198 enum lttng_condition_type type
)
200 struct lttng_condition_buffer_usage
*condition
;
202 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
207 lttng_condition_init(&condition
->parent
, type
);
208 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
209 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
210 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
211 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
212 return &condition
->parent
;
215 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
217 return lttng_condition_buffer_usage_create(
218 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
221 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
223 return lttng_condition_buffer_usage_create(
224 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
228 ssize_t
init_condition_from_payload(struct lttng_condition
*condition
,
229 struct lttng_payload_view
*src_view
)
231 ssize_t ret
, condition_size
;
232 enum lttng_condition_status status
;
233 enum lttng_domain_type domain_type
;
234 const char *session_name
, *channel_name
;
235 struct lttng_buffer_view names_view
;
236 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
237 const struct lttng_payload_view condition_comm_view
=
238 lttng_payload_view_from_view(
239 src_view
, 0, sizeof(*condition_comm
));
241 if (!lttng_payload_view_is_valid(&condition_comm_view
)) {
242 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
247 condition_comm
= (typeof(condition_comm
)) condition_comm_view
.buffer
.data
;
248 names_view
= lttng_buffer_view_from_view(&src_view
->buffer
,
249 sizeof(*condition_comm
), -1);
251 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
252 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
253 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
258 if (names_view
.size
<
259 (condition_comm
->session_name_len
+
260 condition_comm
->channel_name_len
)) {
261 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
266 if (condition_comm
->threshold_set_in_bytes
) {
267 status
= lttng_condition_buffer_usage_set_threshold(condition
,
268 condition_comm
->threshold_bytes
);
270 status
= lttng_condition_buffer_usage_set_threshold_ratio(
271 condition
, condition_comm
->threshold_ratio
);
274 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
275 ERR("Failed to initialize buffer usage condition threshold");
280 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
281 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
282 /* Invalid domain value. */
283 ERR("Invalid domain type value (%i) found in condition buffer",
284 (int) condition_comm
->domain_type
);
289 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
290 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
292 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
293 ERR("Failed to set buffer usage condition domain");
298 session_name
= names_view
.data
;
299 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
300 ERR("Malformed session name encountered in condition buffer");
305 channel_name
= session_name
+ condition_comm
->session_name_len
;
306 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
307 ERR("Malformed channel name encountered in condition buffer");
312 status
= lttng_condition_buffer_usage_set_session_name(condition
,
314 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
315 ERR("Failed to set buffer usage session name");
320 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
322 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
323 ERR("Failed to set buffer usage channel name");
328 if (!lttng_condition_validate(condition
)) {
333 condition_size
= sizeof(*condition_comm
) +
334 (ssize_t
) condition_comm
->session_name_len
+
335 (ssize_t
) condition_comm
->channel_name_len
;
336 ret
= condition_size
;
342 ssize_t
lttng_condition_buffer_usage_low_create_from_payload(
343 struct lttng_payload_view
*view
,
344 struct lttng_condition
**_condition
)
347 struct lttng_condition
*condition
=
348 lttng_condition_buffer_usage_low_create();
350 if (!_condition
|| !condition
) {
355 ret
= init_condition_from_payload(condition
, view
);
360 *_condition
= condition
;
363 lttng_condition_destroy(condition
);
368 ssize_t
lttng_condition_buffer_usage_high_create_from_payload(
369 struct lttng_payload_view
*view
,
370 struct lttng_condition
**_condition
)
373 struct lttng_condition
*condition
=
374 lttng_condition_buffer_usage_high_create();
376 if (!_condition
|| !condition
) {
381 ret
= init_condition_from_payload(condition
, view
);
386 *_condition
= condition
;
389 lttng_condition_destroy(condition
);
394 struct lttng_evaluation
*create_evaluation_from_payload(
395 enum lttng_condition_type type
,
396 struct lttng_payload_view
*view
)
398 const struct lttng_evaluation_buffer_usage_comm
*comm
=
399 (typeof(comm
)) view
->buffer
.data
;
400 struct lttng_evaluation
*evaluation
= NULL
;
402 if (view
->buffer
.size
< sizeof(*comm
)) {
406 evaluation
= lttng_evaluation_buffer_usage_create(type
,
407 comm
->buffer_use
, comm
->buffer_capacity
);
413 ssize_t
lttng_evaluation_buffer_usage_low_create_from_payload(
414 struct lttng_payload_view
*view
,
415 struct lttng_evaluation
**_evaluation
)
418 struct lttng_evaluation
*evaluation
= NULL
;
425 evaluation
= create_evaluation_from_payload(
426 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
432 *_evaluation
= evaluation
;
433 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
436 lttng_evaluation_destroy(evaluation
);
441 ssize_t
lttng_evaluation_buffer_usage_high_create_from_payload(
442 struct lttng_payload_view
*view
,
443 struct lttng_evaluation
**_evaluation
)
446 struct lttng_evaluation
*evaluation
= NULL
;
453 evaluation
= create_evaluation_from_payload(
454 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
460 *_evaluation
= evaluation
;
461 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
464 lttng_evaluation_destroy(evaluation
);
468 enum lttng_condition_status
469 lttng_condition_buffer_usage_get_threshold_ratio(
470 const struct lttng_condition
*condition
,
471 double *threshold_ratio
)
473 struct lttng_condition_buffer_usage
*usage
;
474 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
476 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
478 status
= LTTNG_CONDITION_STATUS_INVALID
;
482 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
484 if (!usage
->threshold_ratio
.set
) {
485 status
= LTTNG_CONDITION_STATUS_UNSET
;
488 *threshold_ratio
= usage
->threshold_ratio
.value
;
493 /* threshold_ratio expressed as [0.0, 1.0]. */
494 enum lttng_condition_status
495 lttng_condition_buffer_usage_set_threshold_ratio(
496 struct lttng_condition
*condition
, double threshold_ratio
)
498 struct lttng_condition_buffer_usage
*usage
;
499 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
501 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
502 threshold_ratio
< 0.0 ||
503 threshold_ratio
> 1.0) {
504 status
= LTTNG_CONDITION_STATUS_INVALID
;
508 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
510 usage
->threshold_ratio
.set
= true;
511 usage
->threshold_bytes
.set
= false;
512 usage
->threshold_ratio
.value
= threshold_ratio
;
517 enum lttng_condition_status
518 lttng_condition_buffer_usage_get_threshold(
519 const struct lttng_condition
*condition
,
520 uint64_t *threshold_bytes
)
522 struct lttng_condition_buffer_usage
*usage
;
523 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
525 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
526 status
= LTTNG_CONDITION_STATUS_INVALID
;
530 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
532 if (!usage
->threshold_bytes
.set
) {
533 status
= LTTNG_CONDITION_STATUS_UNSET
;
536 *threshold_bytes
= usage
->threshold_bytes
.value
;
541 enum lttng_condition_status
542 lttng_condition_buffer_usage_set_threshold(
543 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
545 struct lttng_condition_buffer_usage
*usage
;
546 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
548 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
549 status
= LTTNG_CONDITION_STATUS_INVALID
;
553 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
555 usage
->threshold_ratio
.set
= false;
556 usage
->threshold_bytes
.set
= true;
557 usage
->threshold_bytes
.value
= threshold_bytes
;
562 enum lttng_condition_status
563 lttng_condition_buffer_usage_get_session_name(
564 const struct lttng_condition
*condition
,
565 const char **session_name
)
567 struct lttng_condition_buffer_usage
*usage
;
568 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
570 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
571 status
= LTTNG_CONDITION_STATUS_INVALID
;
575 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
577 if (!usage
->session_name
) {
578 status
= LTTNG_CONDITION_STATUS_UNSET
;
581 *session_name
= usage
->session_name
;
586 enum lttng_condition_status
587 lttng_condition_buffer_usage_set_session_name(
588 struct lttng_condition
*condition
, const char *session_name
)
590 char *session_name_copy
;
591 struct lttng_condition_buffer_usage
*usage
;
592 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
594 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
595 strlen(session_name
) == 0) {
596 status
= LTTNG_CONDITION_STATUS_INVALID
;
600 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
602 session_name_copy
= strdup(session_name
);
603 if (!session_name_copy
) {
604 status
= LTTNG_CONDITION_STATUS_ERROR
;
608 if (usage
->session_name
) {
609 free(usage
->session_name
);
611 usage
->session_name
= session_name_copy
;
616 enum lttng_condition_status
617 lttng_condition_buffer_usage_get_channel_name(
618 const struct lttng_condition
*condition
,
619 const char **channel_name
)
621 struct lttng_condition_buffer_usage
*usage
;
622 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
624 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
625 status
= LTTNG_CONDITION_STATUS_INVALID
;
629 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
631 if (!usage
->channel_name
) {
632 status
= LTTNG_CONDITION_STATUS_UNSET
;
635 *channel_name
= usage
->channel_name
;
640 enum lttng_condition_status
641 lttng_condition_buffer_usage_set_channel_name(
642 struct lttng_condition
*condition
, const char *channel_name
)
644 char *channel_name_copy
;
645 struct lttng_condition_buffer_usage
*usage
;
646 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
648 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
649 strlen(channel_name
) == 0) {
650 status
= LTTNG_CONDITION_STATUS_INVALID
;
654 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
656 channel_name_copy
= strdup(channel_name
);
657 if (!channel_name_copy
) {
658 status
= LTTNG_CONDITION_STATUS_ERROR
;
662 if (usage
->channel_name
) {
663 free(usage
->channel_name
);
665 usage
->channel_name
= channel_name_copy
;
670 enum lttng_condition_status
671 lttng_condition_buffer_usage_get_domain_type(
672 const struct lttng_condition
*condition
,
673 enum lttng_domain_type
*type
)
675 struct lttng_condition_buffer_usage
*usage
;
676 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
678 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
679 status
= LTTNG_CONDITION_STATUS_INVALID
;
683 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
685 if (!usage
->domain
.set
) {
686 status
= LTTNG_CONDITION_STATUS_UNSET
;
689 *type
= usage
->domain
.type
;
694 enum lttng_condition_status
695 lttng_condition_buffer_usage_set_domain_type(
696 struct lttng_condition
*condition
, enum lttng_domain_type type
)
698 struct lttng_condition_buffer_usage
*usage
;
699 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
701 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
702 type
== LTTNG_DOMAIN_NONE
) {
703 status
= LTTNG_CONDITION_STATUS_INVALID
;
707 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
709 usage
->domain
.set
= true;
710 usage
->domain
.type
= type
;
716 int lttng_evaluation_buffer_usage_serialize(
717 const struct lttng_evaluation
*evaluation
,
718 struct lttng_payload
*payload
)
720 struct lttng_evaluation_buffer_usage
*usage
;
721 struct lttng_evaluation_buffer_usage_comm comm
;
723 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
725 comm
.buffer_use
= usage
->buffer_use
;
726 comm
.buffer_capacity
= usage
->buffer_capacity
;
728 return lttng_dynamic_buffer_append(
729 &payload
->buffer
, &comm
, sizeof(comm
));
733 void lttng_evaluation_buffer_usage_destroy(
734 struct lttng_evaluation
*evaluation
)
736 struct lttng_evaluation_buffer_usage
*usage
;
738 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
744 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
745 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
747 struct lttng_evaluation_buffer_usage
*usage
;
749 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
754 usage
->parent
.type
= type
;
755 usage
->buffer_use
= use
;
756 usage
->buffer_capacity
= capacity
;
757 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
758 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
760 return &usage
->parent
;
764 * Get the sampled buffer usage which caused the associated condition to
765 * evaluate to "true".
767 enum lttng_evaluation_status
768 lttng_evaluation_buffer_usage_get_usage_ratio(
769 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
771 struct lttng_evaluation_buffer_usage
*usage
;
772 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
774 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
775 status
= LTTNG_EVALUATION_STATUS_INVALID
;
779 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
781 *usage_ratio
= (double) usage
->buffer_use
/
782 (double) usage
->buffer_capacity
;
787 enum lttng_evaluation_status
788 lttng_evaluation_buffer_usage_get_usage(
789 const struct lttng_evaluation
*evaluation
,
790 uint64_t *usage_bytes
)
792 struct lttng_evaluation_buffer_usage
*usage
;
793 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
795 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
796 status
= LTTNG_EVALUATION_STATUS_INVALID
;
800 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
802 *usage_bytes
= usage
->buffer_use
;