raiden00pl 32bcd87d8f system: unify Private Types banners
unify Private Types banners according to NuttX coding standard

Signed-off-by: raiden00pl <raiden00@railab.me>
2025-05-28 10:16:50 +08:00

651 lines
16 KiB
C

/****************************************************************************
* apps/system/resmonitor/showinfo.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <malloc.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/statfs.h>
#include <sys/time.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PATH "/proc"
#define CPULOAD "cpuload"
#define HEAP "heap"
#define STACK "stack"
#define LOADAVG "loadavg"
#define GROUP "group/status"
#define FILELEN 100
/****************************************************************************
* Private Types
****************************************************************************/
struct t_info
{
unsigned long mem_total;
unsigned long mem_used;
unsigned long mem_maxused;
unsigned long mem_free;
unsigned long mem_largest;
unsigned long mem_nused;
unsigned long mem_nfree;
char total_cpu[8];
};
struct p_info
{
unsigned long stack_used;
unsigned long heap_used;
char cpu[8];
};
/****************************************************************************
* Private Data
****************************************************************************/
static int go = 1;
static int p_head = 1;
static int d_head = 1;
/****************************************************************************
* Private Functions
****************************************************************************/
static void handler(int sig)
{
go = 0;
}
static void show_usages(void)
{
syslog(LOG_WARNING,
"Usage: CMD [-i <interval>] [-p <pid>] [-a] [-d <dir>] [-l "
"<logpath>] [-k <logpath>]\n"
"\t\t-i: set refresh interval (s), default 1s\n"
"\t\t-p: set pid to monitor, show stack, head and cpu used by pid\n"
"\t\t-a: work only if -p is set, show stack, head and cpu used by "
"pid group\n"
"\t\t-d: print the diskinfo of the dir\n"
"\t\t-l: the memory and cpu info output to logpath\n"
"\t\t-k: the diskinfo output to logpath\n");
exit(1);
}
static void get_cpu(int pid, char *buf)
{
char filepath[FILELEN];
int ret;
if (pid <= 0)
{
ret = snprintf(filepath, FILELEN, "%s/%s", PATH, CPULOAD);
}
else
{
ret = snprintf(filepath, FILELEN, "%s/%d/%s", PATH, pid, LOADAVG);
}
if (ret < 0)
{
/* syslog(LOG_ERR, "snprintf error\n"); */
snprintf(buf, 8, "%.1f%%", 0.0);
return;
}
FILE *fp = fopen(filepath, "r");
if (!fp)
{
snprintf(buf, 8, "%.1f%%", 0.0);
return;
}
fgets(buf, 8, fp);
/* sscanf(buf, "%f", &cpu); */
buf[strlen(buf) - 1] = '\0';
fclose(fp);
}
static void add_cpu(char *a, char *b, char *buf)
{
if (a == NULL || b == NULL)
{
return;
}
float fa = 0;
float fb = 0;
sscanf(a, "%f", &fa);
sscanf(b, "%f", &fb);
float sum = fa + fb;
int ret = snprintf(buf, 8, "%.1f%%", sum);
if (ret < 0)
{
syslog(LOG_ERR, "add_cpu error\n");
}
}
static unsigned long get_heap(int pid)
{
unsigned long heap = 0;
char filepath[FILELEN];
int ret = snprintf(filepath, FILELEN, "%s/%d/%s", PATH, pid, HEAP);
if (ret < 0)
{
return heap;
}
FILE *fp = fopen(filepath, "r");
if (!fp)
{
return heap;
}
char buf[25];
while (fgets(buf, 25, fp) != NULL)
{
if (strstr(buf, "AllocSize"))
{
int idx = strcspn(buf, "0123456789");
heap = strtoul(&buf[idx], NULL, 10);
break;
}
}
fclose(fp);
return heap;
}
static unsigned long get_stack(int pid)
{
unsigned long stack = 0;
char filepath[FILELEN];
int ret = snprintf(filepath, FILELEN, "%s/%d/%s", PATH, pid, STACK);
if (ret < 0)
{
return stack;
}
FILE *fp = fopen(filepath, "r");
if (!fp)
{
return stack;
}
char buf[25];
while (fgets(buf, 25, fp) != NULL)
{
if (strstr(buf, "StackUsed"))
{
int idx = strcspn(buf, "0123456789");
stack = strtoul(&buf[idx], NULL, 10);
break;
}
}
fclose(fp);
return stack;
}
static int get_total_info(struct t_info *t_info)
{
memset(t_info, 0, sizeof(struct t_info));
struct mallinfo g_alloc_info = mallinfo();
t_info->mem_total = g_alloc_info.arena;
t_info->mem_used = g_alloc_info.uordblks;
t_info->mem_free = g_alloc_info.fordblks;
t_info->mem_largest = g_alloc_info.mxordblk;
t_info->mem_nused = g_alloc_info.aordblks;
t_info->mem_nfree = g_alloc_info.ordblks;
t_info->mem_maxused = g_alloc_info.usmblks;
get_cpu(0, t_info->total_cpu);
return 0;
}
static int get_pid_info(struct p_info *p_info, int pid, bool all)
{
memset(p_info, 0, sizeof(struct p_info));
if (!all)
{
get_cpu(pid, p_info->cpu);
p_info->heap_used = get_heap(pid);
p_info->stack_used = get_stack(pid);
}
else
{
char filepath[FILELEN];
int ret = snprintf(filepath, FILELEN, "%s/%d/%s", PATH, pid, GROUP);
if (ret < 0)
{
return -1;
}
FILE *fp = fopen(filepath, "r");
if (!fp)
{
return -1;
}
char buf[100];
while (fgets(buf, 100, fp) != NULL)
{
if (strstr(buf, "Member IDs"))
{
int idx = strcspn(buf, ":");
char *p = strtok(&buf[idx], " ");
while ((p = strtok(NULL, " ")) != NULL)
{
int gpid = strtoul(p, NULL, 10);
char gcpu[8] = "0.0%%";
if (gpid > 0)
{
get_cpu(gpid, gcpu);
}
add_cpu(p_info->cpu, gcpu, p_info->cpu);
p_info->heap_used += get_heap(gpid);
p_info->stack_used += get_stack(gpid);
}
break;
}
}
fclose(fp);
}
return 0;
}
static void
print_result(struct t_info *t_info, struct p_info *p_info, char *logpath)
{
if (strlen(logpath) != 0)
{
time_t rawtime = 0;
struct tm info;
char date[30];
time(&rawtime);
localtime_r(&rawtime, &info);
strftime(date, 30, "[%Y-%m-%d %H:%M:%S] ", &info);
FILE *f;
if ((f = fopen(logpath, "a+")) != NULL)
{
if (p_head == 1)
{
p_head = 0;
if (p_info == NULL)
{
fprintf(f,
"%22s%13s%11s%11s%11s%11s%7s%7s%7s\n",
"",
"total",
"used",
"free",
"maxused",
"largest",
"nused",
"nfree",
"cpu");
}
else
{
fprintf(f,
"%22s%13s%11s%11s%11s%11s%7s%7s%7s%7s%11s%7s\n",
"",
"total",
"used",
"free",
"maxused",
"largest",
"nused",
"nfree",
"cpu",
"pstack",
"pheap",
"pcpu");
}
}
if (p_info == NULL)
{
fprintf(f,
"%-22s%13lu%11lu%11lu%11lu%11lu%7lu%7lu%7s\n",
date,
t_info->mem_total,
t_info->mem_used,
t_info->mem_free,
t_info->mem_maxused,
t_info->mem_largest,
t_info->mem_nused,
t_info->mem_nfree,
t_info->total_cpu);
}
else
{
fprintf(
f,
"%-22s%13lu%11lu%11lu%11lu%11lu%7lu%7lu%7s%7lu%11lu%7s\n",
date,
t_info->mem_total,
t_info->mem_used,
t_info->mem_free,
t_info->mem_maxused,
t_info->mem_largest,
t_info->mem_nused,
t_info->mem_nfree,
t_info->total_cpu,
p_info->stack_used,
p_info->heap_used,
p_info->cpu);
}
fclose(f);
}
else
{
syslog(LOG_ERR, "fopen logpath %s error \n", logpath);
}
return;
}
if (p_info == NULL)
{
syslog(LOG_INFO,
"%11s%11s%11s%11s%11s%7s%7s%7s\n",
"total",
"used",
"free",
"maxused",
"largest",
"nused",
"nfree",
"cpu");
syslog(LOG_INFO,
"%11lu%11lu%11lu%11lu%11lu%7lu%7lu%7s\n\n",
t_info->mem_total,
t_info->mem_used,
t_info->mem_free,
t_info->mem_maxused,
t_info->mem_largest,
t_info->mem_nused,
t_info->mem_nfree,
t_info->total_cpu);
}
else
{
syslog(LOG_INFO,
"%11s%11s%11s%11s%11s%7s%7s%7s%7s%11s%7s\n",
"total",
"used",
"free",
"maxused",
"largest",
"nused",
"nfree",
"cpu",
"pstack",
"pheap",
"pcpu");
syslog(LOG_INFO,
"%11lu%11lu%11lu%11lu%11lu%7lu%7lu%7s%7lu%11lu%7s\n\n",
t_info->mem_total,
t_info->mem_used,
t_info->mem_free,
t_info->mem_maxused,
t_info->mem_largest,
t_info->mem_nused,
t_info->mem_nfree,
t_info->total_cpu,
p_info->stack_used,
p_info->heap_used,
p_info->cpu);
}
}
static void transfer(uintmax_t value, char *res, int len)
{
memset(res, 0, len);
if (value > 1024 * 1024)
{
int ret = snprintf(res, len, "%ju", value / 1024 / 1024);
if (ret < 0)
{
return;
}
strcat(res, "M");
}
else if (value > 1024)
{
int ret = snprintf(res, len, "%ju", value / 1024);
if (ret < 0)
{
return;
}
strcat(res, "K");
}
else
{
int ret = snprintf(res, len, "%ju", value);
if (ret < 0)
{
return;
}
strcat(res, "B");
}
}
static void print_diskinfo(char *path, char *logpath)
{
struct statfs diskinfo;
int ret = statfs(path, &diskinfo);
if (ret != 0)
{
syslog(LOG_ERR, "statfs fail!\n");
return;
}
char c_tsize[20];
char c_asize[20];
char c_bsize[20];
char c_fsize[20];
uintmax_t bsize = (uintmax_t)diskinfo.f_bsize;
uintmax_t bavail = (uintmax_t)diskinfo.f_bavail;
uintmax_t blocks = (uintmax_t)diskinfo.f_blocks;
uintmax_t bfree = (uintmax_t)diskinfo.f_bfree;
transfer(bsize * blocks, c_tsize, 20);
transfer(bsize * bavail, c_asize, 20);
transfer(bsize * bfree, c_fsize, 20);
transfer(bsize, c_bsize, 20);
if (strlen(logpath) != 0)
{
time_t rawtime = 0;
struct tm info;
char date[30];
time(&rawtime);
localtime_r(&rawtime, &info);
strftime(date, 30, "[%Y-%m-%d %H:%M:%S] ", &info);
FILE *f;
if ((f = fopen(logpath, "a+")) != NULL)
{
if (d_head == 1)
{
d_head = 0;
fprintf(f,
"%22s%11s%11s%11s%11s%11s\n",
"",
"dir",
"total size",
"free size",
"avail size",
"block size");
}
fprintf(f,
"%-22s%11s%11s%11s%11s%11s\n",
date,
path,
c_tsize,
c_fsize,
c_asize,
c_bsize);
fclose(f);
}
else
{
syslog(LOG_ERR, "fopen logpath %s error \n", logpath);
}
}
else
{
syslog(LOG_INFO,
"%11s%11s%11s%11s%11s\n",
"dir",
"total size",
"free size",
"avail size",
"block size");
syslog(LOG_INFO,
"%11s%11s%11s%11s%11s\n\n",
path,
c_tsize,
c_fsize,
c_asize,
c_bsize);
}
}
int main(int argc, char *argv[])
{
if (argc == 1)
{
show_usages();
}
char filepath[FILELEN];
char logpath_l[FILELEN];
char logpath_k[FILELEN];
struct timeval sleeptime;
struct t_info total_info;
struct p_info pid_info;
int interval = 1;
int pid = -1;
bool all = false;
int ret;
int o;
memset(filepath, 0, FILELEN);
memset(logpath_l, 0, FILELEN);
memset(logpath_k, 0, FILELEN);
go = 1;
p_head = 1;
d_head = 1;
while ((o = getopt(argc, argv, "i:p:ad:l:k:")) != EOF)
{
switch (o)
{
case 'i':
interval = atoi(optarg);
break;
case 'p':
pid = atoi(optarg);
break;
case 'a':
all = true;
break;
case 'd':
snprintf(filepath, FILELEN, "%s", optarg);
break;
case 'l':
snprintf(logpath_l, FILELEN, "%s", optarg);
break;
case 'k':
snprintf(logpath_k, FILELEN, "%s", optarg);
break;
default:
show_usages();
break;
}
}
signal(SIGINT, handler);
signal(SIGKILL, handler);
while (go)
{
ret = get_total_info(&total_info);
if (ret < 0)
{
syslog(LOG_ERR, "get total info fail\n");
break;
}
if (pid > 0)
{
ret = get_pid_info(&pid_info, pid, all);
if (ret < 0)
{
syslog(LOG_ERR, "get pid info fail\n");
break;
}
}
if (all || pid > 0)
{
print_result(&total_info, &pid_info, logpath_l);
}
else
{
print_result(&total_info, NULL, logpath_l);
}
if (strlen(filepath) != 0)
{
print_diskinfo(filepath, logpath_k);
}
sleeptime.tv_sec = interval;
sleeptime.tv_usec = 0;
select(0, NULL, NULL, NULL, &sleeptime);
}
syslog(LOG_INFO, "program complete!\n");
return 0;
}