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
);
156 bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition
*_a
,
157 const struct lttng_condition
*_b
)
159 bool is_equal
= false;
160 struct lttng_condition_buffer_usage
*a
, *b
;
162 a
= container_of(_a
, struct lttng_condition_buffer_usage
, parent
);
163 b
= container_of(_b
, struct lttng_condition_buffer_usage
, parent
);
165 if ((a
->threshold_ratio
.set
&& !b
->threshold_ratio
.set
) ||
166 (a
->threshold_bytes
.set
&& !b
->threshold_bytes
.set
)) {
170 if (a
->threshold_ratio
.set
&& b
->threshold_ratio
.set
) {
171 double a_value
, b_value
, diff
;
173 a_value
= a
->threshold_ratio
.value
;
174 b_value
= b
->threshold_ratio
.value
;
175 diff
= fabs(a_value
- b_value
);
177 if (diff
> DBL_EPSILON
) {
180 } else if (a
->threshold_bytes
.set
&& b
->threshold_bytes
.set
) {
181 uint64_t a_value
, b_value
;
183 a_value
= a
->threshold_bytes
.value
;
184 b_value
= b
->threshold_bytes
.value
;
185 if (a_value
!= b_value
) {
190 if ((a
->session_name
&& !b
->session_name
) ||
191 (!a
->session_name
&& b
->session_name
)) {
195 if (a
->channel_name
&& b
->channel_name
) {
196 if (strcmp(a
->channel_name
, b
->channel_name
)) {
199 } if ((a
->channel_name
&& !b
->channel_name
) ||
200 (!a
->channel_name
&& b
->channel_name
)) {
204 if (a
->channel_name
&& b
->channel_name
) {
205 if (strcmp(a
->channel_name
, b
->channel_name
)) {
210 if ((a
->domain
.set
&& !b
->domain
.set
) ||
211 (!a
->domain
.set
&& b
->domain
.set
)) {
215 if (a
->domain
.set
&& b
->domain
.set
) {
216 if (a
->domain
.type
!= b
->domain
.type
) {
226 struct lttng_condition
*lttng_condition_buffer_usage_create(
227 enum lttng_condition_type type
)
229 struct lttng_condition_buffer_usage
*condition
;
231 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
236 lttng_condition_init(&condition
->parent
, type
);
237 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
238 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
239 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
240 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
241 return &condition
->parent
;
244 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
246 return lttng_condition_buffer_usage_create(
247 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
250 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
252 return lttng_condition_buffer_usage_create(
253 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
257 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
258 const struct lttng_buffer_view
*src_view
)
260 ssize_t ret
, condition_size
;
261 enum lttng_condition_status status
;
262 enum lttng_domain_type domain_type
;
263 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
264 const char *session_name
, *channel_name
;
265 struct lttng_buffer_view names_view
;
267 if (src_view
->size
< sizeof(*condition_comm
)) {
268 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
273 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
274 names_view
= lttng_buffer_view_from_view(src_view
,
275 sizeof(*condition_comm
), -1);
277 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
278 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
279 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
284 if (names_view
.size
<
285 (condition_comm
->session_name_len
+
286 condition_comm
->channel_name_len
)) {
287 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
292 if (condition_comm
->threshold_set_in_bytes
) {
293 status
= lttng_condition_buffer_usage_set_threshold(condition
,
294 condition_comm
->threshold
);
296 status
= lttng_condition_buffer_usage_set_threshold_ratio(
298 fixed_to_double(condition_comm
->threshold
));
300 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
301 ERR("Failed to initialize buffer usage condition threshold");
306 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
307 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
308 /* Invalid domain value. */
309 ERR("Invalid domain type value (%i) found in condition buffer",
310 (int) condition_comm
->domain_type
);
315 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
316 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
318 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
319 ERR("Failed to set buffer usage condition domain");
324 session_name
= names_view
.data
;
325 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
326 ERR("Malformed session name encountered in condition buffer");
331 channel_name
= session_name
+ condition_comm
->session_name_len
;
332 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
333 ERR("Malformed channel name encountered in condition buffer");
338 status
= lttng_condition_buffer_usage_set_session_name(condition
,
340 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
341 ERR("Failed to set buffer usage session name");
346 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
348 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
349 ERR("Failed to set buffer usage channel name");
354 if (!lttng_condition_validate(condition
)) {
359 condition_size
= sizeof(*condition_comm
) +
360 (ssize_t
) condition_comm
->session_name_len
+
361 (ssize_t
) condition_comm
->channel_name_len
;
362 ret
= condition_size
;
368 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
369 const struct lttng_buffer_view
*view
,
370 struct lttng_condition
**_condition
)
373 struct lttng_condition
*condition
=
374 lttng_condition_buffer_usage_low_create();
376 if (!_condition
|| !condition
) {
381 ret
= init_condition_from_buffer(condition
, view
);
386 *_condition
= condition
;
389 lttng_condition_destroy(condition
);
394 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
395 const struct lttng_buffer_view
*view
,
396 struct lttng_condition
**_condition
)
399 struct lttng_condition
*condition
=
400 lttng_condition_buffer_usage_high_create();
402 if (!_condition
|| !condition
) {
407 ret
= init_condition_from_buffer(condition
, view
);
412 *_condition
= condition
;
415 lttng_condition_destroy(condition
);
420 struct lttng_evaluation
*create_evaluation_from_buffer(
421 enum lttng_condition_type type
,
422 const struct lttng_buffer_view
*view
)
424 const struct lttng_evaluation_buffer_usage_comm
*comm
=
425 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
426 struct lttng_evaluation
*evaluation
= NULL
;
428 if (view
->size
< sizeof(*comm
)) {
432 evaluation
= lttng_evaluation_buffer_usage_create(type
,
433 comm
->buffer_use
, comm
->buffer_capacity
);
439 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
440 const struct lttng_buffer_view
*view
,
441 struct lttng_evaluation
**_evaluation
)
444 struct lttng_evaluation
*evaluation
= NULL
;
451 evaluation
= create_evaluation_from_buffer(
452 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
458 *_evaluation
= evaluation
;
459 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
462 lttng_evaluation_destroy(evaluation
);
467 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
468 const struct lttng_buffer_view
*view
,
469 struct lttng_evaluation
**_evaluation
)
472 struct lttng_evaluation
*evaluation
= NULL
;
479 evaluation
= create_evaluation_from_buffer(
480 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
486 *_evaluation
= evaluation
;
487 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
490 lttng_evaluation_destroy(evaluation
);
494 enum lttng_condition_status
495 lttng_condition_buffer_usage_get_threshold_ratio(
496 const struct lttng_condition
*condition
,
497 double *threshold_ratio
)
499 struct lttng_condition_buffer_usage
*usage
;
500 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
502 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
504 status
= LTTNG_CONDITION_STATUS_INVALID
;
508 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
510 if (!usage
->threshold_ratio
.set
) {
511 status
= LTTNG_CONDITION_STATUS_UNSET
;
514 *threshold_ratio
= usage
->threshold_ratio
.value
;
519 /* threshold_ratio expressed as [0.0, 1.0]. */
520 enum lttng_condition_status
521 lttng_condition_buffer_usage_set_threshold_ratio(
522 struct lttng_condition
*condition
, double threshold_ratio
)
524 struct lttng_condition_buffer_usage
*usage
;
525 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
527 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
528 threshold_ratio
< 0.0 ||
529 threshold_ratio
> 1.0) {
530 status
= LTTNG_CONDITION_STATUS_INVALID
;
534 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
536 usage
->threshold_ratio
.set
= true;
537 usage
->threshold_bytes
.set
= false;
538 usage
->threshold_ratio
.value
= threshold_ratio
;
543 enum lttng_condition_status
544 lttng_condition_buffer_usage_get_threshold(
545 const struct lttng_condition
*condition
,
546 uint64_t *threshold_bytes
)
548 struct lttng_condition_buffer_usage
*usage
;
549 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
551 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
552 status
= LTTNG_CONDITION_STATUS_INVALID
;
556 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
558 if (!usage
->threshold_bytes
.set
) {
559 status
= LTTNG_CONDITION_STATUS_UNSET
;
562 *threshold_bytes
= usage
->threshold_bytes
.value
;
567 enum lttng_condition_status
568 lttng_condition_buffer_usage_set_threshold(
569 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
571 struct lttng_condition_buffer_usage
*usage
;
572 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
574 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
575 status
= LTTNG_CONDITION_STATUS_INVALID
;
579 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
581 usage
->threshold_ratio
.set
= false;
582 usage
->threshold_bytes
.set
= true;
583 usage
->threshold_bytes
.value
= threshold_bytes
;
588 enum lttng_condition_status
589 lttng_condition_buffer_usage_get_session_name(
590 const struct lttng_condition
*condition
,
591 const char **session_name
)
593 struct lttng_condition_buffer_usage
*usage
;
594 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
596 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
597 status
= LTTNG_CONDITION_STATUS_INVALID
;
601 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
603 if (!usage
->session_name
) {
604 status
= LTTNG_CONDITION_STATUS_UNSET
;
607 *session_name
= usage
->session_name
;
612 enum lttng_condition_status
613 lttng_condition_buffer_usage_set_session_name(
614 struct lttng_condition
*condition
, const char *session_name
)
616 char *session_name_copy
;
617 struct lttng_condition_buffer_usage
*usage
;
618 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
620 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
621 strlen(session_name
) == 0) {
622 status
= LTTNG_CONDITION_STATUS_INVALID
;
626 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
628 session_name_copy
= strdup(session_name
);
629 if (!session_name_copy
) {
630 status
= LTTNG_CONDITION_STATUS_ERROR
;
634 if (usage
->session_name
) {
635 free(usage
->session_name
);
637 usage
->session_name
= session_name_copy
;
642 enum lttng_condition_status
643 lttng_condition_buffer_usage_get_channel_name(
644 const struct lttng_condition
*condition
,
645 const char **channel_name
)
647 struct lttng_condition_buffer_usage
*usage
;
648 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
650 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
651 status
= LTTNG_CONDITION_STATUS_INVALID
;
655 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
657 if (!usage
->channel_name
) {
658 status
= LTTNG_CONDITION_STATUS_UNSET
;
661 *channel_name
= usage
->channel_name
;
666 enum lttng_condition_status
667 lttng_condition_buffer_usage_set_channel_name(
668 struct lttng_condition
*condition
, const char *channel_name
)
670 char *channel_name_copy
;
671 struct lttng_condition_buffer_usage
*usage
;
672 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
674 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
675 strlen(channel_name
) == 0) {
676 status
= LTTNG_CONDITION_STATUS_INVALID
;
680 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
682 channel_name_copy
= strdup(channel_name
);
683 if (!channel_name_copy
) {
684 status
= LTTNG_CONDITION_STATUS_ERROR
;
688 if (usage
->channel_name
) {
689 free(usage
->channel_name
);
691 usage
->channel_name
= channel_name_copy
;
696 enum lttng_condition_status
697 lttng_condition_buffer_usage_get_domain_type(
698 const struct lttng_condition
*condition
,
699 enum lttng_domain_type
*type
)
701 struct lttng_condition_buffer_usage
*usage
;
702 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
704 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
705 status
= LTTNG_CONDITION_STATUS_INVALID
;
709 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
711 if (!usage
->domain
.set
) {
712 status
= LTTNG_CONDITION_STATUS_UNSET
;
715 *type
= usage
->domain
.type
;
720 enum lttng_condition_status
721 lttng_condition_buffer_usage_set_domain_type(
722 struct lttng_condition
*condition
, enum lttng_domain_type type
)
724 struct lttng_condition_buffer_usage
*usage
;
725 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
727 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
728 type
== LTTNG_DOMAIN_NONE
) {
729 status
= LTTNG_CONDITION_STATUS_INVALID
;
733 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
735 usage
->domain
.set
= true;
736 usage
->domain
.type
= type
;
742 ssize_t
lttng_evaluation_buffer_usage_serialize(
743 struct lttng_evaluation
*evaluation
, char *buf
)
746 struct lttng_evaluation_buffer_usage
*usage
;
748 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
751 struct lttng_evaluation_buffer_usage_comm comm
= {
752 .buffer_use
= usage
->buffer_use
,
753 .buffer_capacity
= usage
->buffer_capacity
,
756 memcpy(buf
, &comm
, sizeof(comm
));
759 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
764 void lttng_evaluation_buffer_usage_destroy(
765 struct lttng_evaluation
*evaluation
)
767 struct lttng_evaluation_buffer_usage
*usage
;
769 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
775 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
776 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
778 struct lttng_evaluation_buffer_usage
*usage
;
780 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
785 usage
->parent
.type
= type
;
786 usage
->buffer_use
= use
;
787 usage
->buffer_capacity
= capacity
;
788 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
789 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
791 return &usage
->parent
;
795 * Get the sampled buffer usage which caused the associated condition to
796 * evaluate to "true".
798 enum lttng_evaluation_status
799 lttng_evaluation_buffer_usage_get_usage_ratio(
800 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
802 struct lttng_evaluation_buffer_usage
*usage
;
803 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
805 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
806 status
= LTTNG_EVALUATION_STATUS_INVALID
;
810 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
812 *usage_ratio
= (double) usage
->buffer_use
/
813 (double) usage
->buffer_capacity
;
818 enum lttng_evaluation_status
819 lttng_evaluation_buffer_usage_get_usage(
820 const struct lttng_evaluation
*evaluation
,
821 uint64_t *usage_bytes
)
823 struct lttng_evaluation_buffer_usage
*usage
;
824 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
826 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
827 status
= LTTNG_EVALUATION_STATUS_INVALID
;
831 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
833 *usage_bytes
= usage
->buffer_use
;