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_dynamic_buffer
*buf
)
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(buf
, &usage_comm
,
142 ret
= lttng_dynamic_buffer_append(buf
, usage
->session_name
,
147 ret
= lttng_dynamic_buffer_append(buf
, usage
->channel_name
,
157 bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition
*_a
,
158 const struct lttng_condition
*_b
)
160 bool is_equal
= false;
161 struct lttng_condition_buffer_usage
*a
, *b
;
163 a
= container_of(_a
, struct lttng_condition_buffer_usage
, parent
);
164 b
= container_of(_b
, struct lttng_condition_buffer_usage
, parent
);
166 if ((a
->threshold_ratio
.set
&& !b
->threshold_ratio
.set
) ||
167 (a
->threshold_bytes
.set
&& !b
->threshold_bytes
.set
)) {
171 if (a
->threshold_ratio
.set
&& b
->threshold_ratio
.set
) {
172 double a_value
, b_value
, diff
;
174 a_value
= a
->threshold_ratio
.value
;
175 b_value
= b
->threshold_ratio
.value
;
176 diff
= fabs(a_value
- b_value
);
178 if (diff
> DBL_EPSILON
) {
181 } else if (a
->threshold_bytes
.set
&& b
->threshold_bytes
.set
) {
182 uint64_t a_value
, b_value
;
184 a_value
= a
->threshold_bytes
.value
;
185 b_value
= b
->threshold_bytes
.value
;
186 if (a_value
!= b_value
) {
191 /* Condition is not valid if this is not true. */
192 assert(a
->session_name
);
193 assert(b
->session_name
);
194 if (strcmp(a
->session_name
, b
->session_name
)) {
198 assert(a
->channel_name
);
199 assert(b
->channel_name
);
200 if (strcmp(a
->channel_name
, b
->channel_name
)) {
204 assert(a
->domain
.set
);
205 assert(b
->domain
.set
);
206 if (a
->domain
.type
!= b
->domain
.type
) {
215 struct lttng_condition
*lttng_condition_buffer_usage_create(
216 enum lttng_condition_type type
)
218 struct lttng_condition_buffer_usage
*condition
;
220 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
225 lttng_condition_init(&condition
->parent
, type
);
226 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
227 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
228 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
229 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
230 return &condition
->parent
;
233 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
235 return lttng_condition_buffer_usage_create(
236 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
239 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
241 return lttng_condition_buffer_usage_create(
242 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
246 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
247 const struct lttng_buffer_view
*src_view
)
249 ssize_t ret
, condition_size
;
250 enum lttng_condition_status status
;
251 enum lttng_domain_type domain_type
;
252 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
253 const char *session_name
, *channel_name
;
254 struct lttng_buffer_view names_view
;
256 if (src_view
->size
< sizeof(*condition_comm
)) {
257 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
262 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
263 names_view
= lttng_buffer_view_from_view(src_view
,
264 sizeof(*condition_comm
), -1);
266 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
267 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
268 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
273 if (names_view
.size
<
274 (condition_comm
->session_name_len
+
275 condition_comm
->channel_name_len
)) {
276 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
281 if (condition_comm
->threshold_set_in_bytes
) {
282 status
= lttng_condition_buffer_usage_set_threshold(condition
,
283 condition_comm
->threshold
);
285 status
= lttng_condition_buffer_usage_set_threshold_ratio(
287 fixed_to_double(condition_comm
->threshold
));
289 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
290 ERR("Failed to initialize buffer usage condition threshold");
295 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
296 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
297 /* Invalid domain value. */
298 ERR("Invalid domain type value (%i) found in condition buffer",
299 (int) condition_comm
->domain_type
);
304 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
305 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
307 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
308 ERR("Failed to set buffer usage condition domain");
313 session_name
= names_view
.data
;
314 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
315 ERR("Malformed session name encountered in condition buffer");
320 channel_name
= session_name
+ condition_comm
->session_name_len
;
321 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
322 ERR("Malformed channel name encountered in condition buffer");
327 status
= lttng_condition_buffer_usage_set_session_name(condition
,
329 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
330 ERR("Failed to set buffer usage session name");
335 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
337 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
338 ERR("Failed to set buffer usage channel name");
343 if (!lttng_condition_validate(condition
)) {
348 condition_size
= sizeof(*condition_comm
) +
349 (ssize_t
) condition_comm
->session_name_len
+
350 (ssize_t
) condition_comm
->channel_name_len
;
351 ret
= condition_size
;
357 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
358 const struct lttng_buffer_view
*view
,
359 struct lttng_condition
**_condition
)
362 struct lttng_condition
*condition
=
363 lttng_condition_buffer_usage_low_create();
365 if (!_condition
|| !condition
) {
370 ret
= init_condition_from_buffer(condition
, view
);
375 *_condition
= condition
;
378 lttng_condition_destroy(condition
);
383 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
384 const struct lttng_buffer_view
*view
,
385 struct lttng_condition
**_condition
)
388 struct lttng_condition
*condition
=
389 lttng_condition_buffer_usage_high_create();
391 if (!_condition
|| !condition
) {
396 ret
= init_condition_from_buffer(condition
, view
);
401 *_condition
= condition
;
404 lttng_condition_destroy(condition
);
409 struct lttng_evaluation
*create_evaluation_from_buffer(
410 enum lttng_condition_type type
,
411 const struct lttng_buffer_view
*view
)
413 const struct lttng_evaluation_buffer_usage_comm
*comm
=
414 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
415 struct lttng_evaluation
*evaluation
= NULL
;
417 if (view
->size
< sizeof(*comm
)) {
421 evaluation
= lttng_evaluation_buffer_usage_create(type
,
422 comm
->buffer_use
, comm
->buffer_capacity
);
428 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
429 const struct lttng_buffer_view
*view
,
430 struct lttng_evaluation
**_evaluation
)
433 struct lttng_evaluation
*evaluation
= NULL
;
440 evaluation
= create_evaluation_from_buffer(
441 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
447 *_evaluation
= evaluation
;
448 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
451 lttng_evaluation_destroy(evaluation
);
456 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
457 const struct lttng_buffer_view
*view
,
458 struct lttng_evaluation
**_evaluation
)
461 struct lttng_evaluation
*evaluation
= NULL
;
468 evaluation
= create_evaluation_from_buffer(
469 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
475 *_evaluation
= evaluation
;
476 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
479 lttng_evaluation_destroy(evaluation
);
483 enum lttng_condition_status
484 lttng_condition_buffer_usage_get_threshold_ratio(
485 const struct lttng_condition
*condition
,
486 double *threshold_ratio
)
488 struct lttng_condition_buffer_usage
*usage
;
489 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
491 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
493 status
= LTTNG_CONDITION_STATUS_INVALID
;
497 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
499 if (!usage
->threshold_ratio
.set
) {
500 status
= LTTNG_CONDITION_STATUS_UNSET
;
503 *threshold_ratio
= usage
->threshold_ratio
.value
;
508 /* threshold_ratio expressed as [0.0, 1.0]. */
509 enum lttng_condition_status
510 lttng_condition_buffer_usage_set_threshold_ratio(
511 struct lttng_condition
*condition
, double threshold_ratio
)
513 struct lttng_condition_buffer_usage
*usage
;
514 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
516 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
517 threshold_ratio
< 0.0 ||
518 threshold_ratio
> 1.0) {
519 status
= LTTNG_CONDITION_STATUS_INVALID
;
523 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
525 usage
->threshold_ratio
.set
= true;
526 usage
->threshold_bytes
.set
= false;
527 usage
->threshold_ratio
.value
= threshold_ratio
;
532 enum lttng_condition_status
533 lttng_condition_buffer_usage_get_threshold(
534 const struct lttng_condition
*condition
,
535 uint64_t *threshold_bytes
)
537 struct lttng_condition_buffer_usage
*usage
;
538 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
540 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
541 status
= LTTNG_CONDITION_STATUS_INVALID
;
545 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
547 if (!usage
->threshold_bytes
.set
) {
548 status
= LTTNG_CONDITION_STATUS_UNSET
;
551 *threshold_bytes
= usage
->threshold_bytes
.value
;
556 enum lttng_condition_status
557 lttng_condition_buffer_usage_set_threshold(
558 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
560 struct lttng_condition_buffer_usage
*usage
;
561 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
563 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
564 status
= LTTNG_CONDITION_STATUS_INVALID
;
568 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
570 usage
->threshold_ratio
.set
= false;
571 usage
->threshold_bytes
.set
= true;
572 usage
->threshold_bytes
.value
= threshold_bytes
;
577 enum lttng_condition_status
578 lttng_condition_buffer_usage_get_session_name(
579 const struct lttng_condition
*condition
,
580 const char **session_name
)
582 struct lttng_condition_buffer_usage
*usage
;
583 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
585 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
586 status
= LTTNG_CONDITION_STATUS_INVALID
;
590 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
592 if (!usage
->session_name
) {
593 status
= LTTNG_CONDITION_STATUS_UNSET
;
596 *session_name
= usage
->session_name
;
601 enum lttng_condition_status
602 lttng_condition_buffer_usage_set_session_name(
603 struct lttng_condition
*condition
, const char *session_name
)
605 char *session_name_copy
;
606 struct lttng_condition_buffer_usage
*usage
;
607 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
609 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
610 strlen(session_name
) == 0) {
611 status
= LTTNG_CONDITION_STATUS_INVALID
;
615 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
617 session_name_copy
= strdup(session_name
);
618 if (!session_name_copy
) {
619 status
= LTTNG_CONDITION_STATUS_ERROR
;
623 if (usage
->session_name
) {
624 free(usage
->session_name
);
626 usage
->session_name
= session_name_copy
;
631 enum lttng_condition_status
632 lttng_condition_buffer_usage_get_channel_name(
633 const struct lttng_condition
*condition
,
634 const char **channel_name
)
636 struct lttng_condition_buffer_usage
*usage
;
637 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
639 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
640 status
= LTTNG_CONDITION_STATUS_INVALID
;
644 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
646 if (!usage
->channel_name
) {
647 status
= LTTNG_CONDITION_STATUS_UNSET
;
650 *channel_name
= usage
->channel_name
;
655 enum lttng_condition_status
656 lttng_condition_buffer_usage_set_channel_name(
657 struct lttng_condition
*condition
, const char *channel_name
)
659 char *channel_name_copy
;
660 struct lttng_condition_buffer_usage
*usage
;
661 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
663 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
664 strlen(channel_name
) == 0) {
665 status
= LTTNG_CONDITION_STATUS_INVALID
;
669 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
671 channel_name_copy
= strdup(channel_name
);
672 if (!channel_name_copy
) {
673 status
= LTTNG_CONDITION_STATUS_ERROR
;
677 if (usage
->channel_name
) {
678 free(usage
->channel_name
);
680 usage
->channel_name
= channel_name_copy
;
685 enum lttng_condition_status
686 lttng_condition_buffer_usage_get_domain_type(
687 const struct lttng_condition
*condition
,
688 enum lttng_domain_type
*type
)
690 struct lttng_condition_buffer_usage
*usage
;
691 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
693 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
694 status
= LTTNG_CONDITION_STATUS_INVALID
;
698 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
700 if (!usage
->domain
.set
) {
701 status
= LTTNG_CONDITION_STATUS_UNSET
;
704 *type
= usage
->domain
.type
;
709 enum lttng_condition_status
710 lttng_condition_buffer_usage_set_domain_type(
711 struct lttng_condition
*condition
, enum lttng_domain_type type
)
713 struct lttng_condition_buffer_usage
*usage
;
714 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
716 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
717 type
== LTTNG_DOMAIN_NONE
) {
718 status
= LTTNG_CONDITION_STATUS_INVALID
;
722 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
724 usage
->domain
.set
= true;
725 usage
->domain
.type
= type
;
731 int lttng_evaluation_buffer_usage_serialize(
732 const struct lttng_evaluation
*evaluation
,
733 struct lttng_dynamic_buffer
*buf
)
735 struct lttng_evaluation_buffer_usage
*usage
;
736 struct lttng_evaluation_buffer_usage_comm comm
;
738 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
740 comm
.buffer_use
= usage
->buffer_use
;
741 comm
.buffer_capacity
= usage
->buffer_capacity
;
743 return lttng_dynamic_buffer_append(buf
, &comm
, sizeof(comm
));
747 void lttng_evaluation_buffer_usage_destroy(
748 struct lttng_evaluation
*evaluation
)
750 struct lttng_evaluation_buffer_usage
*usage
;
752 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
758 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
759 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
761 struct lttng_evaluation_buffer_usage
*usage
;
763 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
768 usage
->parent
.type
= type
;
769 usage
->buffer_use
= use
;
770 usage
->buffer_capacity
= capacity
;
771 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
772 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
774 return &usage
->parent
;
778 * Get the sampled buffer usage which caused the associated condition to
779 * evaluate to "true".
781 enum lttng_evaluation_status
782 lttng_evaluation_buffer_usage_get_usage_ratio(
783 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
785 struct lttng_evaluation_buffer_usage
*usage
;
786 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
788 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
789 status
= LTTNG_EVALUATION_STATUS_INVALID
;
793 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
795 *usage_ratio
= (double) usage
->buffer_use
/
796 (double) usage
->buffer_capacity
;
801 enum lttng_evaluation_status
802 lttng_evaluation_buffer_usage_get_usage(
803 const struct lttng_evaluation
*evaluation
,
804 uint64_t *usage_bytes
)
806 struct lttng_evaluation_buffer_usage
*usage
;
807 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
809 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
810 status
= LTTNG_EVALUATION_STATUS_INVALID
;
814 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
816 *usage_bytes
= usage
->buffer_use
;