dlog_logger: refactor QoS distributions
[platform/core/system/dlog.git] / src / logger / qos.c
1 /* Copyright (c) 2020, Samsung Electronics Co., Ltd. All rights reserved.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License. */
14
15 #include "qos.h"
16
17 #include <assert.h>
18 #include <stdlib.h>
19 #include <logcommon.h>
20
21 bool qos_is_enabled(const struct qos_module *qos)
22 {
23         assert(qos);
24         return qos->threshold > 0 && qos->max_throughput > 0 && qos->file_path && strlen(qos->file_path) > 0;
25 }
26
27 void qos_create_limits_file(struct qos_module *qos, bool is_limiting)
28 {
29         __attribute__((cleanup(close_fd))) int fd = creat(qos->file_path, 0644);
30         if (fd < 0)
31                 return;
32
33         if (!is_limiting) // leave an empty file to reset limits.
34                 return;
35
36         int recv_count;
37         __attribute__((cleanup(free_ptr))) struct metrics_info *const recv_infos = metrics_get_info(qos->log_metrics, &recv_count);
38         if (!recv_infos)
39                 return;
40
41         qsort(recv_infos, recv_count, sizeof(*recv_infos), metrics_sort_by_pid_first);
42         __attribute__((cleanup(free_ptr))) struct metrics_pid_aggr_info *const aggr_infos = calloc(recv_count, sizeof(*aggr_infos));
43         if (!aggr_infos)
44                 return;
45
46         int aggr_count = 0;
47         pid_t last = -1;
48         for (int i = 0; i < recv_count; ++i) {
49                 if (recv_infos[i].pid != last) {
50                         aggr_infos[aggr_count].pid = recv_infos[i].pid;
51                         aggr_infos[aggr_count].count = 0;
52                         for (int j = 0; j < DLOG_PRIO_MAX; ++j)
53                                 aggr_infos[aggr_count].count += recv_infos[i].count[j];
54                         aggr_count += 1;
55                 } else {
56                         for (int j = 0; j < DLOG_PRIO_MAX; ++j)
57                                 aggr_infos[aggr_count - 1].count += recv_infos[i].count[j];
58                 }
59         }
60
61         qos->distribution_func(qos, aggr_infos, aggr_count);
62
63         const int len = aggr_count * 32;
64         __attribute__((cleanup(free_ptr))) char *buf = malloc(len);
65         int pos = 0;
66         for (int i = 0; i < aggr_count; ++i)
67                 if (aggr_infos[i].count >= 0) {
68                         int w = snprintf(buf + pos, pos - len, "pidlimit|%d=%d\n", aggr_infos[i].pid, aggr_infos[i].count);
69                         pos += w;
70                         assert(pos < len);
71                 }
72
73         (void) full_write(fd, buf, pos); // can't do much about write errors; ignore
74 }
75
76 void qos_set_next_update_time(struct qos_module *qos, struct timespec now)
77 {
78         qos->cancel_limits_at = now;
79         qos->cancel_limits_at.tv_sec += qos->limit_duration;
80 }
81
82 void qos_apply_limits(struct qos_module *qos)
83 {
84         qos->currently_limiting = true;
85         qos_create_limits_file(qos, true);
86 }
87
88 void qos_relax_limits(struct qos_module *qos)
89 {
90         qos->currently_limiting = false;
91         qos_create_limits_file(qos, false);
92 }
93
94 void qos_add_log(struct qos_module *qos, const struct dlogutil_entry *due)
95 {
96         assert(qos);
97         assert(due);
98
99         assert(qos->threshold > 0);
100         assert(qos->file_path);
101
102         if (!metrics_add_log(qos->log_metrics, due))
103                 return;
104
105         const int diff = metrics_get_total(qos->log_metrics) - qos->threshold;
106         if (diff < 0)
107                 return;
108
109         if (diff == 0 || (qos->threshold_reapply && diff % qos->threshold_reapply == 0))
110                 qos_apply_limits(qos); // the inQoSition declares Exterminatus
111 }
112
113 void qos_free(struct qos_module *qos)
114 {
115         metrics_destroy(qos->log_metrics);
116         free(qos->file_path);
117 }
118