2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include <lttng/condition/condition-internal.h>
19 #include <lttng/condition/buffer-usage-internal.h>
20 #include <common/macros.h>
21 #include <common/error.h>
27 #define IS_USAGE_CONDITION(condition) ( \
28 lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW || \
29 lttng_condition_get_type(condition) == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH \
33 double fixed_to_double(uint32_t val
)
35 return (double) val
/ (double) UINT32_MAX
;
39 uint64_t double_to_fixed(double val
)
41 return (val
* (double) UINT32_MAX
);
45 bool is_usage_evaluation(const struct lttng_evaluation
*evaluation
)
47 enum lttng_condition_type type
= lttng_evaluation_get_type(evaluation
);
49 return type
== LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
||
50 type
== LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
;
54 void lttng_condition_buffer_usage_destroy(struct lttng_condition
*condition
)
56 struct lttng_condition_buffer_usage
*usage
;
58 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
61 free(usage
->session_name
);
62 free(usage
->channel_name
);
67 bool lttng_condition_buffer_usage_validate(
68 const struct lttng_condition
*condition
)
71 struct lttng_condition_buffer_usage
*usage
;
77 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
79 if (!usage
->session_name
) {
80 ERR("Invalid buffer condition: a target session name must be set.");
83 if (!usage
->channel_name
) {
84 ERR("Invalid buffer condition: a target channel name must be set.");
87 if (!usage
->threshold_ratio
.set
&& !usage
->threshold_bytes
.set
) {
88 ERR("Invalid buffer condition: a threshold must be set.");
98 ssize_t
lttng_condition_buffer_usage_serialize(
99 const struct lttng_condition
*condition
, char *buf
)
101 struct lttng_condition_buffer_usage
*usage
;
103 size_t session_name_len
, channel_name_len
;
105 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
110 DBG("Serializing buffer usage condition");
111 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
113 size
= sizeof(struct lttng_condition_buffer_usage_comm
);
114 session_name_len
= strlen(usage
->session_name
) + 1;
115 channel_name_len
= strlen(usage
->channel_name
) + 1;
116 if (session_name_len
> LTTNG_NAME_MAX
||
117 channel_name_len
> LTTNG_NAME_MAX
) {
121 size
+= session_name_len
+ channel_name_len
;
123 struct lttng_condition_buffer_usage_comm usage_comm
= {
124 .threshold_set_in_bytes
= usage
->threshold_bytes
.set
? 1 : 0,
125 .session_name_len
= session_name_len
,
126 .channel_name_len
= channel_name_len
,
127 .domain_type
= (int8_t) usage
->domain
.type
,
130 if (usage
->threshold_bytes
.set
) {
131 usage_comm
.threshold
= usage
->threshold_bytes
.value
;
133 uint64_t val
= double_to_fixed(
134 usage
->threshold_ratio
.value
);
136 if (val
> UINT32_MAX
) {
141 usage_comm
.threshold
= val
;
144 memcpy(buf
, &usage_comm
, sizeof(usage_comm
));
145 buf
+= sizeof(usage_comm
);
146 memcpy(buf
, usage
->session_name
, session_name_len
);
147 buf
+= session_name_len
;
148 memcpy(buf
, usage
->channel_name
, channel_name_len
);
149 buf
+= channel_name_len
;
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 if ((a
->session_name
&& !b
->session_name
) ||
192 (!a
->session_name
&& b
->session_name
)) {
196 if (a
->channel_name
&& b
->channel_name
) {
197 if (strcmp(a
->channel_name
, b
->channel_name
)) {
200 } if ((a
->channel_name
&& !b
->channel_name
) ||
201 (!a
->channel_name
&& b
->channel_name
)) {
205 if (a
->channel_name
&& b
->channel_name
) {
206 if (strcmp(a
->channel_name
, b
->channel_name
)) {
211 if ((a
->domain
.set
&& !b
->domain
.set
) ||
212 (!a
->domain
.set
&& b
->domain
.set
)) {
216 if (a
->domain
.set
&& b
->domain
.set
) {
217 if (a
->domain
.type
!= b
->domain
.type
) {
227 struct lttng_condition
*lttng_condition_buffer_usage_create(
228 enum lttng_condition_type type
)
230 struct lttng_condition_buffer_usage
*condition
;
232 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
237 lttng_condition_init(&condition
->parent
, type
);
238 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
239 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
240 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
241 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
242 return &condition
->parent
;
245 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
247 return lttng_condition_buffer_usage_create(
248 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
251 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
253 return lttng_condition_buffer_usage_create(
254 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
258 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
259 const struct lttng_buffer_view
*src_view
)
261 ssize_t ret
, condition_size
;
262 enum lttng_condition_status status
;
263 enum lttng_domain_type domain_type
;
264 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
265 const char *session_name
, *channel_name
;
266 struct lttng_buffer_view names_view
;
268 if (src_view
->size
< sizeof(*condition_comm
)) {
269 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
274 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
275 names_view
= lttng_buffer_view_from_view(src_view
,
276 sizeof(*condition_comm
), -1);
278 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
279 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
280 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
285 if (names_view
.size
<
286 (condition_comm
->session_name_len
+
287 condition_comm
->channel_name_len
)) {
288 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
293 if (condition_comm
->threshold_set_in_bytes
) {
294 status
= lttng_condition_buffer_usage_set_threshold(condition
,
295 condition_comm
->threshold
);
297 status
= lttng_condition_buffer_usage_set_threshold_ratio(
299 fixed_to_double(condition_comm
->threshold
));
301 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
302 ERR("Failed to initialize buffer usage condition threshold");
307 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
308 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
309 /* Invalid domain value. */
310 ERR("Invalid domain type value (%i) found in condition buffer",
311 (int) condition_comm
->domain_type
);
316 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
317 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
319 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
320 ERR("Failed to set buffer usage condition domain");
325 session_name
= names_view
.data
;
326 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
327 ERR("Malformed session name encountered in condition buffer");
332 channel_name
= session_name
+ condition_comm
->session_name_len
;
333 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
334 ERR("Malformed channel name encountered in condition buffer");
339 status
= lttng_condition_buffer_usage_set_session_name(condition
,
341 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
342 ERR("Failed to set buffer usage session name");
347 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
349 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
350 ERR("Failed to set buffer usage channel name");
355 if (!lttng_condition_validate(condition
)) {
360 condition_size
= sizeof(*condition_comm
) +
361 (ssize_t
) condition_comm
->session_name_len
+
362 (ssize_t
) condition_comm
->channel_name_len
;
363 ret
= condition_size
;
369 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
370 const struct lttng_buffer_view
*view
,
371 struct lttng_condition
**_condition
)
374 struct lttng_condition
*condition
=
375 lttng_condition_buffer_usage_low_create();
377 if (!_condition
|| !condition
) {
382 ret
= init_condition_from_buffer(condition
, view
);
387 *_condition
= condition
;
390 lttng_condition_destroy(condition
);
395 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
396 const struct lttng_buffer_view
*view
,
397 struct lttng_condition
**_condition
)
400 struct lttng_condition
*condition
=
401 lttng_condition_buffer_usage_high_create();
403 if (!_condition
|| !condition
) {
408 ret
= init_condition_from_buffer(condition
, view
);
413 *_condition
= condition
;
416 lttng_condition_destroy(condition
);
421 struct lttng_evaluation
*create_evaluation_from_buffer(
422 enum lttng_condition_type type
,
423 const struct lttng_buffer_view
*view
)
425 const struct lttng_evaluation_buffer_usage_comm
*comm
=
426 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
427 struct lttng_evaluation
*evaluation
= NULL
;
429 if (view
->size
< sizeof(*comm
)) {
433 evaluation
= lttng_evaluation_buffer_usage_create(type
,
434 comm
->buffer_use
, comm
->buffer_capacity
);
440 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
441 const struct lttng_buffer_view
*view
,
442 struct lttng_evaluation
**_evaluation
)
445 struct lttng_evaluation
*evaluation
= NULL
;
452 evaluation
= create_evaluation_from_buffer(
453 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
459 *_evaluation
= evaluation
;
460 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
463 lttng_evaluation_destroy(evaluation
);
468 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
469 const struct lttng_buffer_view
*view
,
470 struct lttng_evaluation
**_evaluation
)
473 struct lttng_evaluation
*evaluation
= NULL
;
480 evaluation
= create_evaluation_from_buffer(
481 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
487 *_evaluation
= evaluation
;
488 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
491 lttng_evaluation_destroy(evaluation
);
495 enum lttng_condition_status
496 lttng_condition_buffer_usage_get_threshold_ratio(
497 const struct lttng_condition
*condition
,
498 double *threshold_ratio
)
500 struct lttng_condition_buffer_usage
*usage
;
501 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
503 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
505 status
= LTTNG_CONDITION_STATUS_INVALID
;
509 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
511 if (!usage
->threshold_ratio
.set
) {
512 status
= LTTNG_CONDITION_STATUS_UNSET
;
515 *threshold_ratio
= usage
->threshold_ratio
.value
;
520 /* threshold_ratio expressed as [0.0, 1.0]. */
521 enum lttng_condition_status
522 lttng_condition_buffer_usage_set_threshold_ratio(
523 struct lttng_condition
*condition
, double threshold_ratio
)
525 struct lttng_condition_buffer_usage
*usage
;
526 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
528 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
529 threshold_ratio
< 0.0 ||
530 threshold_ratio
> 1.0) {
531 status
= LTTNG_CONDITION_STATUS_INVALID
;
535 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
537 usage
->threshold_ratio
.set
= true;
538 usage
->threshold_bytes
.set
= false;
539 usage
->threshold_ratio
.value
= threshold_ratio
;
544 enum lttng_condition_status
545 lttng_condition_buffer_usage_get_threshold(
546 const struct lttng_condition
*condition
,
547 uint64_t *threshold_bytes
)
549 struct lttng_condition_buffer_usage
*usage
;
550 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
552 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
553 status
= LTTNG_CONDITION_STATUS_INVALID
;
557 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
559 if (!usage
->threshold_bytes
.set
) {
560 status
= LTTNG_CONDITION_STATUS_UNSET
;
563 *threshold_bytes
= usage
->threshold_bytes
.value
;
568 enum lttng_condition_status
569 lttng_condition_buffer_usage_set_threshold(
570 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
572 struct lttng_condition_buffer_usage
*usage
;
573 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
575 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
576 status
= LTTNG_CONDITION_STATUS_INVALID
;
580 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
582 usage
->threshold_ratio
.set
= false;
583 usage
->threshold_bytes
.set
= true;
584 usage
->threshold_bytes
.value
= threshold_bytes
;
589 enum lttng_condition_status
590 lttng_condition_buffer_usage_get_session_name(
591 const struct lttng_condition
*condition
,
592 const char **session_name
)
594 struct lttng_condition_buffer_usage
*usage
;
595 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
597 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
598 status
= LTTNG_CONDITION_STATUS_INVALID
;
602 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
604 if (!usage
->session_name
) {
605 status
= LTTNG_CONDITION_STATUS_UNSET
;
608 *session_name
= usage
->session_name
;
613 enum lttng_condition_status
614 lttng_condition_buffer_usage_set_session_name(
615 struct lttng_condition
*condition
, const char *session_name
)
617 char *session_name_copy
;
618 struct lttng_condition_buffer_usage
*usage
;
619 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
621 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
622 strlen(session_name
) == 0) {
623 status
= LTTNG_CONDITION_STATUS_INVALID
;
627 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
629 session_name_copy
= strdup(session_name
);
630 if (!session_name_copy
) {
631 status
= LTTNG_CONDITION_STATUS_ERROR
;
635 if (usage
->session_name
) {
636 free(usage
->session_name
);
638 usage
->session_name
= session_name_copy
;
643 enum lttng_condition_status
644 lttng_condition_buffer_usage_get_channel_name(
645 const struct lttng_condition
*condition
,
646 const char **channel_name
)
648 struct lttng_condition_buffer_usage
*usage
;
649 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
651 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
652 status
= LTTNG_CONDITION_STATUS_INVALID
;
656 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
658 if (!usage
->channel_name
) {
659 status
= LTTNG_CONDITION_STATUS_UNSET
;
662 *channel_name
= usage
->channel_name
;
667 enum lttng_condition_status
668 lttng_condition_buffer_usage_set_channel_name(
669 struct lttng_condition
*condition
, const char *channel_name
)
671 char *channel_name_copy
;
672 struct lttng_condition_buffer_usage
*usage
;
673 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
675 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
676 strlen(channel_name
) == 0) {
677 status
= LTTNG_CONDITION_STATUS_INVALID
;
681 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
683 channel_name_copy
= strdup(channel_name
);
684 if (!channel_name_copy
) {
685 status
= LTTNG_CONDITION_STATUS_ERROR
;
689 if (usage
->channel_name
) {
690 free(usage
->channel_name
);
692 usage
->channel_name
= channel_name_copy
;
697 enum lttng_condition_status
698 lttng_condition_buffer_usage_get_domain_type(
699 const struct lttng_condition
*condition
,
700 enum lttng_domain_type
*type
)
702 struct lttng_condition_buffer_usage
*usage
;
703 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
705 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
706 status
= LTTNG_CONDITION_STATUS_INVALID
;
710 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
712 if (!usage
->domain
.set
) {
713 status
= LTTNG_CONDITION_STATUS_UNSET
;
716 *type
= usage
->domain
.type
;
721 enum lttng_condition_status
722 lttng_condition_buffer_usage_set_domain_type(
723 struct lttng_condition
*condition
, enum lttng_domain_type type
)
725 struct lttng_condition_buffer_usage
*usage
;
726 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
728 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
729 type
== LTTNG_DOMAIN_NONE
) {
730 status
= LTTNG_CONDITION_STATUS_INVALID
;
734 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
736 usage
->domain
.set
= true;
737 usage
->domain
.type
= type
;
743 ssize_t
lttng_evaluation_buffer_usage_serialize(
744 struct lttng_evaluation
*evaluation
, char *buf
)
747 struct lttng_evaluation_buffer_usage
*usage
;
749 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
752 struct lttng_evaluation_buffer_usage_comm comm
= {
753 .buffer_use
= usage
->buffer_use
,
754 .buffer_capacity
= usage
->buffer_capacity
,
757 memcpy(buf
, &comm
, sizeof(comm
));
760 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
765 void lttng_evaluation_buffer_usage_destroy(
766 struct lttng_evaluation
*evaluation
)
768 struct lttng_evaluation_buffer_usage
*usage
;
770 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
776 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
777 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
779 struct lttng_evaluation_buffer_usage
*usage
;
781 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
786 usage
->parent
.type
= type
;
787 usage
->buffer_use
= use
;
788 usage
->buffer_capacity
= capacity
;
789 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
790 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
792 return &usage
->parent
;
796 * Get the sampled buffer usage which caused the associated condition to
797 * evaluate to "true".
799 enum lttng_evaluation_status
800 lttng_evaluation_buffer_usage_get_usage_ratio(
801 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
803 struct lttng_evaluation_buffer_usage
*usage
;
804 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
806 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
807 status
= LTTNG_EVALUATION_STATUS_INVALID
;
811 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
813 *usage_ratio
= (double) usage
->buffer_use
/
814 (double) usage
->buffer_capacity
;
819 enum lttng_evaluation_status
820 lttng_evaluation_buffer_usage_get_usage(
821 const struct lttng_evaluation
*evaluation
,
822 uint64_t *usage_bytes
)
824 struct lttng_evaluation_buffer_usage
*usage
;
825 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
827 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
828 status
= LTTNG_EVALUATION_STATUS_INVALID
;
832 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
834 *usage_bytes
= usage
->buffer_use
;