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
;
243 return &condition
->parent
;
246 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
248 return lttng_condition_buffer_usage_create(
249 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
252 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
254 return lttng_condition_buffer_usage_create(
255 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
259 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
260 const struct lttng_buffer_view
*src_view
)
262 ssize_t ret
, condition_size
;
263 enum lttng_condition_status status
;
264 enum lttng_domain_type domain_type
;
265 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
266 const char *session_name
, *channel_name
;
267 struct lttng_buffer_view names_view
;
269 if (src_view
->size
< sizeof(*condition_comm
)) {
270 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
275 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
276 names_view
= lttng_buffer_view_from_view(src_view
,
277 sizeof(*condition_comm
), -1);
279 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
280 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
281 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
286 if (names_view
.size
<
287 (condition_comm
->session_name_len
+
288 condition_comm
->channel_name_len
)) {
289 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
294 if (condition_comm
->threshold_set_in_bytes
) {
295 status
= lttng_condition_buffer_usage_set_threshold(condition
,
296 condition_comm
->threshold
);
298 status
= lttng_condition_buffer_usage_set_threshold_ratio(
300 fixed_to_double(condition_comm
->threshold
));
302 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
303 ERR("Failed to initialize buffer usage condition threshold");
308 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
309 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
310 /* Invalid domain value. */
311 ERR("Invalid domain type value (%i) found in condition buffer",
312 (int) condition_comm
->domain_type
);
317 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
318 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
320 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
321 ERR("Failed to set buffer usage condition domain");
326 session_name
= names_view
.data
;
327 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
328 ERR("Malformed session name encountered in condition buffer");
333 channel_name
= session_name
+ condition_comm
->session_name_len
;
334 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
335 ERR("Malformed channel name encountered in condition buffer");
340 status
= lttng_condition_buffer_usage_set_session_name(condition
,
342 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
343 ERR("Failed to set buffer usage session name");
348 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
350 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
351 ERR("Failed to set buffer usage channel name");
356 if (!lttng_condition_validate(condition
)) {
361 condition_size
= sizeof(*condition_comm
) +
362 (ssize_t
) condition_comm
->session_name_len
+
363 (ssize_t
) condition_comm
->channel_name_len
;
364 ret
= condition_size
;
370 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
371 const struct lttng_buffer_view
*view
,
372 struct lttng_condition
**_condition
)
375 struct lttng_condition
*condition
=
376 lttng_condition_buffer_usage_low_create();
378 if (!_condition
|| !condition
) {
383 ret
= init_condition_from_buffer(condition
, view
);
388 *_condition
= condition
;
391 lttng_condition_destroy(condition
);
396 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
397 const struct lttng_buffer_view
*view
,
398 struct lttng_condition
**_condition
)
401 struct lttng_condition
*condition
=
402 lttng_condition_buffer_usage_high_create();
404 if (!_condition
|| !condition
) {
409 ret
= init_condition_from_buffer(condition
, view
);
414 *_condition
= condition
;
417 lttng_condition_destroy(condition
);
422 struct lttng_evaluation
*create_evaluation_from_buffer(
423 enum lttng_condition_type type
,
424 const struct lttng_buffer_view
*view
)
426 const struct lttng_evaluation_buffer_usage_comm
*comm
=
427 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
428 struct lttng_evaluation
*evaluation
= NULL
;
430 if (view
->size
< sizeof(*comm
)) {
434 evaluation
= lttng_evaluation_buffer_usage_create(type
,
435 comm
->buffer_use
, comm
->buffer_capacity
);
441 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
442 const struct lttng_buffer_view
*view
,
443 struct lttng_evaluation
**_evaluation
)
446 struct lttng_evaluation
*evaluation
= NULL
;
453 evaluation
= create_evaluation_from_buffer(
454 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
460 *_evaluation
= evaluation
;
461 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
464 lttng_evaluation_destroy(evaluation
);
469 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
470 const struct lttng_buffer_view
*view
,
471 struct lttng_evaluation
**_evaluation
)
474 struct lttng_evaluation
*evaluation
= NULL
;
481 evaluation
= create_evaluation_from_buffer(
482 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
488 *_evaluation
= evaluation
;
489 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
492 lttng_evaluation_destroy(evaluation
);
496 enum lttng_condition_status
497 lttng_condition_buffer_usage_get_threshold_ratio(
498 const struct lttng_condition
*condition
,
499 double *threshold_ratio
)
501 struct lttng_condition_buffer_usage
*usage
;
502 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
504 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
506 status
= LTTNG_CONDITION_STATUS_INVALID
;
510 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
512 if (!usage
->threshold_ratio
.set
) {
513 status
= LTTNG_CONDITION_STATUS_UNSET
;
516 *threshold_ratio
= usage
->threshold_ratio
.value
;
521 /* threshold_ratio expressed as [0.0, 1.0]. */
522 enum lttng_condition_status
523 lttng_condition_buffer_usage_set_threshold_ratio(
524 struct lttng_condition
*condition
, double threshold_ratio
)
526 struct lttng_condition_buffer_usage
*usage
;
527 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
529 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
530 threshold_ratio
< 0.0 ||
531 threshold_ratio
> 1.0) {
532 status
= LTTNG_CONDITION_STATUS_INVALID
;
536 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
538 usage
->threshold_ratio
.set
= true;
539 usage
->threshold_bytes
.set
= false;
540 usage
->threshold_ratio
.value
= threshold_ratio
;
545 enum lttng_condition_status
546 lttng_condition_buffer_usage_get_threshold(
547 const struct lttng_condition
*condition
,
548 uint64_t *threshold_bytes
)
550 struct lttng_condition_buffer_usage
*usage
;
551 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
553 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
554 status
= LTTNG_CONDITION_STATUS_INVALID
;
558 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
560 if (!usage
->threshold_bytes
.set
) {
561 status
= LTTNG_CONDITION_STATUS_UNSET
;
564 *threshold_bytes
= usage
->threshold_bytes
.value
;
569 enum lttng_condition_status
570 lttng_condition_buffer_usage_set_threshold(
571 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
573 struct lttng_condition_buffer_usage
*usage
;
574 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
576 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
577 status
= LTTNG_CONDITION_STATUS_INVALID
;
581 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
583 usage
->threshold_ratio
.set
= false;
584 usage
->threshold_bytes
.set
= true;
585 usage
->threshold_bytes
.value
= threshold_bytes
;
590 enum lttng_condition_status
591 lttng_condition_buffer_usage_get_session_name(
592 const struct lttng_condition
*condition
,
593 const char **session_name
)
595 struct lttng_condition_buffer_usage
*usage
;
596 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
598 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
599 status
= LTTNG_CONDITION_STATUS_INVALID
;
603 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
605 if (!usage
->session_name
) {
606 status
= LTTNG_CONDITION_STATUS_UNSET
;
609 *session_name
= usage
->session_name
;
614 enum lttng_condition_status
615 lttng_condition_buffer_usage_set_session_name(
616 struct lttng_condition
*condition
, const char *session_name
)
618 char *session_name_copy
;
619 struct lttng_condition_buffer_usage
*usage
;
620 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
622 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
623 strlen(session_name
) == 0) {
624 status
= LTTNG_CONDITION_STATUS_INVALID
;
628 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
630 session_name_copy
= strdup(session_name
);
631 if (!session_name_copy
) {
632 status
= LTTNG_CONDITION_STATUS_ERROR
;
636 if (usage
->session_name
) {
637 free(usage
->session_name
);
639 usage
->session_name
= session_name_copy
;
644 enum lttng_condition_status
645 lttng_condition_buffer_usage_get_channel_name(
646 const struct lttng_condition
*condition
,
647 const char **channel_name
)
649 struct lttng_condition_buffer_usage
*usage
;
650 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
652 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
653 status
= LTTNG_CONDITION_STATUS_INVALID
;
657 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
659 if (!usage
->channel_name
) {
660 status
= LTTNG_CONDITION_STATUS_UNSET
;
663 *channel_name
= usage
->channel_name
;
668 enum lttng_condition_status
669 lttng_condition_buffer_usage_set_channel_name(
670 struct lttng_condition
*condition
, const char *channel_name
)
672 char *channel_name_copy
;
673 struct lttng_condition_buffer_usage
*usage
;
674 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
676 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
677 strlen(channel_name
) == 0) {
678 status
= LTTNG_CONDITION_STATUS_INVALID
;
682 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
684 channel_name_copy
= strdup(channel_name
);
685 if (!channel_name_copy
) {
686 status
= LTTNG_CONDITION_STATUS_ERROR
;
690 if (usage
->channel_name
) {
691 free(usage
->channel_name
);
693 usage
->channel_name
= channel_name_copy
;
698 enum lttng_condition_status
699 lttng_condition_buffer_usage_get_domain_type(
700 const struct lttng_condition
*condition
,
701 enum lttng_domain_type
*type
)
703 struct lttng_condition_buffer_usage
*usage
;
704 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
706 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
707 status
= LTTNG_CONDITION_STATUS_INVALID
;
711 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
713 if (!usage
->domain
.set
) {
714 status
= LTTNG_CONDITION_STATUS_UNSET
;
717 *type
= usage
->domain
.type
;
722 enum lttng_condition_status
723 lttng_condition_buffer_usage_set_domain_type(
724 struct lttng_condition
*condition
, enum lttng_domain_type type
)
726 struct lttng_condition_buffer_usage
*usage
;
727 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
729 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
730 type
== LTTNG_DOMAIN_NONE
) {
731 status
= LTTNG_CONDITION_STATUS_INVALID
;
735 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
737 usage
->domain
.set
= true;
738 usage
->domain
.type
= type
;
744 ssize_t
lttng_evaluation_buffer_usage_serialize(
745 struct lttng_evaluation
*evaluation
, char *buf
)
748 struct lttng_evaluation_buffer_usage
*usage
;
750 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
753 struct lttng_evaluation_buffer_usage_comm comm
= {
754 .buffer_use
= usage
->buffer_use
,
755 .buffer_capacity
= usage
->buffer_capacity
,
758 memcpy(buf
, &comm
, sizeof(comm
));
761 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
766 void lttng_evaluation_buffer_usage_destroy(
767 struct lttng_evaluation
*evaluation
)
769 struct lttng_evaluation_buffer_usage
*usage
;
771 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
777 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
778 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
780 struct lttng_evaluation_buffer_usage
*usage
;
782 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
787 usage
->parent
.type
= type
;
788 usage
->buffer_use
= use
;
789 usage
->buffer_capacity
= capacity
;
790 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
791 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
793 return &usage
->parent
;
797 * Get the sampled buffer usage which caused the associated condition to
798 * evaluate to "true".
800 enum lttng_evaluation_status
801 lttng_evaluation_buffer_usage_get_usage_ratio(
802 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
804 struct lttng_evaluation_buffer_usage
*usage
;
805 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
807 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
808 status
= LTTNG_EVALUATION_STATUS_INVALID
;
812 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
814 *usage_ratio
= (double) usage
->buffer_use
/
815 (double) usage
->buffer_capacity
;
820 enum lttng_evaluation_status
821 lttng_evaluation_buffer_usage_get_usage(
822 const struct lttng_evaluation
*evaluation
,
823 uint64_t *usage_bytes
)
825 struct lttng_evaluation_buffer_usage
*usage
;
826 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
828 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
829 status
= LTTNG_EVALUATION_STATUS_INVALID
;
833 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
835 *usage_bytes
= usage
->buffer_use
;