2 * PASS (Power Aware System Service) - System Resource Driver
4 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 * @file resource-system.c
27 #include <hal/hal-power.h>
29 #include <util/common.h>
31 #include <util/kernel.h>
33 #include <libsyscommon/resource-manager.h>
34 #include <libsyscommon/resource-type.h>
36 #include <resource-monitor/resource-monitor.h>
38 struct system_resource_data {
39 int num_possible_cpus;
41 struct cpu_stat *prev_cpus;
42 struct cpu_stat *curr_cpus;
45 static double __calculate_cpu_util(int64_t id, struct cpu_stat *prev,
46 struct cpu_stat *curr)
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;
57 total = (double)(diff.user + diff.system + diff.nice + diff.idle);
63 case SYSTEM_ATTR_CPU_UTIL:
64 case SYSTEM_ATTR_PER_CPU_UTIL:
65 util = (double)((diff.user + diff.system + diff.nice) * 100) / total;
67 case SYSTEM_ATTR_CPU_USER_UTIL:
68 case SYSTEM_ATTR_PER_CPU_USER_UTIL:
69 util = (double)((diff.user) * 100) / total;
71 case SYSTEM_ATTR_CPU_SYS_UTIL:
72 case SYSTEM_ATTR_PER_CPU_SYS_UTIL:
73 util = (double)((diff.system + diff.nice) * 100) / total;
82 static int system_get_avg_cpu_util(int resource_id,
83 const struct syscommon_resman_resource_attribute *attr,
86 struct system_resource_data *sysdata;
87 double util, sum = 0.0;
90 if (resource_id < 0 || !attr || !data)
93 sysdata = syscommon_resman_get_resource_privdata(resource_id);
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]);
102 _W("failed to calculate per-cpu util (%s: %s)\n",
103 syscommon_resman_get_resource_name(resource_id), attr->name);
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
116 *(double *)data = sum / sysdata->num_possible_cpus;
121 static int system_get_per_cpu_util(int resource_id,
122 const struct syscommon_resman_resource_attribute *attr,
125 struct system_resource_data *sysdata;
126 struct syscommon_resman_array_value *array = (struct syscommon_resman_array_value *)data;
130 if (resource_id < 0 || !attr || !data)
133 sysdata = syscommon_resman_get_resource_privdata(resource_id);
137 array->type = SYSCOMMON_RESMAN_DATA_TYPE_DOUBLE;
138 array->length = sysdata->num_possible_cpus;
143 array->data = calloc(sysdata->num_possible_cpus, sizeof(double));
147 utils = (double *)array->data;
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]);
154 _W("failed to calculate per-cpu util (%s: %s)\n",
155 syscommon_resman_get_resource_name(resource_id), attr->name);
163 static int system_get_cpu_num(int resource_id,
164 const struct syscommon_resman_resource_attribute *attr,
167 int *cpu_num = (int *)data;
169 if (resource_id < 0 || !attr || !data)
173 case SYSTEM_ATTR_POSSIBLE_CPU:
174 *cpu_num = kernel_get_online_cpu_num();
176 case SYSTEM_ATTR_ONLINE_CPU:
177 *cpu_num = kernel_get_possible_cpu_num();
186 static const struct syscommon_resman_resource_attribute system_attrs[] = {
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,
193 .get = system_get_avg_cpu_util,
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,
201 .get = system_get_avg_cpu_util,
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,
209 .get = system_get_avg_cpu_util,
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,
217 .get = system_get_per_cpu_util,
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,
225 .get = system_get_per_cpu_util,
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,
233 .get = system_get_per_cpu_util,
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,
241 .get = system_get_cpu_num,
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,
249 .get = system_get_cpu_num,
254 static int system_create(int resource_id)
256 struct system_resource_data *sysdata;
257 const char *res_name = syscommon_resman_get_resource_name(resource_id);
260 sysdata = calloc(1, sizeof(struct system_resource_data));
264 ret = kernel_get_possible_cpu_num();
266 _I("failed to get possible cpu on system driver (%s)\n", res_name);
269 sysdata->num_possible_cpus = ret;
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);
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);
287 syscommon_resman_set_resource_privdata(resource_id, (void *)sysdata);
292 free(sysdata->prev_cpus);
294 sysdata->num_possible_cpus = 0;
300 static void system_delete(int resource_id)
302 struct system_resource_data *sysdata;
307 sysdata = syscommon_resman_get_resource_privdata(resource_id);
311 free(sysdata->prev_cpus);
312 free(sysdata->curr_cpus);
314 syscommon_resman_set_resource_privdata(resource_id, NULL);
317 static int system_driver_prepare_update(int resource_id)
319 struct system_resource_data *sysdata;
320 const char *res_name = syscommon_resman_get_resource_name(resource_id);
323 sysdata = syscommon_resman_get_resource_privdata(resource_id);
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);
334 _I("failed to calculate per-cpu util (%s)\n", res_name);
341 static const struct syscommon_resman_resource_driver system_resource_driver = {
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),
348 .create = system_create,
349 .delete = system_delete,
350 .prepare_update = system_driver_prepare_update,
353 SYSCOMMON_RESMAN_RESOURCE_DRIVER_REGISTER(&system_resource_driver)