4 * Copyright (c) 2015 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.
21 * @file proc-usage-stats-helper.c
23 * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved.
27 #include <sys/types.h>
31 #include "proc-usage-stats-helper.h"
35 #define TASK_NAME_BASE "runtime_info_%s_usage"
37 static int proc_get_virtual_mem_size(int pid, int *vsize)
41 unsigned long long vsz_bytes = 0;
48 snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
49 proc_stat = fopen(buf, "r");
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",
60 *vsize = BYTE_TO_KBYTE(vsz_bytes);
61 return RESOURCED_ERROR_NONE;
66 _E("error reading /proc/%d/stat file", pid);
67 return RESOURCED_ERROR_FAIL;
70 static int proc_get_smaps_info(int pid, struct process_memory_info_s *mem_info)
72 _cleanup_smaps_free_ struct smaps *maps = NULL;
75 r = smaps_get(pid, &maps, (SMAPS_MASK_RSS |
77 SMAPS_MASK_SHARED_CLEAN |
78 SMAPS_MASK_SHARED_DIRTY |
79 SMAPS_MASK_PRIVATE_CLEAN |
80 SMAPS_MASK_PRIVATE_DIRTY));
82 _E("error reading /proc/%d/smaps file", pid);
83 return RESOURCED_ERROR_FAIL;
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];
93 return RESOURCED_ERROR_NONE;
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)
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)
109 if (proc_get_smaps_info(pid, mem_info) != RESOURCED_ERROR_NONE)
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;
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)
127 unsigned long utime = 0;
128 unsigned long stime = 0;
140 snprintf(buf, sizeof(buf), "/proc/%d/stat", pid);
141 proc_stat = fopen(buf, "r");
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) {
152 cpu_usage->utime = (int)utime;
153 cpu_usage->stime = (int)stime;
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;
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)
169 if (!usage_info_list || !result || (index < 0)) {
171 return RESOURCED_ERROR_FAIL;
174 if (type == RUNTIME_INFO_TASK_MEMORY) {
175 struct process_memory_info_s *mem_info;
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;
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;
192 int *swap_usage = (int *)usage_info_list;
193 result[0] = swap_usage[index];
196 return RESOURCED_ERROR_NONE;
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)
206 char buf[TASK_NAME_SIZE];
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" ));
212 if (!task_name || size <= 0)
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);
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);
229 /* Helper function to free the runtime info task instance */
230 void proc_free_runtime_info_task(struct runtime_info_task *rt_task)
235 if (rt_task->usage_info_list)
236 free(rt_task->usage_info_list);
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]);
243 free(rt_task->pid_list);
245 // we assume that rt_task->task_invocation is already freed before calling proc_free_runtime_info_task.