mem.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <time.h>
  6. #include <sys/sysinfo.h>
  7. #include <sys/types.h>
  8. #include <fcntl.h>
  9. #include <errno.h>
  10. #include <signal.h>
  11. #define MAX_LINE 256
  12. #define DEFAULT_INTERVAL 10
  13. #define DEFAULT_DURATION 0
  14. #define FLUSH_INTERVAL 5 // 每5次写入刷新一次文件
  15. volatile sig_atomic_t stop = 0;
  16. void handle_signal(int sig) {
  17. stop = 1;
  18. }
  19. // 低内存方式获取系统内存信息
  20. int get_memory_info(unsigned long* total, unsigned long* available,
  21. unsigned long* buffers, unsigned long* cached) {
  22. FILE* fp = fopen("/proc/meminfo", "r");
  23. if (!fp) return -1;
  24. char line[MAX_LINE];
  25. *total = *available = *buffers = *cached = 0;
  26. while (fgets(line, sizeof(line), fp)) {
  27. if (strncmp(line, "MemTotal:", 9) == 0) sscanf(line+9, "%lu", total);
  28. else if (strncmp(line, "MemAvailable:", 13) == 0) sscanf(line+13, "%lu", available);
  29. else if (strncmp(line, "Buffers:", 8) == 0) sscanf(line+8, "%lu", buffers);
  30. else if (strncmp(line, "Cached:", 7) == 0) sscanf(line+7, "%lu", cached);
  31. }
  32. fclose(fp);
  33. return 0;
  34. }
  35. // 低内存方式获取进程内存信息
  36. int get_process_mem(pid_t pid, unsigned long* rss, unsigned long* vsz) {
  37. char path[MAX_LINE];
  38. snprintf(path, sizeof(path), "/proc/%d/statm", pid);
  39. FILE* fp = fopen(path, "r");
  40. if (!fp) return -1;
  41. if (fscanf(fp, "%lu %lu", vsz, rss) != 2) {
  42. fclose(fp);
  43. return -1;
  44. }
  45. fclose(fp);
  46. long page_kb = sysconf(_SC_PAGESIZE) / 1024;
  47. *vsz *= page_kb;
  48. *rss *= page_kb;
  49. return 0;
  50. }
  51. // 最小化内存占用的CSV写入
  52. void write_csv_entry(FILE* csv, const char* name, pid_t pid,
  53. unsigned long rss, unsigned long vsz,
  54. unsigned long total, unsigned long avail,
  55. unsigned long buf, unsigned long cache) {
  56. time_t now = time(NULL);
  57. struct tm* tm = localtime(&now);
  58. // 直接格式化输出到文件,减少内存缓冲
  59. fprintf(csv, "%04d-%02d-%02d %02d:%02d:%02d,%s,%d,%lu,%lu,%lu,%lu,%lu,%lu\n",
  60. tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
  61. tm->tm_hour, tm->tm_min, tm->tm_sec,
  62. name, pid, rss, vsz, total, avail, buf, cache);
  63. }
  64. int main(int argc, char** argv) {
  65. if (argc < 4) {
  66. printf("Usage: %s <name> <pid> <output.csv> [interval=10] [duration=0]\n", argv[0]);
  67. return 1;
  68. }
  69. signal(SIGINT, handle_signal);
  70. signal(SIGTERM, handle_signal);
  71. const char* name = argv[1];
  72. pid_t pid = atoi(argv[2]);
  73. const char* outfile = argv[3];
  74. int interval = argc > 4 ? atoi(argv[4]) : DEFAULT_INTERVAL;
  75. int duration = argc > 5 ? atoi(argv[5]) : DEFAULT_DURATION;
  76. if (interval <= 0) interval = DEFAULT_INTERVAL;
  77. // 以最小缓冲模式打开文件
  78. FILE* csv = fopen(outfile, "a");
  79. if (!csv) {
  80. perror("Failed to open output file");
  81. return 1;
  82. }
  83. // 设置文件缓冲模式为行缓冲
  84. setvbuf(csv, NULL, _IOLBF, 0);
  85. // 如果是新文件,写入表头
  86. if (ftell(csv) == 0) {
  87. fprintf(csv, "Timestamp,Process,PID,RSS(KB),VSZ(KB),Total(KB),Available(KB),Buffers(KB),Cached(KB)\n");
  88. }
  89. time_t start = time(NULL);
  90. int count = 0;
  91. printf("Monitoring %s (PID: %d), logging to %s\n", name, pid, outfile);
  92. printf("Interval: %ds, Duration: %ds\n", interval, duration);
  93. while (!stop) {
  94. unsigned long rss, vsz, total, avail, buf, cache;
  95. if (get_process_mem(pid, &rss, &vsz)) {
  96. fprintf(stderr, "Failed to get process memory\n");
  97. } else if (get_memory_info(&total, &avail, &buf, &cache)) {
  98. fprintf(stderr, "Failed to get system memory\n");
  99. } else {
  100. write_csv_entry(csv, name, pid, rss, vsz, total, avail, buf, cache);
  101. count++;
  102. // 定期刷新文件缓冲
  103. if (count % FLUSH_INTERVAL == 0) {
  104. fflush(csv);
  105. }
  106. printf(".");
  107. fflush(stdout);
  108. }
  109. // 检查是否达到总时长
  110. if (duration > 0 && (time(NULL) - start) >= duration) {
  111. printf("\nReached specified duration\n");
  112. break;
  113. }
  114. // 更精确的睡眠控制
  115. time_t next = time(NULL) + interval;
  116. while (time(NULL) < next && !stop) {
  117. sleep(1);
  118. }
  119. }
  120. fclose(csv);
  121. printf("\nMonitoring stopped. %d records written.\n", count);
  122. return 0;
  123. }