Add unit(in variable) & fix bugs
[platform/core/system/resourced.git] / src / process / proc-usage-stats-helper.c
1 /*
2  * resourced
3  *
4  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
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 /*
21  * @file proc-usage-stats-helper.c
22  *
23  * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
24  *
25  */
26
27 #include <sys/types.h>
28 #include <unistd.h>
29
30 #include "smaps.h"
31 #include "proc-usage-stats-helper.h"
32 #include "macro.h"
33 #include "trace.h"
34
35 #define TASK_NAME_BASE "runtime_info_%s_usage"
36
37 static int proc_get_virtual_mem_size(int pid, int *vsize)
38 {
39         FILE *proc_stat;
40         char buf[1024];
41         unsigned long long vsz_bytes = 0;
42
43         proc_stat = NULL;
44
45         if (!vsize)
46                 goto error;
47
48         snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
49         proc_stat = fopen(buf, "r");
50         if (!proc_stat)
51                 goto error;
52
53         while (fgets(buf, sizeof(buf), proc_stat) != NULL) {
54                 if (sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %llu",
55                                         &vsz_bytes) != 1)
56                         goto error;
57         }
58         fclose(proc_stat);
59
60         *vsize =  BYTE_TO_KBYTE(vsz_bytes);
61         return RESOURCED_ERROR_NONE;
62
63 error:
64         if (proc_stat)
65                 fclose(proc_stat);
66         _E("error reading /proc/%d/stat file", pid);
67         return RESOURCED_ERROR_FAIL;
68 }
69
70 static int proc_get_smaps_info(int pid, struct process_memory_info_s *mem_info)
71 {
72         _cleanup_smaps_free_ struct smaps *maps = NULL;
73         int r;
74
75         r = smaps_get(pid, &maps, (SMAPS_MASK_RSS |
76                                    SMAPS_MASK_PSS |
77                                    SMAPS_MASK_SHARED_CLEAN |
78                                    SMAPS_MASK_SHARED_DIRTY |
79                                    SMAPS_MASK_PRIVATE_CLEAN |
80                                    SMAPS_MASK_PRIVATE_DIRTY));
81         if (r < 0) {
82                 _E("error reading /proc/%d/smaps file", pid);
83                 return RESOURCED_ERROR_FAIL;
84         }
85
86         mem_info->rss = maps->sum[SMAPS_ID_RSS];
87         mem_info->pss = maps->sum[SMAPS_ID_PSS];
88         mem_info->shared_clean = maps->sum[SMAPS_ID_SHARED_CLEAN];
89         mem_info->shared_dirty = maps->sum[SMAPS_ID_SHARED_DIRTY];
90         mem_info->private_clean = maps->sum[SMAPS_ID_PRIVATE_CLEAN];
91         mem_info->private_dirty = maps->sum[SMAPS_ID_PRIVATE_DIRTY];
92
93         return RESOURCED_ERROR_NONE;
94 }
95
96 /* Helper functions to get the needed memory usage info. */
97 void proc_get_memory_usage(int pid, struct process_memory_info_s *mem_info)
98 {
99         if (!mem_info)
100                 return;
101
102         if (pid < 0)
103                 goto error;
104
105         memset(mem_info, 0, sizeof(struct process_memory_info_s));
106         if (proc_get_virtual_mem_size(pid, &mem_info->vsz) != RESOURCED_ERROR_NONE)
107                 goto error;
108
109         if (proc_get_smaps_info(pid, mem_info) != RESOURCED_ERROR_NONE)
110                 goto error;
111
112         return;
113
114 error:
115         mem_info->vsz = INVALID_PROCESS_INFO_FIELD_VALUE;
116         mem_info->rss = INVALID_PROCESS_INFO_FIELD_VALUE;
117         mem_info->pss = INVALID_PROCESS_INFO_FIELD_VALUE;
118         mem_info->shared_clean = INVALID_PROCESS_INFO_FIELD_VALUE;
119         mem_info->shared_dirty = INVALID_PROCESS_INFO_FIELD_VALUE;
120         mem_info->private_clean = INVALID_PROCESS_INFO_FIELD_VALUE;
121         mem_info->private_dirty = INVALID_PROCESS_INFO_FIELD_VALUE;
122 }
123
124 /* Helper functions to get the needed cpu usage info. */
125 void proc_get_cpu_usage(int pid, struct process_cpu_usage_s *cpu_usage)
126 {
127         unsigned long utime = 0;
128         unsigned long stime = 0;
129         FILE *proc_stat;
130         char buf[1024];
131
132         proc_stat = NULL;
133
134         if (!cpu_usage)
135                 return;
136
137         if (pid < 0)
138                 goto error;
139
140         snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
141         proc_stat = fopen(buf, "r");
142         if (!proc_stat)
143                 goto error;
144         while (fgets(buf, sizeof(buf), proc_stat) != NULL) {
145                 if (sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %lu %lu",
146                                 &utime, &stime) != 2) {
147                         goto error;
148                 }
149         }
150         fclose(proc_stat);
151
152         cpu_usage->utime = (int)utime;
153         cpu_usage->stime = (int)stime;
154         return;
155
156 error:
157         if (proc_stat)
158                 fclose(proc_stat);
159         _E("error reading /proc/%d/stat file", pid);
160         cpu_usage->utime = INVALID_PROCESS_INFO_FIELD_VALUE;
161         cpu_usage->stime = INVALID_PROCESS_INFO_FIELD_VALUE;
162 }
163
164 /* Helper function to read from usage_info struct and populate
165  * result according to the task type */
166 int proc_read_from_usage_struct(void *usage_info_list, int index,
167                 int *result, runtime_info_task_type type)
168 {
169         if (!usage_info_list || !result || (index < 0)) {
170                 _E("invalid input");
171                 return RESOURCED_ERROR_FAIL;
172         }
173
174         if (type == RUNTIME_INFO_TASK_MEMORY) {
175                 struct process_memory_info_s *mem_info;
176
177                 mem_info = (struct process_memory_info_s *)usage_info_list;
178                 result[0] = mem_info[index].vsz;
179                 result[1] = mem_info[index].rss;
180                 result[2] = mem_info[index].pss;
181                 result[3] = mem_info[index].shared_clean;
182                 result[4] = mem_info[index].shared_dirty;
183                 result[5] = mem_info[index].private_clean;
184                 result[6] = mem_info[index].private_dirty;
185         } else if (type == RUNTIME_INFO_TASK_CPU) {
186                 struct process_cpu_usage_s *cpu_usage;
187
188                 cpu_usage = (struct process_cpu_usage_s *)usage_info_list;
189                 result[0] = cpu_usage[index].utime;
190                 result[1] = cpu_usage[index].stime;
191         } else {
192                 int *swap_usage = (int *)usage_info_list;
193                 result[0] = swap_usage[index];
194         }
195
196         return RESOURCED_ERROR_NONE;
197 }
198
199 /* Create task name according to the current time and
200  * set it to the input param task_name */
201 void proc_get_task_name(char *task_name, int size,
202                 runtime_info_task_type task_type)
203 {
204         struct tm cur_tm;
205         time_t now;
206         char buf[TASK_NAME_SIZE];
207
208         snprintf(buf, sizeof(buf), TASK_NAME_BASE,
209                         ((task_type == RUNTIME_INFO_TASK_MEMORY) ? "memory" :
210                          (task_type == RUNTIME_INFO_TASK_CPU) ? "cpu" : "swap" ));
211
212         if (!task_name || size <= 0)
213                 return;
214
215         now = time(NULL);
216         if (localtime_r(&now, &cur_tm) == NULL) {
217                 _E("Failed to get localtime");
218                 snprintf(task_name, size, "%s_%llu",
219                                 buf, (long long)now);
220                 return;
221         }
222
223         snprintf(task_name, size, "%s_%.4d%.2d%.2d_%.2d%.2d%.2d",
224                         buf, (1900 + cur_tm.tm_year),
225                         1 + cur_tm.tm_mon, cur_tm.tm_mday, cur_tm.tm_hour,
226                         cur_tm.tm_min, cur_tm.tm_sec);
227 }
228
229 /* Helper function to free the runtime info task instance */
230 void proc_free_runtime_info_task(struct runtime_info_task *rt_task)
231 {
232         if (!rt_task)
233                 return;
234
235         if (rt_task->usage_info_list)
236                 free(rt_task->usage_info_list);
237
238         if (rt_task->pipe_fds[0] >= 0)
239                 close(rt_task->pipe_fds[0]);
240         if (rt_task->pipe_fds[1] >= 0)
241                 close(rt_task->pipe_fds[1]);
242
243         free(rt_task->pid_list);
244
245         // we assume that rt_task->task_invocation is already freed before calling proc_free_runtime_info_task.
246
247         free(rt_task);
248 }