4 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
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.
22 * @desc start cpu logging system for resourced
24 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
34 #include <sys/types.h>
36 #include <linux/limits.h>
42 #include <sys/utsname.h>
43 #include <systemd/sd-journal.h>
45 #include "resourced.h"
49 #include "proc-process.h"
52 #define PROC_STAT_PATH "/proc/%d/stat"
53 #define CPU_NAME "cpu"
54 #define CPU_COMMIT_INTERVAL 30*60 /* 20 min */
56 #define CPU_MAX_INTERVAL 20*60 /* 5 min */
57 #define CPU_INIT_INTERVAL 20*60 /* 3 min */
58 #define CPU_FOREGRD_INTERVAL 3*60 /* 1 min */
59 #define CPU_BACKGRD_INTERVAL 10*60 /* 2 min */
60 #define CPU_BACKGRD_OLD_INTERVAL 15*60 /* 5 min */
62 struct logging_cpu_info {
65 unsigned long last_utime;
66 unsigned long last_stime;
73 static int get_cpu_time(pid_t pid, unsigned long *utime,
76 char proc_path[sizeof(PROC_STAT_PATH) + MAX_DEC_SIZE(int)];
79 assert(utime != NULL);
80 assert(stime != NULL);
82 snprintf(proc_path, sizeof(proc_path), PROC_STAT_PATH, pid);
83 fp = fopen(proc_path, "r");
85 return RESOURCED_ERROR_FAIL;
87 if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s") < 0) {
89 return RESOURCED_ERROR_FAIL;
92 if (fscanf(fp, "%lu %lu", utime, stime) < 1) {
94 return RESOURCED_ERROR_FAIL;
99 return RESOURCED_ERROR_NONE;
102 static void update_log_interval(struct logging_cpu_info *loginfo, int oom,
105 if (!always && (oom < OOMADJ_FOREGRD_LOCKED))
110 case OOMADJ_SERVICE_MIN:
112 loginfo->log_interval = CPU_MAX_INTERVAL;
115 loginfo->log_interval = CPU_INIT_INTERVAL;
117 case OOMADJ_FOREGRD_LOCKED:
118 case OOMADJ_FOREGRD_UNLOCKED:
119 case OOMADJ_BACKGRD_LOCKED:
120 case OOMADJ_SERVICE_DEFAULT:
121 case OOMADJ_SERVICE_FOREGRD:
122 loginfo->log_interval = CPU_FOREGRD_INTERVAL;
124 case OOMADJ_BACKGRD_UNLOCKED:
125 case OOMADJ_SERVICE_BACKGRD:
126 loginfo->log_interval = CPU_BACKGRD_INTERVAL;
129 if (oom > OOMADJ_BACKGRD_UNLOCKED)
130 loginfo->log_interval = CPU_BACKGRD_OLD_INTERVAL;
135 static int init_cpu_info(void **pl, int pid, int oom, time_t now)
137 struct logging_cpu_info *info;
139 info = (struct logging_cpu_info *)
140 malloc(sizeof(struct logging_cpu_info));
142 _E("malloc for logging_cpu_info is failed");
143 return RESOURCED_ERROR_FAIL;
145 info->last_pid = pid;
148 info->last_utime = 0;
149 info->last_stime = 0;
150 info->last_log_time = now;
151 info->last_commited = false;
153 update_log_interval(info, oom, 1);
155 return RESOURCED_ERROR_NONE;
158 /* pss_interval should be adjusted depending on app type */
159 static int update_cpu_info(void *pl, pid_t pid, int oom,
160 time_t now, unsigned always)
162 int ret = RESOURCED_ERROR_NONE;
163 struct logging_cpu_info *loginfo = (struct logging_cpu_info *)pl;
164 unsigned long utime = 0, stime = 0;
165 unsigned long utime_diff = 0, stime_diff = 0;
168 unsigned long update_interval = now - loginfo->last_log_time;
169 if (update_interval < CPU_MAX_INTERVAL) {
170 if (now < loginfo->last_log_time + loginfo->log_interval)
173 loginfo->last_log_time = now;
177 ret = get_cpu_time(pid, &utime, &stime);
179 if (ret != RESOURCED_ERROR_NONE)
182 if (loginfo->last_pid == pid) {
183 if (loginfo->last_utime > utime)
186 utime_diff = utime - loginfo->last_utime;
187 loginfo->last_utime = utime;
188 loginfo->utime += utime_diff;
189 if (loginfo->stime > stime)
191 stime_diff = stime - loginfo->last_stime;
192 loginfo->last_stime = stime;
193 loginfo->stime += stime_diff;
196 loginfo->last_pid = pid;
197 loginfo->utime += utime;
198 loginfo->stime += stime;
199 loginfo->last_utime = utime;
200 loginfo->last_stime = stime;
204 loginfo->last_log_time = now;
205 loginfo->last_commited = false;
206 update_log_interval(loginfo, oom, 0);
210 static int write_cpu_info(char *name, struct logging_infos *infos,
213 struct logging_cpu_info *ci = infos->stats[ss_index];
215 if (!infos->running && ci->last_commited)
216 return RESOURCED_ERROR_NONE;
218 sd_journal_send("NAME=cpu",
219 "TIME=%ld", ci->last_log_time,
221 "UTIME=%ld", ci->utime,
222 "STIME=%ld", ci->stime,
225 ci->last_commited = true;
227 return RESOURCED_ERROR_NONE;
230 static struct logging_info_ops cpu_info_ops = {
231 .update = update_cpu_info,
232 .write = write_cpu_info,
233 .init = init_cpu_info,
236 static int logging_cpu_init(void *data)
240 ret = register_logging_subsystem(CPU_NAME, &cpu_info_ops);
241 if(ret != RESOURCED_ERROR_NONE) {
242 _E("register logging subsystem failed");
243 return RESOURCED_ERROR_FAIL;
245 ret = update_commit_interval(CPU_NAME, CPU_COMMIT_INTERVAL);
246 if(ret != RESOURCED_ERROR_NONE) {
247 _E("update commit interval logging subsystem failed");
248 return RESOURCED_ERROR_FAIL;
251 _D("logging cpu init finished");
252 return RESOURCED_ERROR_NONE;
255 static int logging_cpu_exit(void *data)
257 _D("logging cpu exit");
258 return RESOURCED_ERROR_NONE;
261 static struct module_ops logging_cpu_ops = {
262 .priority = MODULE_PRIORITY_NORMAL,
263 .name = "logging_cpu",
264 .init = logging_cpu_init,
265 .exit = logging_cpu_exit,
268 MODULE_REGISTER(&logging_cpu_ops)