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.");
91 if (!usage
->domain
.set
) {
92 ERR("Invalid buffer usage condition: a domain must be set.");
102 int lttng_condition_buffer_usage_serialize(
103 const struct lttng_condition
*condition
,
104 struct lttng_dynamic_buffer
*buf
)
107 struct lttng_condition_buffer_usage
*usage
;
108 size_t session_name_len
, channel_name_len
;
109 struct lttng_condition_buffer_usage_comm usage_comm
;
111 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
116 DBG("Serializing buffer usage condition");
117 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
120 session_name_len
= strlen(usage
->session_name
) + 1;
121 channel_name_len
= strlen(usage
->channel_name
) + 1;
122 if (session_name_len
> LTTNG_NAME_MAX
||
123 channel_name_len
> LTTNG_NAME_MAX
) {
128 usage_comm
.threshold_set_in_bytes
= !!usage
->threshold_bytes
.set
;
129 usage_comm
.session_name_len
= session_name_len
;
130 usage_comm
.channel_name_len
= channel_name_len
;
131 usage_comm
.domain_type
= (int8_t) usage
->domain
.type
;
133 if (usage
->threshold_bytes
.set
) {
134 usage_comm
.threshold
= usage
->threshold_bytes
.value
;
136 uint64_t val
= double_to_fixed(
137 usage
->threshold_ratio
.value
);
139 if (val
> UINT32_MAX
) {
144 usage_comm
.threshold
= val
;
147 ret
= lttng_dynamic_buffer_append(buf
, &usage_comm
,
152 ret
= lttng_dynamic_buffer_append(buf
, usage
->session_name
,
157 ret
= lttng_dynamic_buffer_append(buf
, usage
->channel_name
,
167 bool lttng_condition_buffer_usage_is_equal(const struct lttng_condition
*_a
,
168 const struct lttng_condition
*_b
)
170 bool is_equal
= false;
171 struct lttng_condition_buffer_usage
*a
, *b
;
173 a
= container_of(_a
, struct lttng_condition_buffer_usage
, parent
);
174 b
= container_of(_b
, struct lttng_condition_buffer_usage
, parent
);
176 if ((a
->threshold_ratio
.set
&& !b
->threshold_ratio
.set
) ||
177 (a
->threshold_bytes
.set
&& !b
->threshold_bytes
.set
)) {
181 if (a
->threshold_ratio
.set
&& b
->threshold_ratio
.set
) {
182 double a_value
, b_value
, diff
;
184 a_value
= a
->threshold_ratio
.value
;
185 b_value
= b
->threshold_ratio
.value
;
186 diff
= fabs(a_value
- b_value
);
188 if (diff
> DBL_EPSILON
) {
191 } else if (a
->threshold_bytes
.set
&& b
->threshold_bytes
.set
) {
192 uint64_t a_value
, b_value
;
194 a_value
= a
->threshold_bytes
.value
;
195 b_value
= b
->threshold_bytes
.value
;
196 if (a_value
!= b_value
) {
201 /* Condition is not valid if this is not true. */
202 assert(a
->session_name
);
203 assert(b
->session_name
);
204 if (strcmp(a
->session_name
, b
->session_name
)) {
208 assert(a
->channel_name
);
209 assert(b
->channel_name
);
210 if (strcmp(a
->channel_name
, b
->channel_name
)) {
214 assert(a
->domain
.set
);
215 assert(b
->domain
.set
);
216 if (a
->domain
.type
!= b
->domain
.type
) {
225 struct lttng_condition
*lttng_condition_buffer_usage_create(
226 enum lttng_condition_type type
)
228 struct lttng_condition_buffer_usage
*condition
;
230 condition
= zmalloc(sizeof(struct lttng_condition_buffer_usage
));
235 lttng_condition_init(&condition
->parent
, type
);
236 condition
->parent
.validate
= lttng_condition_buffer_usage_validate
;
237 condition
->parent
.serialize
= lttng_condition_buffer_usage_serialize
;
238 condition
->parent
.equal
= lttng_condition_buffer_usage_is_equal
;
239 condition
->parent
.destroy
= lttng_condition_buffer_usage_destroy
;
240 return &condition
->parent
;
243 struct lttng_condition
*lttng_condition_buffer_usage_low_create(void)
245 return lttng_condition_buffer_usage_create(
246 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
);
249 struct lttng_condition
*lttng_condition_buffer_usage_high_create(void)
251 return lttng_condition_buffer_usage_create(
252 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
);
256 ssize_t
init_condition_from_buffer(struct lttng_condition
*condition
,
257 const struct lttng_buffer_view
*src_view
)
259 ssize_t ret
, condition_size
;
260 enum lttng_condition_status status
;
261 enum lttng_domain_type domain_type
;
262 const struct lttng_condition_buffer_usage_comm
*condition_comm
;
263 const char *session_name
, *channel_name
;
264 struct lttng_buffer_view names_view
;
266 if (src_view
->size
< sizeof(*condition_comm
)) {
267 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain header");
272 condition_comm
= (const struct lttng_condition_buffer_usage_comm
*) src_view
->data
;
273 names_view
= lttng_buffer_view_from_view(src_view
,
274 sizeof(*condition_comm
), -1);
276 if (condition_comm
->session_name_len
> LTTNG_NAME_MAX
||
277 condition_comm
->channel_name_len
> LTTNG_NAME_MAX
) {
278 ERR("Failed to initialize from malformed condition buffer: name exceeds LTTNG_MAX_NAME");
283 if (names_view
.size
<
284 (condition_comm
->session_name_len
+
285 condition_comm
->channel_name_len
)) {
286 ERR("Failed to initialize from malformed condition buffer: buffer too short to contain element names");
291 if (condition_comm
->threshold_set_in_bytes
) {
292 status
= lttng_condition_buffer_usage_set_threshold(condition
,
293 condition_comm
->threshold
);
295 status
= lttng_condition_buffer_usage_set_threshold_ratio(
297 fixed_to_double(condition_comm
->threshold
));
299 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
300 ERR("Failed to initialize buffer usage condition threshold");
305 if (condition_comm
->domain_type
<= LTTNG_DOMAIN_NONE
||
306 condition_comm
->domain_type
> LTTNG_DOMAIN_PYTHON
) {
307 /* Invalid domain value. */
308 ERR("Invalid domain type value (%i) found in condition buffer",
309 (int) condition_comm
->domain_type
);
314 domain_type
= (enum lttng_domain_type
) condition_comm
->domain_type
;
315 status
= lttng_condition_buffer_usage_set_domain_type(condition
,
317 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
318 ERR("Failed to set buffer usage condition domain");
323 session_name
= names_view
.data
;
324 if (*(session_name
+ condition_comm
->session_name_len
- 1) != '\0') {
325 ERR("Malformed session name encountered in condition buffer");
330 channel_name
= session_name
+ condition_comm
->session_name_len
;
331 if (*(channel_name
+ condition_comm
->channel_name_len
- 1) != '\0') {
332 ERR("Malformed channel name encountered in condition buffer");
337 status
= lttng_condition_buffer_usage_set_session_name(condition
,
339 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
340 ERR("Failed to set buffer usage session name");
345 status
= lttng_condition_buffer_usage_set_channel_name(condition
,
347 if (status
!= LTTNG_CONDITION_STATUS_OK
) {
348 ERR("Failed to set buffer usage channel name");
353 if (!lttng_condition_validate(condition
)) {
358 condition_size
= sizeof(*condition_comm
) +
359 (ssize_t
) condition_comm
->session_name_len
+
360 (ssize_t
) condition_comm
->channel_name_len
;
361 ret
= condition_size
;
367 ssize_t
lttng_condition_buffer_usage_low_create_from_buffer(
368 const struct lttng_buffer_view
*view
,
369 struct lttng_condition
**_condition
)
372 struct lttng_condition
*condition
=
373 lttng_condition_buffer_usage_low_create();
375 if (!_condition
|| !condition
) {
380 ret
= init_condition_from_buffer(condition
, view
);
385 *_condition
= condition
;
388 lttng_condition_destroy(condition
);
393 ssize_t
lttng_condition_buffer_usage_high_create_from_buffer(
394 const struct lttng_buffer_view
*view
,
395 struct lttng_condition
**_condition
)
398 struct lttng_condition
*condition
=
399 lttng_condition_buffer_usage_high_create();
401 if (!_condition
|| !condition
) {
406 ret
= init_condition_from_buffer(condition
, view
);
411 *_condition
= condition
;
414 lttng_condition_destroy(condition
);
419 struct lttng_evaluation
*create_evaluation_from_buffer(
420 enum lttng_condition_type type
,
421 const struct lttng_buffer_view
*view
)
423 const struct lttng_evaluation_buffer_usage_comm
*comm
=
424 (const struct lttng_evaluation_buffer_usage_comm
*) view
->data
;
425 struct lttng_evaluation
*evaluation
= NULL
;
427 if (view
->size
< sizeof(*comm
)) {
431 evaluation
= lttng_evaluation_buffer_usage_create(type
,
432 comm
->buffer_use
, comm
->buffer_capacity
);
438 ssize_t
lttng_evaluation_buffer_usage_low_create_from_buffer(
439 const struct lttng_buffer_view
*view
,
440 struct lttng_evaluation
**_evaluation
)
443 struct lttng_evaluation
*evaluation
= NULL
;
450 evaluation
= create_evaluation_from_buffer(
451 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW
, view
);
457 *_evaluation
= evaluation
;
458 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
461 lttng_evaluation_destroy(evaluation
);
466 ssize_t
lttng_evaluation_buffer_usage_high_create_from_buffer(
467 const struct lttng_buffer_view
*view
,
468 struct lttng_evaluation
**_evaluation
)
471 struct lttng_evaluation
*evaluation
= NULL
;
478 evaluation
= create_evaluation_from_buffer(
479 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH
, view
);
485 *_evaluation
= evaluation
;
486 ret
= sizeof(struct lttng_evaluation_buffer_usage_comm
);
489 lttng_evaluation_destroy(evaluation
);
493 enum lttng_condition_status
494 lttng_condition_buffer_usage_get_threshold_ratio(
495 const struct lttng_condition
*condition
,
496 double *threshold_ratio
)
498 struct lttng_condition_buffer_usage
*usage
;
499 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
501 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
503 status
= LTTNG_CONDITION_STATUS_INVALID
;
507 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
509 if (!usage
->threshold_ratio
.set
) {
510 status
= LTTNG_CONDITION_STATUS_UNSET
;
513 *threshold_ratio
= usage
->threshold_ratio
.value
;
518 /* threshold_ratio expressed as [0.0, 1.0]. */
519 enum lttng_condition_status
520 lttng_condition_buffer_usage_set_threshold_ratio(
521 struct lttng_condition
*condition
, double threshold_ratio
)
523 struct lttng_condition_buffer_usage
*usage
;
524 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
526 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
527 threshold_ratio
< 0.0 ||
528 threshold_ratio
> 1.0) {
529 status
= LTTNG_CONDITION_STATUS_INVALID
;
533 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
535 usage
->threshold_ratio
.set
= true;
536 usage
->threshold_bytes
.set
= false;
537 usage
->threshold_ratio
.value
= threshold_ratio
;
542 enum lttng_condition_status
543 lttng_condition_buffer_usage_get_threshold(
544 const struct lttng_condition
*condition
,
545 uint64_t *threshold_bytes
)
547 struct lttng_condition_buffer_usage
*usage
;
548 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
550 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !threshold_bytes
) {
551 status
= LTTNG_CONDITION_STATUS_INVALID
;
555 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
557 if (!usage
->threshold_bytes
.set
) {
558 status
= LTTNG_CONDITION_STATUS_UNSET
;
561 *threshold_bytes
= usage
->threshold_bytes
.value
;
566 enum lttng_condition_status
567 lttng_condition_buffer_usage_set_threshold(
568 struct lttng_condition
*condition
, uint64_t threshold_bytes
)
570 struct lttng_condition_buffer_usage
*usage
;
571 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
573 if (!condition
|| !IS_USAGE_CONDITION(condition
)) {
574 status
= LTTNG_CONDITION_STATUS_INVALID
;
578 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
580 usage
->threshold_ratio
.set
= false;
581 usage
->threshold_bytes
.set
= true;
582 usage
->threshold_bytes
.value
= threshold_bytes
;
587 enum lttng_condition_status
588 lttng_condition_buffer_usage_get_session_name(
589 const struct lttng_condition
*condition
,
590 const char **session_name
)
592 struct lttng_condition_buffer_usage
*usage
;
593 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
595 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
) {
596 status
= LTTNG_CONDITION_STATUS_INVALID
;
600 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
602 if (!usage
->session_name
) {
603 status
= LTTNG_CONDITION_STATUS_UNSET
;
606 *session_name
= usage
->session_name
;
611 enum lttng_condition_status
612 lttng_condition_buffer_usage_set_session_name(
613 struct lttng_condition
*condition
, const char *session_name
)
615 char *session_name_copy
;
616 struct lttng_condition_buffer_usage
*usage
;
617 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
619 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !session_name
||
620 strlen(session_name
) == 0) {
621 status
= LTTNG_CONDITION_STATUS_INVALID
;
625 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
627 session_name_copy
= strdup(session_name
);
628 if (!session_name_copy
) {
629 status
= LTTNG_CONDITION_STATUS_ERROR
;
633 if (usage
->session_name
) {
634 free(usage
->session_name
);
636 usage
->session_name
= session_name_copy
;
641 enum lttng_condition_status
642 lttng_condition_buffer_usage_get_channel_name(
643 const struct lttng_condition
*condition
,
644 const char **channel_name
)
646 struct lttng_condition_buffer_usage
*usage
;
647 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
649 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
) {
650 status
= LTTNG_CONDITION_STATUS_INVALID
;
654 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
656 if (!usage
->channel_name
) {
657 status
= LTTNG_CONDITION_STATUS_UNSET
;
660 *channel_name
= usage
->channel_name
;
665 enum lttng_condition_status
666 lttng_condition_buffer_usage_set_channel_name(
667 struct lttng_condition
*condition
, const char *channel_name
)
669 char *channel_name_copy
;
670 struct lttng_condition_buffer_usage
*usage
;
671 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
673 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !channel_name
||
674 strlen(channel_name
) == 0) {
675 status
= LTTNG_CONDITION_STATUS_INVALID
;
679 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
681 channel_name_copy
= strdup(channel_name
);
682 if (!channel_name_copy
) {
683 status
= LTTNG_CONDITION_STATUS_ERROR
;
687 if (usage
->channel_name
) {
688 free(usage
->channel_name
);
690 usage
->channel_name
= channel_name_copy
;
695 enum lttng_condition_status
696 lttng_condition_buffer_usage_get_domain_type(
697 const struct lttng_condition
*condition
,
698 enum lttng_domain_type
*type
)
700 struct lttng_condition_buffer_usage
*usage
;
701 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
703 if (!condition
|| !IS_USAGE_CONDITION(condition
) || !type
) {
704 status
= LTTNG_CONDITION_STATUS_INVALID
;
708 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
710 if (!usage
->domain
.set
) {
711 status
= LTTNG_CONDITION_STATUS_UNSET
;
714 *type
= usage
->domain
.type
;
719 enum lttng_condition_status
720 lttng_condition_buffer_usage_set_domain_type(
721 struct lttng_condition
*condition
, enum lttng_domain_type type
)
723 struct lttng_condition_buffer_usage
*usage
;
724 enum lttng_condition_status status
= LTTNG_CONDITION_STATUS_OK
;
726 if (!condition
|| !IS_USAGE_CONDITION(condition
) ||
727 type
== LTTNG_DOMAIN_NONE
) {
728 status
= LTTNG_CONDITION_STATUS_INVALID
;
732 usage
= container_of(condition
, struct lttng_condition_buffer_usage
,
734 usage
->domain
.set
= true;
735 usage
->domain
.type
= type
;
741 int lttng_evaluation_buffer_usage_serialize(
742 const struct lttng_evaluation
*evaluation
,
743 struct lttng_dynamic_buffer
*buf
)
745 struct lttng_evaluation_buffer_usage
*usage
;
746 struct lttng_evaluation_buffer_usage_comm comm
;
748 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
750 comm
.buffer_use
= usage
->buffer_use
;
751 comm
.buffer_capacity
= usage
->buffer_capacity
;
753 return lttng_dynamic_buffer_append(buf
, &comm
, sizeof(comm
));
757 void lttng_evaluation_buffer_usage_destroy(
758 struct lttng_evaluation
*evaluation
)
760 struct lttng_evaluation_buffer_usage
*usage
;
762 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
768 struct lttng_evaluation
*lttng_evaluation_buffer_usage_create(
769 enum lttng_condition_type type
, uint64_t use
, uint64_t capacity
)
771 struct lttng_evaluation_buffer_usage
*usage
;
773 usage
= zmalloc(sizeof(struct lttng_evaluation_buffer_usage
));
778 usage
->parent
.type
= type
;
779 usage
->buffer_use
= use
;
780 usage
->buffer_capacity
= capacity
;
781 usage
->parent
.serialize
= lttng_evaluation_buffer_usage_serialize
;
782 usage
->parent
.destroy
= lttng_evaluation_buffer_usage_destroy
;
784 return &usage
->parent
;
788 * Get the sampled buffer usage which caused the associated condition to
789 * evaluate to "true".
791 enum lttng_evaluation_status
792 lttng_evaluation_buffer_usage_get_usage_ratio(
793 const struct lttng_evaluation
*evaluation
, double *usage_ratio
)
795 struct lttng_evaluation_buffer_usage
*usage
;
796 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
798 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_ratio
) {
799 status
= LTTNG_EVALUATION_STATUS_INVALID
;
803 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
805 *usage_ratio
= (double) usage
->buffer_use
/
806 (double) usage
->buffer_capacity
;
811 enum lttng_evaluation_status
812 lttng_evaluation_buffer_usage_get_usage(
813 const struct lttng_evaluation
*evaluation
,
814 uint64_t *usage_bytes
)
816 struct lttng_evaluation_buffer_usage
*usage
;
817 enum lttng_evaluation_status status
= LTTNG_EVALUATION_STATUS_OK
;
819 if (!evaluation
|| !is_usage_evaluation(evaluation
) || !usage_bytes
) {
820 status
= LTTNG_EVALUATION_STATUS_INVALID
;
824 usage
= container_of(evaluation
, struct lttng_evaluation_buffer_usage
,
826 *usage_bytes
= usage
->buffer_use
;