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
,
98 struct lttng_condition_buffer_usage
*usage
;
99 size_t session_name_len
, channel_name_len
;
100 struct lttng_condition_buffer_usage_comm usage_comm
;
102 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
107 DBG("Serializing buffer usage condition");
108 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
111 session_name_len
= strlen(usage
->session_name
) + 1;
112 channel_name_len
= strlen(usage
->channel_name
) + 1;
113 if (session_name_len
> LTTNG_NAME_MAX
||
114 channel_name_len
> LTTNG_NAME_MAX
) {
119 usage_comm
.threshold_set_in_bytes
= !!usage
->threshold_bytes
.set
;
120 usage_comm
.session_name_len
= session_name_len
;
121 usage_comm
.channel_name_len
= channel_name_len
;
122 usage_comm
.domain_type
= (int8_t) usage
->domain
.type
;
124 if (usage
->threshold_bytes
.set
) {
125 usage_comm
.threshold
= usage
->threshold_bytes
.value
;
127 uint64_t val
= double_to_fixed(
128 usage
->threshold_ratio
.value
);
130 if (val
> UINT32_MAX
) {
135 usage_comm
.threshold
= val
;
138 ret
= lttng_dynamic_buffer_append(buf
, &usage_comm
,
143 ret
= lttng_dynamic_buffer_append(buf
, usage
->session_name
,
148 ret
= lttng_dynamic_buffer_append(buf
, usage
->channel_name
,
163 bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition
*_a
,
164 const struct lttng_condition
*_b
)
166 bool is_equal
= false;
167 struct lttng_condition_buffer_usage
*a
, *b
;
169 a
= container_of(_a
, struct lttng_condition_buffer_usage
, parent
);
170 b
= container_of(_b
, struct lttng_condition_buffer_usage
, parent
);
172 if ((a
->threshold_ratio
.set
&& !b
->threshold_ratio
.set
) ||
173 (a
->threshold_bytes
.set
&& !b
->threshold_bytes
.set
)) {
177 if (a
->threshold_ratio
.set
&& b
->threshold_ratio
.set
) {
178 double a_value
, b_value
, diff
;
180 a_value
= a
->threshold_ratio
.value
;
181 b_value
= b
->threshold_ratio
.value
;
182 diff
= fabs(a_value
- b_value
);
184 if (diff
> DBL_EPSILON
) {
187 } else if (a
->threshold_bytes
.set
&& b
->threshold_bytes
.set
) {
188 uint64_t a_value
, b_value
;
190 a_value
= a
->threshold_bytes
.value
;
191 b_value
= b
->threshold_bytes
.value
;
192 if (a_value
!= b_value
) {
197 /* Condition is not valid if this is not true. */
198 assert(a
->session_name
);
199 assert(b
->session_name
);
200 if (strcmp(a
->session_name
, b
->session_name
)) {
204 assert(a
->channel_name
);
205 assert(b
->channel_name
);
206 if (strcmp(a
->channel_name
, b
->channel_name
)) {
210 assert(a
->domain
.set
);
211 assert(b
->domain
.set
);
212 if (a
->domain
.type
!= b
->domain
.type
) {
221 struct lttng_condition
*lttng_condition_buffer_usage_create(
222 enum lttng_condition_type type
)
224 struct lttng_condition_buffer_usage
*condition
;
226 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
231 lttng_condition_init(&condition
->parent
, type
);
232 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
233 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
234 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
235 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
236 return &condition
->parent
;
239 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
241 return lttng_condition_buffer_usage_create(
242 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
245 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
247 return lttng_condition_buffer_usage_create(
248 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
252 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
253 const struct lttng_buffer_view
*src_view
)
255 ssize_t ret
, condition_size
;
256 enum lttng_condition_status status
;
257 enum lttng_domain_type domain_type
;
258 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
259 const char *session_name
, *channel_name
;
260 struct lttng_buffer_view names_view
;
262 if (src_view
->size
< sizeof(*condition_comm
)) {
263 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
268 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
269 names_view
= lttng_buffer_view_from_view(src_view
,
270 sizeof(*condition_comm
), -1);
272 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
273 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
274 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
279 if (names_view
.size
<
280 (condition_comm
->session_name_len
+
281 condition_comm
->channel_name_len
)) {
282 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
287 if (condition_comm
->threshold_set_in_bytes
) {
288 status
= lttng_condition_buffer_usage_set_threshold(condition
,
289 condition_comm
->threshold
);
291 status
= lttng_condition_buffer_usage_set_threshold_ratio(
293 fixed_to_double(condition_comm
->threshold
));
295 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
296 ERR("Failed to initialize buffer usage condition threshold");
301 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
302 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
303 /* Invalid domain value. */
304 ERR("Invalid domain type value (%i) found in condition buffer",
305 (int) condition_comm
->domain_type
);
310 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
311 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
313 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
314 ERR("Failed to set buffer usage condition domain");
319 session_name
= names_view
.data
;
320 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
321 ERR("Malformed session name encountered in condition buffer");
326 channel_name
= session_name
+ condition_comm
->session_name_len
;
327 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
328 ERR("Malformed channel name encountered in condition buffer");
333 status
= lttng_condition_buffer_usage_set_session_name(condition
,
335 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
336 ERR("Failed to set buffer usage session name");
341 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
343 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
344 ERR("Failed to set buffer usage channel name");
349 if (!lttng_condition_validate(condition
)) {
354 condition_size
= sizeof(*condition_comm
) +
355 (ssize_t
) condition_comm
->session_name_len
+
356 (ssize_t
) condition_comm
->channel_name_len
;
357 ret
= condition_size
;
363 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
364 const struct lttng_buffer_view
*view
,
365 struct lttng_condition
**_condition
)
368 struct lttng_condition
*condition
=
369 lttng_condition_buffer_usage_low_create();
371 if (!_condition
|| !condition
) {
376 ret
= init_condition_from_buffer(condition
, view
);
381 *_condition
= condition
;
384 lttng_condition_destroy(condition
);
389 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
390 const struct lttng_buffer_view
*view
,
391 struct lttng_condition
**_condition
)
394 struct lttng_condition
*condition
=
395 lttng_condition_buffer_usage_high_create();
397 if (!_condition
|| !condition
) {
402 ret
= init_condition_from_buffer(condition
, view
);
407 *_condition
= condition
;
410 lttng_condition_destroy(condition
);
415 struct lttng_evaluation
*create_evaluation_from_buffer(
416 enum lttng_condition_type type
,
417 const struct lttng_buffer_view
*view
)
419 const struct lttng_evaluation_buffer_usage_comm
*comm
=
420 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
421 struct lttng_evaluation
*evaluation
= NULL
;
423 if (view
->size
< sizeof(*comm
)) {
427 evaluation
= lttng_evaluation_buffer_usage_create(type
,
428 comm
->buffer_use
, comm
->buffer_capacity
);
434 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
435 const struct lttng_buffer_view
*view
,
436 struct lttng_evaluation
**_evaluation
)
439 struct lttng_evaluation
*evaluation
= NULL
;
446 evaluation
= create_evaluation_from_buffer(
447 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
453 *_evaluation
= evaluation
;
454 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
457 lttng_evaluation_destroy(evaluation
);
462 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
463 const struct lttng_buffer_view
*view
,
464 struct lttng_evaluation
**_evaluation
)
467 struct lttng_evaluation
*evaluation
= NULL
;
474 evaluation
= create_evaluation_from_buffer(
475 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
481 *_evaluation
= evaluation
;
482 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
485 lttng_evaluation_destroy(evaluation
);
489 enum lttng_condition_status
490 lttng_condition_buffer_usage_get_threshold_ratio(
491 const struct lttng_condition
*condition
,
492 double *threshold_ratio
)
494 struct lttng_condition_buffer_usage
*usage
;
495 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
497 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
499 status
= LTTNG_CONDITION_STATUS_INVALID
;
503 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
505 if (!usage
->threshold_ratio
.set
) {
506 status
= LTTNG_CONDITION_STATUS_UNSET
;
509 *threshold_ratio
= usage
->threshold_ratio
.value
;
514 /* threshold_ratio expressed as [0.0, 1.0]. */
515 enum lttng_condition_status
516 lttng_condition_buffer_usage_set_threshold_ratio(
517 struct lttng_condition
*condition
, double threshold_ratio
)
519 struct lttng_condition_buffer_usage
*usage
;
520 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
522 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
523 threshold_ratio
< 0.0 ||
524 threshold_ratio
> 1.0) {
525 status
= LTTNG_CONDITION_STATUS_INVALID
;
529 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
531 usage
->threshold_ratio
.set
= true;
532 usage
->threshold_bytes
.set
= false;
533 usage
->threshold_ratio
.value
= threshold_ratio
;
538 enum lttng_condition_status
539 lttng_condition_buffer_usage_get_threshold(
540 const struct lttng_condition
*condition
,
541 uint64_t *threshold_bytes
)
543 struct lttng_condition_buffer_usage
*usage
;
544 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
546 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
547 status
= LTTNG_CONDITION_STATUS_INVALID
;
551 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
553 if (!usage
->threshold_bytes
.set
) {
554 status
= LTTNG_CONDITION_STATUS_UNSET
;
557 *threshold_bytes
= usage
->threshold_bytes
.value
;
562 enum lttng_condition_status
563 lttng_condition_buffer_usage_set_threshold(
564 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
566 struct lttng_condition_buffer_usage
*usage
;
567 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
569 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
570 status
= LTTNG_CONDITION_STATUS_INVALID
;
574 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
576 usage
->threshold_ratio
.set
= false;
577 usage
->threshold_bytes
.set
= true;
578 usage
->threshold_bytes
.value
= threshold_bytes
;
583 enum lttng_condition_status
584 lttng_condition_buffer_usage_get_session_name(
585 const struct lttng_condition
*condition
,
586 const char **session_name
)
588 struct lttng_condition_buffer_usage
*usage
;
589 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
591 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
592 status
= LTTNG_CONDITION_STATUS_INVALID
;
596 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
598 if (!usage
->session_name
) {
599 status
= LTTNG_CONDITION_STATUS_UNSET
;
602 *session_name
= usage
->session_name
;
607 enum lttng_condition_status
608 lttng_condition_buffer_usage_set_session_name(
609 struct lttng_condition
*condition
, const char *session_name
)
611 char *session_name_copy
;
612 struct lttng_condition_buffer_usage
*usage
;
613 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
615 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
616 strlen(session_name
) == 0) {
617 status
= LTTNG_CONDITION_STATUS_INVALID
;
621 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
623 session_name_copy
= strdup(session_name
);
624 if (!session_name_copy
) {
625 status
= LTTNG_CONDITION_STATUS_ERROR
;
629 if (usage
->session_name
) {
630 free(usage
->session_name
);
632 usage
->session_name
= session_name_copy
;
637 enum lttng_condition_status
638 lttng_condition_buffer_usage_get_channel_name(
639 const struct lttng_condition
*condition
,
640 const char **channel_name
)
642 struct lttng_condition_buffer_usage
*usage
;
643 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
645 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
646 status
= LTTNG_CONDITION_STATUS_INVALID
;
650 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
652 if (!usage
->channel_name
) {
653 status
= LTTNG_CONDITION_STATUS_UNSET
;
656 *channel_name
= usage
->channel_name
;
661 enum lttng_condition_status
662 lttng_condition_buffer_usage_set_channel_name(
663 struct lttng_condition
*condition
, const char *channel_name
)
665 char *channel_name_copy
;
666 struct lttng_condition_buffer_usage
*usage
;
667 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
669 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
670 strlen(channel_name
) == 0) {
671 status
= LTTNG_CONDITION_STATUS_INVALID
;
675 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
677 channel_name_copy
= strdup(channel_name
);
678 if (!channel_name_copy
) {
679 status
= LTTNG_CONDITION_STATUS_ERROR
;
683 if (usage
->channel_name
) {
684 free(usage
->channel_name
);
686 usage
->channel_name
= channel_name_copy
;
691 enum lttng_condition_status
692 lttng_condition_buffer_usage_get_domain_type(
693 const struct lttng_condition
*condition
,
694 enum lttng_domain_type
*type
)
696 struct lttng_condition_buffer_usage
*usage
;
697 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
699 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
700 status
= LTTNG_CONDITION_STATUS_INVALID
;
704 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
706 if (!usage
->domain
.set
) {
707 status
= LTTNG_CONDITION_STATUS_UNSET
;
710 *type
= usage
->domain
.type
;
715 enum lttng_condition_status
716 lttng_condition_buffer_usage_set_domain_type(
717 struct lttng_condition
*condition
, enum lttng_domain_type type
)
719 struct lttng_condition_buffer_usage
*usage
;
720 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
722 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
723 type
== LTTNG_DOMAIN_NONE
) {
724 status
= LTTNG_CONDITION_STATUS_INVALID
;
728 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
730 usage
->domain
.set
= true;
731 usage
->domain
.type
= type
;
737 int lttng_evaluation_buffer_usage_serialize(
738 const struct lttng_evaluation
*evaluation
,
739 struct lttng_dynamic_buffer
*buf
)
741 struct lttng_evaluation_buffer_usage
*usage
;
742 struct lttng_evaluation_buffer_usage_comm comm
;
744 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
746 comm
.buffer_use
= usage
->buffer_use
;
747 comm
.buffer_capacity
= usage
->buffer_capacity
;
749 return lttng_dynamic_buffer_append(buf
, &comm
, sizeof(comm
));
753 void lttng_evaluation_buffer_usage_destroy(
754 struct lttng_evaluation
*evaluation
)
756 struct lttng_evaluation_buffer_usage
*usage
;
758 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
764 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
765 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
767 struct lttng_evaluation_buffer_usage
*usage
;
769 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
774 usage
->parent
.type
= type
;
775 usage
->buffer_use
= use
;
776 usage
->buffer_capacity
= capacity
;
777 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
778 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
780 return &usage
->parent
;
784 * Get the sampled buffer usage which caused the associated condition to
785 * evaluate to "true".
787 enum lttng_evaluation_status
788 lttng_evaluation_buffer_usage_get_usage_ratio(
789 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
791 struct lttng_evaluation_buffer_usage
*usage
;
792 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
794 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
795 status
= LTTNG_EVALUATION_STATUS_INVALID
;
799 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
801 *usage_ratio
= (double) usage
->buffer_use
/
802 (double) usage
->buffer_capacity
;
807 enum lttng_evaluation_status
808 lttng_evaluation_buffer_usage_get_usage(
809 const struct lttng_evaluation
*evaluation
,
810 uint64_t *usage_bytes
)
812 struct lttng_evaluation_buffer_usage
*usage
;
813 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
815 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
816 status
= LTTNG_EVALUATION_STATUS_INVALID
;
820 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
822 *usage_bytes
= usage
->buffer_use
;