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 char *session_name
, *channel_name
;
255 struct lttng_buffer_view names_view
;
256 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
257 const struct lttng_payload_view condition_comm_view
=
258 lttng_payload_view_from_view(
259 src_view
, 0, sizeof(*condition_comm
));
261 if (!lttng_payload_view_is_valid(&condition_comm_view
)) {
262 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
267 condition_comm
= (typeof(condition_comm
)) condition_comm_view
.buffer
.data
;
268 names_view
= lttng_buffer_view_from_view(&src_view
->buffer
,
269 sizeof(*condition_comm
), -1);
271 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
272 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
273 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
278 if (names_view
.size
<
279 (condition_comm
->session_name_len
+
280 condition_comm
->channel_name_len
)) {
281 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
286 if (condition_comm
->threshold_set_in_bytes
) {
287 status
= lttng_condition_buffer_usage_set_threshold(condition
,
288 condition_comm
->threshold
);
290 status
= lttng_condition_buffer_usage_set_threshold_ratio(
292 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_payload(
364 struct lttng_payload_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_payload(condition
, view
);
381 *_condition
= condition
;
384 lttng_condition_destroy(condition
);
389 ssize_t
lttng_condition_buffer_usage_high_create_from_payload(
390 struct lttng_payload_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_payload(condition
, view
);
407 *_condition
= condition
;
410 lttng_condition_destroy(condition
);
415 struct lttng_evaluation
*create_evaluation_from_payload(
416 enum lttng_condition_type type
,
417 struct lttng_payload_view
*view
)
419 const struct lttng_evaluation_buffer_usage_comm
*comm
=
420 (typeof(comm
)) view
->buffer
.data
;
421 struct lttng_evaluation
*evaluation
= NULL
;
423 if (view
->buffer
.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_payload(
435 struct lttng_payload_view
*view
,
436 struct lttng_evaluation
**_evaluation
)
439 struct lttng_evaluation
*evaluation
= NULL
;
446 evaluation
= create_evaluation_from_payload(
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_payload(
463 struct lttng_payload_view
*view
,
464 struct lttng_evaluation
**_evaluation
)
467 struct lttng_evaluation
*evaluation
= NULL
;
474 evaluation
= create_evaluation_from_payload(
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_payload
*payload
)
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(
750 &payload
->buffer
, &comm
, sizeof(comm
));
754 void lttng_evaluation_buffer_usage_destroy(
755 struct lttng_evaluation
*evaluation
)
757 struct lttng_evaluation_buffer_usage
*usage
;
759 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
765 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
766 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
768 struct lttng_evaluation_buffer_usage
*usage
;
770 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
775 usage
->parent
.type
= type
;
776 usage
->buffer_use
= use
;
777 usage
->buffer_capacity
= capacity
;
778 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
779 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
781 return &usage
->parent
;
785 * Get the sampled buffer usage which caused the associated condition to
786 * evaluate to "true".
788 enum lttng_evaluation_status
789 lttng_evaluation_buffer_usage_get_usage_ratio(
790 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
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_ratio
) {
796 status
= LTTNG_EVALUATION_STATUS_INVALID
;
800 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
802 *usage_ratio
= (double) usage
->buffer_use
/
803 (double) usage
->buffer_capacity
;
808 enum lttng_evaluation_status
809 lttng_evaluation_buffer_usage_get_usage(
810 const struct lttng_evaluation
*evaluation
,
811 uint64_t *usage_bytes
)
813 struct lttng_evaluation_buffer_usage
*usage
;
814 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
816 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
817 status
= LTTNG_EVALUATION_STATUS_INVALID
;
821 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
823 *usage_bytes
= usage
->buffer_use
;