/**************************************************************************** * apps/system/resmonitor/filldisk.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 #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; }