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 double fixed_to_double(uint32_t val
)
25 return (double) val
/ (double) UINT32_MAX
;
29 uint64_t double_to_fixed(double val
)
31 return (val
* (double) UINT32_MAX
);
35 bool is_usage_evaluation(const struct lttng_evaluation
*evaluation
)
37 enum lttng_condition_type type
= lttng_evaluation_get_type(evaluation
);
39 return type
== LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
||
40 type
== LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
;
44 void lttng_condition_buffer_usage_destroy(struct lttng_condition
*condition
)
46 struct lttng_condition_buffer_usage
*usage
;
48 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
51 free(usage
->session_name
);
52 free(usage
->channel_name
);
57 bool lttng_condition_buffer_usage_validate(
58 const struct lttng_condition
*condition
)
61 struct lttng_condition_buffer_usage
*usage
;
67 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
69 if (!usage
->session_name
) {
70 ERR("Invalid buffer condition: a target session name must be set.");
73 if (!usage
->channel_name
) {
74 ERR("Invalid buffer condition: a target channel name must be set.");
77 if (!usage
->threshold_ratio
.set
&& !usage
->threshold_bytes
.set
) {
78 ERR("Invalid buffer condition: a threshold must be set.");
81 if (!usage
->domain
.set
) {
82 ERR("Invalid buffer usage condition: a domain must be set.");
92 int lttng_condition_buffer_usage_serialize(
93 const struct lttng_condition
*condition
,
94 struct lttng_payload
*payload
)
97 struct lttng_condition_buffer_usage
*usage
;
98 size_t session_name_len
, channel_name_len
;
99 struct lttng_condition_buffer_usage_comm usage_comm
;
101 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
106 DBG("Serializing buffer usage condition");
107 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
110 session_name_len
= strlen(usage
->session_name
) + 1;
111 channel_name_len
= strlen(usage
->channel_name
) + 1;
112 if (session_name_len
> LTTNG_NAME_MAX
||
113 channel_name_len
> LTTNG_NAME_MAX
) {
118 usage_comm
.threshold_set_in_bytes
= !!usage
->threshold_bytes
.set
;
119 usage_comm
.session_name_len
= session_name_len
;
120 usage_comm
.channel_name_len
= channel_name_len
;
121 usage_comm
.domain_type
= (int8_t) usage
->domain
.type
;
123 if (usage
->threshold_bytes
.set
) {
124 usage_comm
.threshold
= usage
->threshold_bytes
.value
;
126 uint64_t val
= double_to_fixed(
127 usage
->threshold_ratio
.value
);
129 if (val
> UINT32_MAX
) {
134 usage_comm
.threshold
= val
;
137 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &usage_comm
,
143 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, usage
->session_name
,
149 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, usage
->channel_name
,
159 bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition
*_a
,
160 const struct lttng_condition
*_b
)
162 bool is_equal
= false;
163 struct lttng_condition_buffer_usage
*a
, *b
;
165 a
= container_of(_a
, struct lttng_condition_buffer_usage
, parent
);
166 b
= container_of(_b
, struct lttng_condition_buffer_usage
, parent
);
168 if ((a
->threshold_ratio
.set
&& !b
->threshold_ratio
.set
) ||
169 (a
->threshold_bytes
.set
&& !b
->threshold_bytes
.set
)) {
173 if (a
->threshold_ratio
.set
&& b
->threshold_ratio
.set
) {
174 double a_value
, b_value
, diff
;
176 a_value
= a
->threshold_ratio
.value
;
177 b_value
= b
->threshold_ratio
.value
;
178 diff
= fabs(a_value
- b_value
);
180 if (diff
> DBL_EPSILON
) {
183 } else if (a
->threshold_bytes
.set
&& b
->threshold_bytes
.set
) {
184 uint64_t a_value
, b_value
;
186 a_value
= a
->threshold_bytes
.value
;
187 b_value
= b
->threshold_bytes
.value
;
188 if (a_value
!= b_value
) {
193 /* Condition is not valid if this is not true. */
194 assert(a
->session_name
);
195 assert(b
->session_name
);
196 if (strcmp(a
->session_name
, b
->session_name
)) {
200 assert(a
->channel_name
);
201 assert(b
->channel_name
);
202 if (strcmp(a
->channel_name
, b
->channel_name
)) {
206 assert(a
->domain
.set
);
207 assert(b
->domain
.set
);
208 if (a
->domain
.type
!= b
->domain
.type
) {
217 struct lttng_condition
*lttng_condition_buffer_usage_create(
218 enum lttng_condition_type type
)
220 struct lttng_condition_buffer_usage
*condition
;
222 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
227 lttng_condition_init(&condition
->parent
, type
);
228 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
229 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
230 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
231 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
232 return &condition
->parent
;
235 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
237 return lttng_condition_buffer_usage_create(
238 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
241 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
243 return lttng_condition_buffer_usage_create(
244 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
248 ssize_t
init_condition_from_payload(struct lttng_condition
*condition
,
249 struct lttng_payload_view
*src_view
)
251 ssize_t ret
, condition_size
;
252 enum lttng_condition_status status
;
253 enum lttng_domain_type domain_type
;
254 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
255 const char *session_name
, *channel_name
;
256 struct lttng_buffer_view names_view
;
258 if (src_view
->buffer
.size
< sizeof(*condition_comm
)) {
259 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
264 condition_comm
= (typeof(condition_comm
)) src_view
->buffer
.data
;
265 names_view
= lttng_buffer_view_from_view(&src_view
->buffer
,
266 sizeof(*condition_comm
), -1);
268 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
269 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
270 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
275 if (names_view
.size
<
276 (condition_comm
->session_name_len
+
277 condition_comm
->channel_name_len
)) {
278 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
283 if (condition_comm
->threshold_set_in_bytes
) {
284 status
= lttng_condition_buffer_usage_set_threshold(condition
,
285 condition_comm
->threshold
);
287 status
= lttng_condition_buffer_usage_set_threshold_ratio(
289 fixed_to_double(condition_comm
->threshold
));
292 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
293 ERR("Failed to initialize buffer usage condition threshold");
298 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
299 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
300 /* Invalid domain value. */
301 ERR("Invalid domain type value (%i) found in condition buffer",
302 (int) condition_comm
->domain_type
);
307 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
308 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
310 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
311 ERR("Failed to set buffer usage condition domain");
316 session_name
= names_view
.data
;
317 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
318 ERR("Malformed session name encountered in condition buffer");
323 channel_name
= session_name
+ condition_comm
->session_name_len
;
324 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
325 ERR("Malformed channel name encountered in condition buffer");
330 status
= lttng_condition_buffer_usage_set_session_name(condition
,
332 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
333 ERR("Failed to set buffer usage session name");
338 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
340 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
341 ERR("Failed to set buffer usage channel name");
346 if (!lttng_condition_validate(condition
)) {
351 condition_size
= sizeof(*condition_comm
) +
352 (ssize_t
) condition_comm
->session_name_len
+
353 (ssize_t
) condition_comm
->channel_name_len
;
354 ret
= condition_size
;
360 ssize_t
lttng_condition_buffer_usage_low_create_from_payload(
361 struct lttng_payload_view
*view
,
362 struct lttng_condition
**_condition
)
365 struct lttng_condition
*condition
=
366 lttng_condition_buffer_usage_low_create();
368 if (!_condition
|| !condition
) {
373 ret
= init_condition_from_payload(condition
, view
);
378 *_condition
= condition
;
381 lttng_condition_destroy(condition
);
386 ssize_t
lttng_condition_buffer_usage_high_create_from_payload(
387 struct lttng_payload_view
*view
,
388 struct lttng_condition
**_condition
)
391 struct lttng_condition
*condition
=
392 lttng_condition_buffer_usage_high_create();
394 if (!_condition
|| !condition
) {
399 ret
= init_condition_from_payload(condition
, view
);
404 *_condition
= condition
;
407 lttng_condition_destroy(condition
);
412 struct lttng_evaluation
*create_evaluation_from_payload(
413 enum lttng_condition_type type
,
414 struct lttng_payload_view
*view
)
416 const struct lttng_evaluation_buffer_usage_comm
*comm
=
417 (typeof(comm
)) view
->buffer
.data
;
418 struct lttng_evaluation
*evaluation
= NULL
;
420 if (view
->buffer
.size
< sizeof(*comm
)) {
424 evaluation
= lttng_evaluation_buffer_usage_create(type
,
425 comm
->buffer_use
, comm
->buffer_capacity
);
431 ssize_t
lttng_evaluation_buffer_usage_low_create_from_payload(
432 struct lttng_payload_view
*view
,
433 struct lttng_evaluation
**_evaluation
)
436 struct lttng_evaluation
*evaluation
= NULL
;
443 evaluation
= create_evaluation_from_payload(
444 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
450 *_evaluation
= evaluation
;
451 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
454 lttng_evaluation_destroy(evaluation
);
459 ssize_t
lttng_evaluation_buffer_usage_high_create_from_payload(
460 struct lttng_payload_view
*view
,
461 struct lttng_evaluation
**_evaluation
)
464 struct lttng_evaluation
*evaluation
= NULL
;
471 evaluation
= create_evaluation_from_payload(
472 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
478 *_evaluation
= evaluation
;
479 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
482 lttng_evaluation_destroy(evaluation
);
486 enum lttng_condition_status
487 lttng_condition_buffer_usage_get_threshold_ratio(
488 const struct lttng_condition
*condition
,
489 double *threshold_ratio
)
491 struct lttng_condition_buffer_usage
*usage
;
492 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
494 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
496 status
= LTTNG_CONDITION_STATUS_INVALID
;
500 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
502 if (!usage
->threshold_ratio
.set
) {
503 status
= LTTNG_CONDITION_STATUS_UNSET
;
506 *threshold_ratio
= usage
->threshold_ratio
.value
;
511 /* threshold_ratio expressed as [0.0, 1.0]. */
512 enum lttng_condition_status
513 lttng_condition_buffer_usage_set_threshold_ratio(
514 struct lttng_condition
*condition
, double threshold_ratio
)
516 struct lttng_condition_buffer_usage
*usage
;
517 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
519 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
520 threshold_ratio
< 0.0 ||
521 threshold_ratio
> 1.0) {
522 status
= LTTNG_CONDITION_STATUS_INVALID
;
526 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
528 usage
->threshold_ratio
.set
= true;
529 usage
->threshold_bytes
.set
= false;
530 usage
->threshold_ratio
.value
= threshold_ratio
;
535 enum lttng_condition_status
536 lttng_condition_buffer_usage_get_threshold(
537 const struct lttng_condition
*condition
,
538 uint64_t *threshold_bytes
)
540 struct lttng_condition_buffer_usage
*usage
;
541 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
543 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
544 status
= LTTNG_CONDITION_STATUS_INVALID
;
548 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
550 if (!usage
->threshold_bytes
.set
) {
551 status
= LTTNG_CONDITION_STATUS_UNSET
;
554 *threshold_bytes
= usage
->threshold_bytes
.value
;
559 enum lttng_condition_status
560 lttng_condition_buffer_usage_set_threshold(
561 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
563 struct lttng_condition_buffer_usage
*usage
;
564 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
566 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
567 status
= LTTNG_CONDITION_STATUS_INVALID
;
571 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
573 usage
->threshold_ratio
.set
= false;
574 usage
->threshold_bytes
.set
= true;
575 usage
->threshold_bytes
.value
= threshold_bytes
;
580 enum lttng_condition_status
581 lttng_condition_buffer_usage_get_session_name(
582 const struct lttng_condition
*condition
,
583 const char **session_name
)
585 struct lttng_condition_buffer_usage
*usage
;
586 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
588 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
589 status
= LTTNG_CONDITION_STATUS_INVALID
;
593 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
595 if (!usage
->session_name
) {
596 status
= LTTNG_CONDITION_STATUS_UNSET
;
599 *session_name
= usage
->session_name
;
604 enum lttng_condition_status
605 lttng_condition_buffer_usage_set_session_name(
606 struct lttng_condition
*condition
, const char *session_name
)
608 char *session_name_copy
;
609 struct lttng_condition_buffer_usage
*usage
;
610 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
612 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
613 strlen(session_name
) == 0) {
614 status
= LTTNG_CONDITION_STATUS_INVALID
;
618 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
620 session_name_copy
= strdup(session_name
);
621 if (!session_name_copy
) {
622 status
= LTTNG_CONDITION_STATUS_ERROR
;
626 if (usage
->session_name
) {
627 free(usage
->session_name
);
629 usage
->session_name
= session_name_copy
;
634 enum lttng_condition_status
635 lttng_condition_buffer_usage_get_channel_name(
636 const struct lttng_condition
*condition
,
637 const char **channel_name
)
639 struct lttng_condition_buffer_usage
*usage
;
640 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
642 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
643 status
= LTTNG_CONDITION_STATUS_INVALID
;
647 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
649 if (!usage
->channel_name
) {
650 status
= LTTNG_CONDITION_STATUS_UNSET
;
653 *channel_name
= usage
->channel_name
;
658 enum lttng_condition_status
659 lttng_condition_buffer_usage_set_channel_name(
660 struct lttng_condition
*condition
, const char *channel_name
)
662 char *channel_name_copy
;
663 struct lttng_condition_buffer_usage
*usage
;
664 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
666 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
667 strlen(channel_name
) == 0) {
668 status
= LTTNG_CONDITION_STATUS_INVALID
;
672 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
674 channel_name_copy
= strdup(channel_name
);
675 if (!channel_name_copy
) {
676 status
= LTTNG_CONDITION_STATUS_ERROR
;
680 if (usage
->channel_name
) {
681 free(usage
->channel_name
);
683 usage
->channel_name
= channel_name_copy
;
688 enum lttng_condition_status
689 lttng_condition_buffer_usage_get_domain_type(
690 const struct lttng_condition
*condition
,
691 enum lttng_domain_type
*type
)
693 struct lttng_condition_buffer_usage
*usage
;
694 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
696 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
697 status
= LTTNG_CONDITION_STATUS_INVALID
;
701 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
703 if (!usage
->domain
.set
) {
704 status
= LTTNG_CONDITION_STATUS_UNSET
;
707 *type
= usage
->domain
.type
;
712 enum lttng_condition_status
713 lttng_condition_buffer_usage_set_domain_type(
714 struct lttng_condition
*condition
, enum lttng_domain_type type
)
716 struct lttng_condition_buffer_usage
*usage
;
717 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
719 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
720 type
== LTTNG_DOMAIN_NONE
) {
721 status
= LTTNG_CONDITION_STATUS_INVALID
;
725 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
727 usage
->domain
.set
= true;
728 usage
->domain
.type
= type
;
734 int lttng_evaluation_buffer_usage_serialize(
735 const struct lttng_evaluation
*evaluation
,
736 struct lttng_payload
*payload
)
738 struct lttng_evaluation_buffer_usage
*usage
;
739 struct lttng_evaluation_buffer_usage_comm comm
;
741 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
743 comm
.buffer_use
= usage
->buffer_use
;
744 comm
.buffer_capacity
= usage
->buffer_capacity
;
746 return lttng_dynamic_buffer_append(
747 &payload
->buffer
, &comm
, sizeof(comm
));
751 void lttng_evaluation_buffer_usage_destroy(
752 struct lttng_evaluation
*evaluation
)
754 struct lttng_evaluation_buffer_usage
*usage
;
756 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
762 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
763 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
765 struct lttng_evaluation_buffer_usage
*usage
;
767 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
772 usage
->parent
.type
= type
;
773 usage
->buffer_use
= use
;
774 usage
->buffer_capacity
= capacity
;
775 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
776 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
778 return &usage
->parent
;
782 * Get the sampled buffer usage which caused the associated condition to
783 * evaluate to "true".
785 enum lttng_evaluation_status
786 lttng_evaluation_buffer_usage_get_usage_ratio(
787 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
789 struct lttng_evaluation_buffer_usage
*usage
;
790 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
792 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
793 status
= LTTNG_EVALUATION_STATUS_INVALID
;
797 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
799 *usage_ratio
= (double) usage
->buffer_use
/
800 (double) usage
->buffer_capacity
;
805 enum lttng_evaluation_status
806 lttng_evaluation_buffer_usage_get_usage(
807 const struct lttng_evaluation
*evaluation
,
808 uint64_t *usage_bytes
)
810 struct lttng_evaluation_buffer_usage
*usage
;
811 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
813 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
814 status
= LTTNG_EVALUATION_STATUS_INVALID
;
818 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
820 *usage_bytes
= usage
->buffer_use
;