diff --git a/testing/resmonitor/CMakeLists.txt b/testing/resmonitor/CMakeLists.txt new file mode 100644 index 0000000000..38f94064e4 --- /dev/null +++ b/testing/resmonitor/CMakeLists.txt @@ -0,0 +1,63 @@ +# ############################################################################## +# apps/testing/resmonitor/CMakeLists.txt +# +# 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. +# +# ############################################################################## + +if(CONFIG_TESTING_RESMONITOR) + nuttx_add_application( + NAME + showinfo + SRCS + showinfo.c + STACKSIZE + ${CONFIG_TESTING_RESMONITOR_STACKSIZE} + PRIORITY + ${CONFIG_TESTING_RESMONITOR_PRIORITY}) + + if(CONFIG_TESTING_RESMONITOR_FILL) + nuttx_add_application( + NAME + filldisk + SRCS + filldisk.c + STACKSIZE + ${CONFIG_TESTING_RESMONITOR_STACKSIZE} + PRIORITY + ${CONFIG_TESTING_RESMONITOR_PRIORITY}) + + nuttx_add_application( + NAME + fillcpu + SRCS + fillcpu.c + STACKSIZE + ${CONFIG_TESTING_RESMONITOR_STACKSIZE} + PRIORITY + ${CONFIG_TESTING_RESMONITOR_PRIORITY}) + + nuttx_add_application( + NAME + fillmem + SRCS + fillmem.c + STACKSIZE + ${CONFIG_TESTING_RESMONITOR_STACKSIZE} + PRIORITY + ${CONFIG_TESTING_RESMONITOR_PRIORITY}) + endif() +endif() diff --git a/testing/resmonitor/Kconfig b/testing/resmonitor/Kconfig new file mode 100644 index 0000000000..5b577bf585 --- /dev/null +++ b/testing/resmonitor/Kconfig @@ -0,0 +1,27 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config TESTING_RESMONITOR + bool "enable resource monitor [showinfo]" + default n + ---help--- + Enable resource show with specific duration. + Should not use with LOW_RESOURCE_TEST at the same time. + +if TESTING_RESMONITOR + +config TESTING_RESMONITOR_PRIORITY + int "Task priority" + default 100 + +config TESTING_RESMONITOR_STACKSIZE + int "Stack size" + default 4096 + +config TESTING_RESMONITOR_FILL + bool "[filldisk/fillcpu/fillmem]" + default n + +endif diff --git a/testing/resmonitor/Make.defs b/testing/resmonitor/Make.defs new file mode 100644 index 0000000000..a111ad4c89 --- /dev/null +++ b/testing/resmonitor/Make.defs @@ -0,0 +1,24 @@ +############################################################################ +# apps/testing/resmonitor/Make.defs +# +# 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. +# +# +############################################################################ + +ifneq ($(CONFIG_TESTING_RESMONITOR),) +CONFIGURED_APPS += $(APPDIR)/testing/resmonitor +endif diff --git a/testing/resmonitor/Makefile b/testing/resmonitor/Makefile new file mode 100644 index 0000000000..a5d7d352f7 --- /dev/null +++ b/testing/resmonitor/Makefile @@ -0,0 +1,33 @@ +# apps/testing/resmonitor/Makefile +# +# Licensed 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. + +include $(APPDIR)/Make.defs + +PRIORITY = $(CONFIG_TESTING_RESMONITOR_PRIORITY) +STACKSIZE = $(CONFIG_TESTING_RESMONITOR_STACKSIZE) +MODULE = $(CONFIG_TESTING_RESMONITOR) + +PROGNAME += showinfo +MAINSRC += $(CURDIR)/showinfo.c + +ifeq ($(CONFIG_TESTING_RESMONITOR_FILL),y) +PROGNAME += filldisk +MAINSRC += $(CURDIR)/filldisk.c +PROGNAME += fillcpu +MAINSRC += $(CURDIR)/fillcpu.c +PROGNAME += fillmem +MAINSRC += $(CURDIR)/fillmem.c +endif + +include $(APPDIR)/Application.mk diff --git a/testing/resmonitor/fillcpu.c b/testing/resmonitor/fillcpu.c new file mode 100644 index 0000000000..024219b310 --- /dev/null +++ b/testing/resmonitor/fillcpu.c @@ -0,0 +1,232 @@ +/**************************************************************************** + * apps/testing/resmonitor/fillcpu.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PATH "/proc" +#define CPULOAD "cpuload" +#define LOADAVG "loadavg" + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int go = 1; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void handler(int sig) +{ + go = 0; +} + +static void show_usages(void) +{ + syslog(LOG_WARNING, + "Usage: CMD [-c ] [-f ] [-a]\n" + "\t\t-c: set cpu occupation that you except, default 80\n" + "\t\t-f: set write payload path, eg. /tmp/payload, program will " + "write to memory if -f not set\n" + "\t\t-a: the cpu (set by -c) is the cpu occupied by this program\n"); + exit(1); +} + +static float get_cpu(int pid) +{ + float cpu = 0; + char filepath[20]; + int ret; + if (pid <= 0) + { + ret = snprintf(filepath, 20, "%s/%s", PATH, CPULOAD); + } + else + { + ret = snprintf(filepath, 20, "%s/%d/%s", PATH, pid, LOADAVG); + } + + if (ret < 0) + { + /* syslog(LOG_ERR, "snprintf error\n"); */ + + return cpu; + } + + FILE *fp = fopen(filepath, "r"); + if (!fp) + { + return cpu; + } + + char buf[8]; + fgets(buf, 8, fp); + sscanf(buf, "%f", &cpu); + fclose(fp); + return cpu; +} + +static int writefile(char *filepath, char *buffer1, char *buffer2) +{ + if (strlen(filepath) == 0) + { + memset(buffer2, '*', 1024); + memcpy(buffer1, buffer2, 1024); + return 0; + } + else + { + int fd; + memset(buffer1, '*', 1024); + if ((fd = open(filepath, O_WRONLY | O_CREAT, 0700)) <= 0) + { + syslog(LOG_ERR, "open file error\n"); + return -1; + } + + if (write(fd, buffer1, 1024) <= 0) + { + syslog(LOG_ERR, "write file error\n"); + close(fd); + return -1; + } + + return close(fd); + } +} + +int main(int argc, char *argv[]) +{ + char buf1[1024]; + char buf2[1024]; + char filepath[40]; + struct timeval sleeptime; + int n = 0; + int lowcount = 0; + int cpu = 80; + bool ispid = false; + int time = 10000; + float fcpu; + int o; + + memset(filepath, 0, 40); + go = 1; + if (argc == 1) + { + show_usages(); + } + + while ((o = getopt(argc, argv, "c:f:a")) != EOF) + { + switch (o) + { + case 'c': + cpu = atoi(optarg); + break; + case 'f': + snprintf(filepath, 40, "%s", optarg); + break; + case 'a': + ispid = true; + break; + default: + show_usages(); + break; + } + } + + signal(SIGINT, handler); + signal(SIGKILL, handler); + + while (go) + { + if (time < 1000) + { + time = 1000; + lowcount++; + if (lowcount > 4) + { + lowcount = 0; + n += 2; + } + } + + else if (time > 10000) + { + time = 10000; + n -= 1; + n = (n < 0 ? 0 : n); + } + else + { + lowcount = 0; + } + + sleeptime.tv_sec = 0; + sleeptime.tv_usec = time; + select(0, NULL, NULL, NULL, &sleeptime); + if (ispid) + { + fcpu = get_cpu(getpid()); + } + else + { + fcpu = get_cpu(0); + } + + if (fcpu > cpu) + { + time += 1000; + } + else + { + time -= 1000; + } + + for (int i = 0; i < n; i++) + { + if (writefile(filepath, buf1, buf2) != 0) + { + break; + } + } + } + + syslog(LOG_INFO, "program complete!\n"); + return 0; +} diff --git a/testing/resmonitor/filldisk.c b/testing/resmonitor/filldisk.c new file mode 100644 index 0000000000..5f7b6618cb --- /dev/null +++ b/testing/resmonitor/filldisk.c @@ -0,0 +1,404 @@ +/**************************************************************************** + * apps/testing/resmonitor/filldisk.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PATHSIZE 70 +#define FILESIZE 100 +#define FILENAME "testpayload" +#define INTERVAL 0 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static time_t interval = INTERVAL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int getdiv(uintmax_t count) +{ + int div = 1000; + if (count > 1000) + { + div = 1000; + } + else if (count > 100) + { + div = 100; + } + else if (count > 10) + { + div = 10; + } + else + { + div = 1; + } + + return div; +} + +static uintmax_t +get_fillsize(char *filepath, int mode, uintmax_t remain, uintmax_t fill) +{ + struct statfs diskinfo; + int ret = statfs(filepath, &diskinfo); + if (ret != 0) + { + syslog(LOG_ERR, "statfs fail!\n"); + return -1; + } + + uintmax_t bsize = (uintmax_t)diskinfo.f_bsize; + uintmax_t bavail = (uintmax_t)diskinfo.f_bavail; + uintmax_t t_size = bsize * bavail; + uintmax_t fillsize = 0; + if (mode == 1) + { + fillsize = t_size - remain; + } + else if (mode == 2) + { + fillsize = (fill < t_size) ? fill : t_size; + } + + return fillsize; +} + +static clock_t fill_disk(char *file, uintmax_t bufsize, int mode, + uintmax_t remain, uintmax_t fill) +{ + FILE *fp; + clock_t start, finish; + struct timeval sleeptime; + int ret; + if ((fp = fopen(file, "a+")) == NULL) + { + syslog(LOG_ERR, "Fail to open file!\n"); + return -1; + } + + uintmax_t fillsize = get_fillsize(file, mode, remain, fill); + if (fillsize <= 0) + { + syslog(LOG_WARNING, "out of space !!\n"); + fclose(fp); + return -1; + } + + char *buf = (char *)malloc((size_t)bufsize); + if (!buf) + { + syslog(LOG_ERR, "malloc fail, errno %d\n", errno); + fclose(fp); + return -1; + } + + memset(buf, 'a', (size_t)bufsize); + uintmax_t count = fillsize / bufsize; + int div = getdiv(count); + start = clock(); + while (fillsize > bufsize) + { + ret = fwrite(buf, 1, bufsize, fp); + if (ret > 0) + { + fillsize -= ret; + count--; + } + else + { + syslog(LOG_ERR, "write fail \n"); + fclose(fp); + free(buf); + return -1; + } + + sleeptime.tv_sec = interval / 1000000; + sleeptime.tv_usec = interval % 1000000; + select(0, NULL, NULL, NULL, &sleeptime); + if (count % div == 0) + { + syslog(LOG_INFO, "remain %ju B\n", fillsize); + fillsize = get_fillsize(file, mode, remain, fillsize); + if (fillsize < 0) + { + syslog(LOG_WARNING, "out of space !!\n"); + fclose(fp); + free(buf); + return -1; + } + + count = fillsize / bufsize; + div = getdiv(count); + } + } + + fwrite(buf, 1, fillsize, fp); + fflush(fp); + finish = clock(); + syslog(LOG_INFO, "write complete !!!\n"); + fclose(fp); + free(buf); + return finish - start; +} + +static void show_usages(void) +{ + syslog(LOG_WARNING, + "Usage: CMD [-d ] [-f ] [-r ] [-b " + "] [-n ] [-i ]\n" + "\t\t-d: set dir to fill (e.g. /data)\n" + "\t\t-f: set fill file size, can end with KkMm, (disabled if -r is " + "set)\n" + "\t\t-n: works only if -f is set, create n files of size -f set, " + "default 1\n" + "\t\t-r: set remain size, can end with KkMm\n" + "\t\t-b: set write buf size, can end with kKMm, default is f_bsize\n" + "\t\t-i: set write intervals (us), default 0 us, set only if the " + "program killed by wdt\n"); + exit(1); +} + +static void double2str(double f, char *s, int len) +{ + int ret = snprintf(s, len, "%.2lf", f); + if (ret < 0) + { + syslog(LOG_ERR, "double to str fail, ret %d\n", ret); + } +} + +static uintmax_t bytes(char *s) +{ + uintmax_t n; + if (sscanf(s, "%ju", &n) < 1) + { + return 0; + } + + if ((s[strlen(s) - 1] == 'k') || (s[strlen(s) - 1] == 'K')) + { + n *= 1024; + } + + if ((s[strlen(s) - 1] == 'm') || (s[strlen(s) - 1] == 'M')) + { + n *= (1024 * 1024); + } + + return n; +} + +static void print_disk_info(struct statfs *diskinfo) +{ + syslog(LOG_INFO, "\tfs block size : %zu\n", diskinfo->f_bsize); + syslog(LOG_INFO, + "\tfs block nums : %" PRIu64 "\n", + (uint64_t)diskinfo->f_blocks); + syslog(LOG_INFO, + "\tfs free blocks : %" PRIu64 "\n", + (uint64_t)diskinfo->f_bfree); + syslog(LOG_INFO, + "\tfs free blocks available : %" PRIu64 "\n", + (uint64_t)diskinfo->f_bavail); + syslog(LOG_INFO, + "\tfs total file nodes : %" PRIu64 "\n", + (uint64_t)diskinfo->f_files); + syslog(LOG_INFO, + "\tfs free file nodes : %" PRIu64 "\n", + (uint64_t)diskinfo->f_ffree); +} + +int main(int argc, FAR char *argv[]) +{ + if (argc == 1) + { + show_usages(); + return -1; + } + + char filepath[PATHSIZE]; + char sduration_t[15]; + char sduration_w[15]; + char sspeed_t[15]; + char sspeed_w[15]; + uintmax_t fill = 0; + uintmax_t remain = 0; + uintmax_t bufsize = 0; + int nf = 1; + int mode = 0; + clock_t write_t = 0; + struct statfs diskinfo_old; + struct statfs diskinfo_new; + uintmax_t fillsize; + double duration_t; + double speed_t; + double duration_w; + double speed_w; + clock_t start; + clock_t finish; + clock_t tmp; + int ret; + int o; + + interval = INTERVAL; + memset(filepath, 0, PATHSIZE); + while ((o = getopt(argc, argv, "d:f:r:b:i:n:")) != EOF) + { + switch (o) + { + case 'd': + snprintf(filepath, PATHSIZE, "%s", optarg); + break; + case 'f': + fill = bytes(optarg); + if (mode != 1) + { + mode = 2; + } + + break; + case 'r': + remain = bytes(optarg); + mode = 1; + break; + case 'i': + interval = (time_t)bytes(optarg); + break; + case 'b': + bufsize = bytes(optarg); + break; + case 'n': + nf = atoi(optarg); + break; + default: + show_usages(); + break; + } + } + + if (strlen(filepath) == 0) + { + syslog(LOG_ERR, "please set dir \n"); + return -1; + } + + if (mode == 0) + { + syslog(LOG_ERR, "please set -f or -r \n"); + return -1; + } + else if (mode != 2) + { + nf = 1; + } + + ret = statfs(filepath, &diskinfo_old); + if (ret != 0) + { + syslog(LOG_ERR, "statfs fail!\n"); + return -1; + } + + if (bufsize == 0) + { + bufsize = diskinfo_old.f_bsize; + } + + fillsize = get_fillsize(filepath, mode, remain, fill) * nf; + syslog(LOG_INFO, "outputfilepath: %s\n", filepath); + start = clock(); + for (int i = 1; i <= nf; i++) + { + syslog(LOG_INFO, "create file %d, total %d\n", i, nf); + char file[FILESIZE]; + ret = snprintf(file, FILESIZE, "%s/%s%d", filepath, FILENAME, i); + if (ret < 0) + { + syslog(LOG_ERR, "snprintf err, ret %d\n", ret); + return -1; + } + + if ((tmp = fill_disk(file, bufsize, mode, remain, fill)) > 0) + { + write_t += tmp; + } + else + { + syslog(LOG_ERR, "fill disk error\n"); + return -1; + } + } + + finish = clock(); + ret = statfs(filepath, &diskinfo_new); + if (ret != 0) + { + syslog(LOG_ERR, "statfs fail!\n"); + return -1; + } + + syslog(LOG_INFO, "***diskinfo before filldisk***\n"); + print_disk_info(&diskinfo_old); + + syslog(LOG_INFO, "***diskinfo after filldisk***\n"); + print_disk_info(&diskinfo_new); + duration_t = (double)(finish - start) / CLOCKS_PER_SEC; + speed_t = fillsize / 1024.0 / duration_t; + duration_w = (double)(write_t) / CLOCKS_PER_SEC; + speed_w = fillsize / 1024.0 / duration_w; + double2str(speed_t, sspeed_t, 15); + double2str(speed_w, sspeed_w, 15); + double2str(duration_t, sduration_t, 15); + double2str(duration_w, sduration_w, 15); + syslog(LOG_INFO, "fill buf size: %ju\n", bufsize); + syslog(LOG_INFO, "total fill size: %ju\n", fillsize); + syslog(LOG_INFO, + "write speed (include open and close) %s KB/s, duration %s s\n", + sspeed_t, + sduration_t); + syslog(LOG_INFO, + "write speed (only write) %s KB/s, duration %s s\n", + sspeed_w, + sduration_w); + return 0; +} diff --git a/testing/resmonitor/fillmem.c b/testing/resmonitor/fillmem.c new file mode 100644 index 0000000000..7f96203178 --- /dev/null +++ b/testing/resmonitor/fillmem.c @@ -0,0 +1,255 @@ +/**************************************************************************** + * apps/testing/resmonitor/fillmem.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define PAYLOADSIZE 100 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int go = 1; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void handler(int sig) +{ + go = 0; +} + +static void show_usages(void) +{ + syslog(LOG_WARNING, + "Usage: CMD [-f ] [-r ]\n" + "\t\t-f: set fill mem size, can end with KkMm, (disabled if -r " + "is set)\n" + "\t\t-r: set remain size, can end with KkMm\n" + "\t\t-p: set percentage occupancy\n"); + exit(1); +} + +static uintmax_t bytes(char *s) +{ + uintmax_t n; + if (sscanf(s, "%ju", &n) < 1) + { + return 0; + } + + if ((s[strlen(s) - 1] == 'k') || (s[strlen(s) - 1] == 'K')) + { + n *= 1024; + } + + if ((s[strlen(s) - 1] == 'm') || (s[strlen(s) - 1] == 'M')) + { + n *= (1024 * 1024); + } + + return n; +} + +int main(int argc, char *argv[]) +{ + struct mallinfo g_alloc_info; + size_t fill_size = 0; + size_t remain_size = 0; + size_t free_mem = 0; + size_t largest_mem = 0; + size_t total_mem = 0; + size_t used_mem = 0; + float fill_percentage = 0; + char *payloads[PAYLOADSIZE]; + int idx = 0; + go = 1; + struct timeval sleeptime; + memset(payloads, 0, sizeof(payloads)); + int mode = 0; + if (argc == 1) + { + show_usages(); + } + + int o; + while ((o = getopt(argc, argv, "r:f:p:")) != EOF) + { + switch (o) + { + case 'r': + remain_size = (size_t)bytes(optarg); + mode = 1; + break; + case 'f': + fill_size = (size_t)bytes(optarg); + break; + case 'p': + fill_percentage = atof(optarg); + mode = 2; + break; + default: + show_usages(); + break; + } + } + + g_alloc_info = mallinfo(); + total_mem = (size_t)g_alloc_info.arena; + free_mem = (size_t)g_alloc_info.fordblks; + largest_mem = (size_t)g_alloc_info.mxordblk; + used_mem = (size_t)g_alloc_info.uordblks; + if (mode == 2) + { + size_t per_fill = (size_t)total_mem * fill_percentage; + syslog(LOG_INFO, "per fill is %zu\n", per_fill); + fill_size = per_fill - used_mem; + if (fill_size < 0) + { + syslog(LOG_WARNING, + "memory has used %zu, has exceed %f\n", + used_mem, + fill_percentage); + return 0; + } + + mode = 0; + } + + if (remain_size != 0 || mode == 1) + { + if (remain_size > free_mem) + { + syslog(LOG_INFO, + "remain is greater than free, remain %zu, free %zu\n", + remain_size, + free_mem); + return 0; + } + + fill_size = free_mem - remain_size; + } + + if (fill_size > free_mem) + { + syslog(LOG_INFO, + "no enough mem, fill %zu, free %zu\n", + fill_size, + free_mem); + return 0; + } + + syslog(LOG_INFO, + "fill size %zu, free %zu, largest %zu\n", + fill_size, + free_mem, + largest_mem); + if (fill_size <= largest_mem) + { + payloads[0] = malloc(fill_size - 100); + if (payloads[0] == NULL) + { + syslog(LOG_ERR, "malloc fail, errno %d\n", errno); + goto END; + } + + syslog(LOG_INFO, "malloc size %zu\n", fill_size); + } + else + { + while ((fill_size > largest_mem) && (idx < PAYLOADSIZE - 1)) + { + if (largest_mem <= 150) + { + break; + } + + payloads[idx] = malloc(largest_mem - 100); + if (payloads[idx] == NULL) + { + syslog(LOG_ERR, "malloc fail, errno %d\n", errno); + goto END; + } + + fill_size -= largest_mem; + syslog(LOG_INFO, "idx: %d, malloc size %zu\n", idx, largest_mem); + g_alloc_info = mallinfo(); + largest_mem = (size_t)g_alloc_info.mxordblk; + idx++; + } + + if (largest_mem > 100) + { + if (largest_mem - fill_size <= 100) + { + fill_size = largest_mem - 100; + } + + payloads[idx] = malloc(fill_size); + if (payloads[idx] == NULL) + { + syslog(LOG_ERR, "malloc fail, errno %d\n", errno); + goto END; + } + + syslog(LOG_INFO, "idx: %d, malloc size %zu\n", idx, fill_size); + } + } + + signal(SIGINT, handler); + signal(SIGKILL, handler); + while (go) + { + sleeptime.tv_sec = 600; + sleeptime.tv_usec = 0; + select(0, NULL, NULL, NULL, &sleeptime); + } + + syslog(LOG_INFO, "program complete!\n"); +END: + for (int i = 0; i < PAYLOADSIZE; i++) + { + if (payloads[i] != NULL) + { + free(payloads[i]); + } + } + + return 0; +} diff --git a/testing/resmonitor/showinfo.c b/testing/resmonitor/showinfo.c new file mode 100644 index 0000000000..44a04471a8 --- /dev/null +++ b/testing/resmonitor/showinfo.c @@ -0,0 +1,648 @@ +/**************************************************************************** + * apps/testing/resmonitor/showinfo.c + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * 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 Type Declarations + ****************************************************************************/ + +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 ] [-p ] [-a] [-d ] [-l " + "] [-k ]\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; +}