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 int lttng_condition_buffer_usage_serialize(
99 const struct lttng_condition
*condition
,
100 struct lttng_dynamic_buffer
*buf
)
103 struct lttng_condition_buffer_usage
*usage
;
104 size_t session_name_len
, channel_name_len
;
105 struct lttng_condition_buffer_usage_comm usage_comm
;
107 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
112 DBG("Serializing buffer usage condition");
113 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
116 session_name_len
= strlen(usage
->session_name
) + 1;
117 channel_name_len
= strlen(usage
->channel_name
) + 1;
118 if (session_name_len
> LTTNG_NAME_MAX
||
119 channel_name_len
> LTTNG_NAME_MAX
) {
124 usage_comm
.threshold_set_in_bytes
= !!usage
->threshold_bytes
.set
;
125 usage_comm
.session_name_len
= session_name_len
;
126 usage_comm
.channel_name_len
= channel_name_len
;
127 usage_comm
.domain_type
= (int8_t) usage
->domain
.type
;
129 if (usage
->threshold_bytes
.set
) {
130 usage_comm
.threshold
= usage
->threshold_bytes
.value
;
132 uint64_t val
= double_to_fixed(
133 usage
->threshold_ratio
.value
);
135 if (val
> UINT32_MAX
) {
140 usage_comm
.threshold
= val
;
143 ret
= lttng_dynamic_buffer_append(buf
, &usage_comm
,
148 ret
= lttng_dynamic_buffer_append(buf
, usage
->session_name
,
153 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 if ((a
->session_name
&& !b
->session_name
) ||
198 (!a
->session_name
&& b
->session_name
)) {
202 if (a
->channel_name
&& b
->channel_name
) {
203 if (strcmp(a
->channel_name
, b
->channel_name
)) {
206 } if ((a
->channel_name
&& !b
->channel_name
) ||
207 (!a
->channel_name
&& b
->channel_name
)) {
211 if (a
->channel_name
&& b
->channel_name
) {
212 if (strcmp(a
->channel_name
, b
->channel_name
)) {
217 if ((a
->domain
.set
&& !b
->domain
.set
) ||
218 (!a
->domain
.set
&& b
->domain
.set
)) {
222 if (a
->domain
.set
&& b
->domain
.set
) {
223 if (a
->domain
.type
!= b
->domain
.type
) {
233 struct lttng_condition
*lttng_condition_buffer_usage_create(
234 enum lttng_condition_type type
)
236 struct lttng_condition_buffer_usage
*condition
;
238 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
243 lttng_condition_init(&condition
->parent
, type
);
244 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
245 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
246 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
247 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
248 return &condition
->parent
;
251 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
253 return lttng_condition_buffer_usage_create(
254 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
257 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
259 return lttng_condition_buffer_usage_create(
260 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
264 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
265 const struct lttng_buffer_view
*src_view
)
267 ssize_t ret
, condition_size
;
268 enum lttng_condition_status status
;
269 enum lttng_domain_type domain_type
;
270 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
271 const char *session_name
, *channel_name
;
272 struct lttng_buffer_view names_view
;
274 if (src_view
->size
< sizeof(*condition_comm
)) {
275 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
280 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
281 names_view
= lttng_buffer_view_from_view(src_view
,
282 sizeof(*condition_comm
), -1);
284 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
285 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
286 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
291 if (names_view
.size
<
292 (condition_comm
->session_name_len
+
293 condition_comm
->channel_name_len
)) {
294 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
299 if (condition_comm
->threshold_set_in_bytes
) {
300 status
= lttng_condition_buffer_usage_set_threshold(condition
,
301 condition_comm
->threshold
);
303 status
= lttng_condition_buffer_usage_set_threshold_ratio(
305 fixed_to_double(condition_comm
->threshold
));
307 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
308 ERR("Failed to initialize buffer usage condition threshold");
313 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
314 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
315 /* Invalid domain value. */
316 ERR("Invalid domain type value (%i) found in condition buffer",
317 (int) condition_comm
->domain_type
);
322 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
323 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
325 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
326 ERR("Failed to set buffer usage condition domain");
331 session_name
= names_view
.data
;
332 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
333 ERR("Malformed session name encountered in condition buffer");
338 channel_name
= session_name
+ condition_comm
->session_name_len
;
339 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
340 ERR("Malformed channel name encountered in condition buffer");
345 status
= lttng_condition_buffer_usage_set_session_name(condition
,
347 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
348 ERR("Failed to set buffer usage session name");
353 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
355 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
356 ERR("Failed to set buffer usage channel name");
361 if (!lttng_condition_validate(condition
)) {
366 condition_size
= sizeof(*condition_comm
) +
367 (ssize_t
) condition_comm
->session_name_len
+
368 (ssize_t
) condition_comm
->channel_name_len
;
369 ret
= condition_size
;
375 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
376 const struct lttng_buffer_view
*view
,
377 struct lttng_condition
**_condition
)
380 struct lttng_condition
*condition
=
381 lttng_condition_buffer_usage_low_create();
383 if (!_condition
|| !condition
) {
388 ret
= init_condition_from_buffer(condition
, view
);
393 *_condition
= condition
;
396 lttng_condition_destroy(condition
);
401 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
402 const struct lttng_buffer_view
*view
,
403 struct lttng_condition
**_condition
)
406 struct lttng_condition
*condition
=
407 lttng_condition_buffer_usage_high_create();
409 if (!_condition
|| !condition
) {
414 ret
= init_condition_from_buffer(condition
, view
);
419 *_condition
= condition
;
422 lttng_condition_destroy(condition
);
427 struct lttng_evaluation
*create_evaluation_from_buffer(
428 enum lttng_condition_type type
,
429 const struct lttng_buffer_view
*view
)
431 const struct lttng_evaluation_buffer_usage_comm
*comm
=
432 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
433 struct lttng_evaluation
*evaluation
= NULL
;
435 if (view
->size
< sizeof(*comm
)) {
439 evaluation
= lttng_evaluation_buffer_usage_create(type
,
440 comm
->buffer_use
, comm
->buffer_capacity
);
446 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
447 const struct lttng_buffer_view
*view
,
448 struct lttng_evaluation
**_evaluation
)
451 struct lttng_evaluation
*evaluation
= NULL
;
458 evaluation
= create_evaluation_from_buffer(
459 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
465 *_evaluation
= evaluation
;
466 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
469 lttng_evaluation_destroy(evaluation
);
474 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
475 const struct lttng_buffer_view
*view
,
476 struct lttng_evaluation
**_evaluation
)
479 struct lttng_evaluation
*evaluation
= NULL
;
486 evaluation
= create_evaluation_from_buffer(
487 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
493 *_evaluation
= evaluation
;
494 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
497 lttng_evaluation_destroy(evaluation
);
501 enum lttng_condition_status
502 lttng_condition_buffer_usage_get_threshold_ratio(
503 const struct lttng_condition
*condition
,
504 double *threshold_ratio
)
506 struct lttng_condition_buffer_usage
*usage
;
507 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
509 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
511 status
= LTTNG_CONDITION_STATUS_INVALID
;
515 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
517 if (!usage
->threshold_ratio
.set
) {
518 status
= LTTNG_CONDITION_STATUS_UNSET
;
521 *threshold_ratio
= usage
->threshold_ratio
.value
;
526 /* threshold_ratio expressed as [0.0, 1.0]. */
527 enum lttng_condition_status
528 lttng_condition_buffer_usage_set_threshold_ratio(
529 struct lttng_condition
*condition
, double threshold_ratio
)
531 struct lttng_condition_buffer_usage
*usage
;
532 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
534 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
535 threshold_ratio
< 0.0 ||
536 threshold_ratio
> 1.0) {
537 status
= LTTNG_CONDITION_STATUS_INVALID
;
541 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
543 usage
->threshold_ratio
.set
= true;
544 usage
->threshold_bytes
.set
= false;
545 usage
->threshold_ratio
.value
= threshold_ratio
;
550 enum lttng_condition_status
551 lttng_condition_buffer_usage_get_threshold(
552 const struct lttng_condition
*condition
,
553 uint64_t *threshold_bytes
)
555 struct lttng_condition_buffer_usage
*usage
;
556 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
558 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
559 status
= LTTNG_CONDITION_STATUS_INVALID
;
563 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
565 if (!usage
->threshold_bytes
.set
) {
566 status
= LTTNG_CONDITION_STATUS_UNSET
;
569 *threshold_bytes
= usage
->threshold_bytes
.value
;
574 enum lttng_condition_status
575 lttng_condition_buffer_usage_set_threshold(
576 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
578 struct lttng_condition_buffer_usage
*usage
;
579 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
581 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
582 status
= LTTNG_CONDITION_STATUS_INVALID
;
586 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
588 usage
->threshold_ratio
.set
= false;
589 usage
->threshold_bytes
.set
= true;
590 usage
->threshold_bytes
.value
= threshold_bytes
;
595 enum lttng_condition_status
596 lttng_condition_buffer_usage_get_session_name(
597 const struct lttng_condition
*condition
,
598 const char **session_name
)
600 struct lttng_condition_buffer_usage
*usage
;
601 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
603 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
604 status
= LTTNG_CONDITION_STATUS_INVALID
;
608 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
610 if (!usage
->session_name
) {
611 status
= LTTNG_CONDITION_STATUS_UNSET
;
614 *session_name
= usage
->session_name
;
619 enum lttng_condition_status
620 lttng_condition_buffer_usage_set_session_name(
621 struct lttng_condition
*condition
, const char *session_name
)
623 char *session_name_copy
;
624 struct lttng_condition_buffer_usage
*usage
;
625 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
627 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
628 strlen(session_name
) == 0) {
629 status
= LTTNG_CONDITION_STATUS_INVALID
;
633 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
635 session_name_copy
= strdup(session_name
);
636 if (!session_name_copy
) {
637 status
= LTTNG_CONDITION_STATUS_ERROR
;
641 if (usage
->session_name
) {
642 free(usage
->session_name
);
644 usage
->session_name
= session_name_copy
;
649 enum lttng_condition_status
650 lttng_condition_buffer_usage_get_channel_name(
651 const struct lttng_condition
*condition
,
652 const char **channel_name
)
654 struct lttng_condition_buffer_usage
*usage
;
655 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
657 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
658 status
= LTTNG_CONDITION_STATUS_INVALID
;
662 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
664 if (!usage
->channel_name
) {
665 status
= LTTNG_CONDITION_STATUS_UNSET
;
668 *channel_name
= usage
->channel_name
;
673 enum lttng_condition_status
674 lttng_condition_buffer_usage_set_channel_name(
675 struct lttng_condition
*condition
, const char *channel_name
)
677 char *channel_name_copy
;
678 struct lttng_condition_buffer_usage
*usage
;
679 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
681 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
682 strlen(channel_name
) == 0) {
683 status
= LTTNG_CONDITION_STATUS_INVALID
;
687 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
689 channel_name_copy
= strdup(channel_name
);
690 if (!channel_name_copy
) {
691 status
= LTTNG_CONDITION_STATUS_ERROR
;
695 if (usage
->channel_name
) {
696 free(usage
->channel_name
);
698 usage
->channel_name
= channel_name_copy
;
703 enum lttng_condition_status
704 lttng_condition_buffer_usage_get_domain_type(
705 const struct lttng_condition
*condition
,
706 enum lttng_domain_type
*type
)
708 struct lttng_condition_buffer_usage
*usage
;
709 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
711 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
712 status
= LTTNG_CONDITION_STATUS_INVALID
;
716 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
718 if (!usage
->domain
.set
) {
719 status
= LTTNG_CONDITION_STATUS_UNSET
;
722 *type
= usage
->domain
.type
;
727 enum lttng_condition_status
728 lttng_condition_buffer_usage_set_domain_type(
729 struct lttng_condition
*condition
, enum lttng_domain_type type
)
731 struct lttng_condition_buffer_usage
*usage
;
732 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
734 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
735 type
== LTTNG_DOMAIN_NONE
) {
736 status
= LTTNG_CONDITION_STATUS_INVALID
;
740 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
742 usage
->domain
.set
= true;
743 usage
->domain
.type
= type
;
749 int lttng_evaluation_buffer_usage_serialize(
750 struct lttng_evaluation
*evaluation
,
751 struct lttng_dynamic_buffer
*buf
)
753 struct lttng_evaluation_buffer_usage
*usage
;
754 struct lttng_evaluation_buffer_usage_comm comm
;
756 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
758 comm
.buffer_use
= usage
->buffer_use
;
759 comm
.buffer_capacity
= usage
->buffer_capacity
;
761 return lttng_dynamic_buffer_append(buf
, &comm
, sizeof(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
;