resource: Operate based on resource id
[platform/core/system/pass.git] / src / resource / resource-system.c
1 /*
2  * PASS (Power Aware System Service) - System Resource Driver
3  *
4  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /**
20  * @file        resource-system.c
21  * @brief       TBD
22  * @ingroup     TBD
23  */
24
25 #include <glib.h>
26
27 #include <hal/hal-power.h>
28
29 #include <util/common.h>
30 #include <util/log.h>
31 #include <util/kernel.h>
32
33 #include <libsyscommon/resource-manager.h>
34 #include <libsyscommon/resource-type.h>
35
36 #include <resource-monitor/resource-monitor.h>
37
38 struct system_resource_data {
39         int num_possible_cpus;
40         int num_online_cpus;
41         struct cpu_stat *prev_cpus;
42         struct cpu_stat *curr_cpus;
43 };
44
45 static double __calculate_cpu_util(int64_t id, struct cpu_stat *prev,
46                                         struct cpu_stat *curr)
47 {
48         struct cpu_stat diff;
49         int total;
50         double util;
51
52         diff.user = curr->user - prev->user;
53         diff.system = curr->system - prev->system;
54         diff.nice = curr->nice - prev->nice;
55         diff.idle = curr->idle - prev->idle;
56
57         total = (double)(diff.user + diff.system + diff.nice + diff.idle);
58
59         if (total < 1E-6)
60                 return 0.0;
61
62         switch (id) {
63         case SYSTEM_ATTR_CPU_UTIL:
64         case SYSTEM_ATTR_PER_CPU_UTIL:
65                 util = (double)((diff.user + diff.system + diff.nice) * 100) / total;
66                 break;
67         case SYSTEM_ATTR_CPU_USER_UTIL:
68         case SYSTEM_ATTR_PER_CPU_USER_UTIL:
69                 util = (double)((diff.user) * 100) / total;
70                 break;
71         case SYSTEM_ATTR_CPU_SYS_UTIL:
72         case SYSTEM_ATTR_PER_CPU_SYS_UTIL:
73                 util = (double)((diff.system + diff.nice) * 100) / total;
74                 break;
75         default:
76                 return -EINVAL;
77         }
78
79         return util;
80 }
81
82 static int system_get_avg_cpu_util(int resource_id,
83                                 const struct syscommon_resman_resource_attribute *attr,
84                                 void *data)
85 {
86         struct system_resource_data *sysdata;
87         double util, sum = 0.0;
88         int i;
89
90         if (resource_id < 0 || !attr || !data)
91                 return -EINVAL;
92
93         sysdata = syscommon_resman_get_resource_privdata(resource_id);
94         if (!sysdata)
95                 return -EINVAL;
96
97         for (i = 0; i < sysdata->num_possible_cpus; i++) {
98                 util = __calculate_cpu_util(attr->id,
99                                         &sysdata->prev_cpus[i],
100                                         &sysdata->curr_cpus[i]);
101                 if (util < 0.0) {
102                         _W("failed to calculate per-cpu util (%s: %s)\n",
103                                         syscommon_resman_get_resource_name(resource_id), attr->name);
104                         continue;
105                 }
106
107                 sum += util;
108         }
109
110         /*
111          * For offline cpus, it is reasonable to assume that the cpu utilization
112          * is 0%, so when calculating the average utilization, it is more
113          * accurate to average the number of possible cpus instead of the number
114          * of online cpus.
115          */
116         *(double *)data = sum / sysdata->num_possible_cpus;
117
118         return 0;
119 }
120
121 static int system_get_per_cpu_util(int resource_id,
122                                 const struct syscommon_resman_resource_attribute *attr,
123                                 void *data)
124 {
125         struct system_resource_data *sysdata;
126         struct syscommon_resman_array_value *array = (struct syscommon_resman_array_value *)data;
127         double *utils;
128         int i;
129
130         if (resource_id < 0 || !attr || !data)
131                 return -EINVAL;
132
133         sysdata = syscommon_resman_get_resource_privdata(resource_id);
134         if (!sysdata)
135                 return -EINVAL;
136
137         array->type = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE;
138         array->length = sysdata->num_possible_cpus;
139
140         if (array->data)
141                 free(array->data);
142
143         array->data = calloc(sysdata->num_possible_cpus, sizeof(double));
144         if (!array->data)
145                 return -ENOMEM;
146
147         utils = (double *)array->data;
148
149         for (i = 0; i < sysdata->num_possible_cpus; i++) {
150                 utils[i] = __calculate_cpu_util(attr->id,
151                                         &sysdata->prev_cpus[i],
152                                         &sysdata->curr_cpus[i]);
153                 if (utils[i] < 0) {
154                         _W("failed to calculate per-cpu util (%s: %s)\n",
155                                         syscommon_resman_get_resource_name(resource_id), attr->name);
156                         utils[i] = 0;
157                 }
158         }
159
160         return 0;
161 }
162
163 static int system_get_cpu_num(int resource_id,
164                                 const struct syscommon_resman_resource_attribute *attr,
165                                 void *data)
166 {
167         int *cpu_num = (int *)data;
168
169         if (resource_id < 0 || !attr || !data)
170                 return -EINVAL;
171
172         switch (attr->id) {
173         case SYSTEM_ATTR_POSSIBLE_CPU:
174                 *cpu_num = kernel_get_online_cpu_num();
175                 break;
176         case SYSTEM_ATTR_ONLINE_CPU:
177                 *cpu_num = kernel_get_possible_cpu_num();
178                 break;
179         default:
180                 return -EINVAL;
181         }
182
183         return 0;
184 }
185
186 static const struct syscommon_resman_resource_attribute system_attrs[] = {
187         {
188                 .name   = "SYSTEM_ATTR_CPU_UTIL",
189                 .id     = SYSTEM_ATTR_CPU_UTIL,
190                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE,
191                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
192                 .ops    = {
193                         .get = system_get_avg_cpu_util,
194                 }
195         }, {
196                 .name   = "SYSTEM_ATTR_CPU_USER_UTIL",
197                 .id     = SYSTEM_ATTR_CPU_USER_UTIL,
198                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE,
199                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
200                 .ops    = {
201                         .get = system_get_avg_cpu_util,
202                 }
203         }, {
204                 .name   = "SYSTEM_ATTR_CPU_SYS_UTIL",
205                 .id     = SYSTEM_ATTR_CPU_SYS_UTIL,
206                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE,
207                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
208                 .ops    = {
209                         .get = system_get_avg_cpu_util,
210                 }
211         }, {
212                 .name   = "SYSTEM_ATTR_PER_CPU_UTIL",
213                 .id     = SYSTEM_ATTR_PER_CPU_UTIL,
214                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_ARRAY,
215                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
216                 .ops    = {
217                         .get = system_get_per_cpu_util,
218                 }
219         }, {
220                 .name   = "SYSTEM_ATTR_PER_CPU_USER_UTIL",
221                 .id     = SYSTEM_ATTR_PER_CPU_USER_UTIL,
222                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_ARRAY,
223                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
224                 .ops    = {
225                         .get = system_get_per_cpu_util,
226                 }
227         }, {
228                 .name   = "SYSTEM_ATTR_PER_CPU_SYS_UTIL",
229                 .id     = SYSTEM_ATTR_PER_CPU_SYS_UTIL,
230                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_ARRAY,
231                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
232                 .ops    = {
233                         .get = system_get_per_cpu_util,
234                 }
235         }, {
236                 .name   = "SYSTEM_ATTR_POSSIBLE_CPU",
237                 .id     = SYSTEM_ATTR_POSSIBLE_CPU,
238                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_INT,
239                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
240                 .ops    = {
241                         .get = system_get_cpu_num,
242                 }
243         }, {
244                 .name   = "SYSTEM_ATTR_ONLINE_CPU",
245                 .id     = SYSTEM_ATTR_ONLINE_CPU,
246                 .type   = SYSCOMMON_RESMAN_DATA_TYPE_INT,
247                 .flag   = SYSCOMMON_RESMAN_RESOURCE_ATTR_FLAG_PUBLIC,
248                 .ops    = {
249                         .get = system_get_cpu_num,
250                 }
251         },
252 };
253
254 static int system_create(int resource_id)
255 {
256         struct system_resource_data *sysdata;
257         const char *res_name = syscommon_resman_get_resource_name(resource_id);
258         int ret;
259
260         sysdata = calloc(1, sizeof(struct system_resource_data));
261         if (!sysdata)
262                 return -ENOMEM;
263
264         ret = kernel_get_possible_cpu_num();
265         if (ret < 0) {
266                 _I("failed to get possible cpu on system driver (%s)\n", res_name);
267                 goto err;
268         }
269         sysdata->num_possible_cpus = ret;
270
271         sysdata->prev_cpus = calloc(sysdata->num_possible_cpus,
272                                         sizeof(struct cpu_stat));
273         if (!sysdata->prev_cpus) {
274                 _I("failed to allocate memory of prev_cpus (%s)\n", res_name);
275                 ret = -ENOMEM;
276                 goto err;
277         }
278
279         sysdata->curr_cpus = calloc(sysdata->num_possible_cpus,
280                                         sizeof(struct cpu_stat));
281         if (!sysdata->curr_cpus) {
282                 _I("failed to allocate memory of curr_cpus (%s)\n", res_name);
283                 ret = -ENOMEM;
284                 goto err_prev_cpus;
285         }
286
287         syscommon_resman_set_resource_privdata(resource_id, (void *)sysdata);
288
289         return 0;
290
291 err_prev_cpus:
292         free(sysdata->prev_cpus);
293 err:
294         sysdata->num_possible_cpus = 0;
295         free(sysdata);
296
297         return ret;
298 }
299
300 static void system_delete(int resource_id)
301 {
302         struct system_resource_data *sysdata;
303
304         if (resource_id < 0)
305                 return;
306
307         sysdata = syscommon_resman_get_resource_privdata(resource_id);
308         if (!sysdata)
309                 return;
310
311         free(sysdata->prev_cpus);
312         free(sysdata->curr_cpus);
313         free(sysdata);
314         syscommon_resman_set_resource_privdata(resource_id, NULL);
315 }
316
317 static int system_driver_prepare_update(int resource_id)
318 {
319         struct system_resource_data *sysdata;
320         const char *res_name = syscommon_resman_get_resource_name(resource_id);
321         int ret;
322
323         sysdata = syscommon_resman_get_resource_privdata(resource_id);
324         if (!sysdata)
325                 return -EINVAL;
326
327         /* Get the per-cpu utilization */
328         memcpy(sysdata->prev_cpus, sysdata->curr_cpus,
329                         sizeof(struct cpu_stat) * sysdata->num_possible_cpus);
330         ret = kernel_get_per_cpu_stat(sysdata->curr_cpus,
331                                         sysdata->num_possible_cpus,
332                                         &sysdata->num_online_cpus);
333         if (ret < 0) {
334                 _I("failed to calculate per-cpu util (%s)\n", res_name);
335                 return ret;
336         }
337
338         return 0;
339 }
340
341 static const struct syscommon_resman_resource_driver system_resource_driver = {
342         .name           = "SYSTEM",
343         .type           = RESOURCE_TYPE_SYSTEM,
344         .flag           = SYSCOMMON_RESMAN_RESOURCE_DRIVER_FLAG_COUNT_ONLY_ONE,
345         .attrs          = system_attrs,
346         .num_attrs      = ARRAY_SIZE(system_attrs),
347         .ops = {
348                 .create         = system_create,
349                 .delete         = system_delete,
350                 .prepare_update = system_driver_prepare_update,
351         },
352 };
353 SYSCOMMON_RESMAN_RESOURCE_DRIVER_REGISTER(&system_resource_driver)