meminfo-writer.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include <fcntl.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <xs.h>
  6. #include <syslog.h>
  7. #include <string.h>
  8. #include <signal.h>
  9. unsigned long prev_used_mem;
  10. int used_mem_change_threshold;
  11. int delay;
  12. int usr1_received;
  13. char *parse(char *buf)
  14. {
  15. char *ptr = buf;
  16. char name[256];
  17. static char outbuf[4096];
  18. int val;
  19. int len;
  20. int MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapTotal =
  21. 0, SwapFree = 0;
  22. unsigned long long key;
  23. long used_mem, used_mem_diff;
  24. int nitems = 0;
  25. while (nitems != 6) {
  26. sscanf(ptr, "%s %d kB\n%n", name, &val, &len);
  27. key = *(unsigned long long *) ptr;
  28. if (key == *(unsigned long long *) "MemTotal:") {
  29. MemTotal = val;
  30. nitems++;
  31. } else if (key == *(unsigned long long *) "MemFree:") {
  32. MemFree = val;
  33. nitems++;
  34. } else if (key == *(unsigned long long *) "Buffers:") {
  35. Buffers = val;
  36. nitems++;
  37. } else if (key == *(unsigned long long *) "Cached: ") {
  38. Cached = val;
  39. nitems++;
  40. } else if (key == *(unsigned long long *) "SwapTotal:") {
  41. SwapTotal = val;
  42. nitems++;
  43. } else if (key == *(unsigned long long *) "SwapFree:") {
  44. SwapFree = val;
  45. nitems++;
  46. }
  47. ptr += len;
  48. }
  49. used_mem =
  50. MemTotal - Buffers - Cached - MemFree + SwapTotal - SwapFree;
  51. if (used_mem < 0)
  52. return NULL;
  53. used_mem_diff = used_mem - prev_used_mem;
  54. if (used_mem_diff < 0)
  55. used_mem_diff = -used_mem_diff;
  56. if (used_mem_diff > used_mem_change_threshold
  57. || (used_mem > prev_used_mem && used_mem * 13 / 10 > MemTotal
  58. && used_mem_diff > used_mem_change_threshold/2)) {
  59. prev_used_mem = used_mem;
  60. sprintf(outbuf,
  61. "MemTotal: %d kB\nMemFree: %d kB\nBuffers: %d kB\nCached: %d kB\n"
  62. "SwapTotal: %d kB\nSwapFree: %d kB\n", MemTotal,
  63. MemFree, Buffers, Cached, SwapTotal, SwapFree);
  64. return outbuf;
  65. }
  66. return NULL;
  67. }
  68. void usage()
  69. {
  70. fprintf(stderr,
  71. "usage: meminfo_writer threshold_in_kb delay_in_us [pidfile]\n");
  72. fprintf(stderr, " When pidfile set, meminfo-writer will:\n");
  73. fprintf(stderr, " - fork into background\n");
  74. fprintf(stderr, " - wait for SIGURS1 (in background) before starting main work\n");
  75. exit(1);
  76. }
  77. void send_to_qmemman(struct xs_handle *xs, char *data)
  78. {
  79. if (!xs_write(xs, XBT_NULL, "memory/meminfo", data, strlen(data))) {
  80. syslog(LOG_DAEMON | LOG_ERR, "error writing xenstore ?");
  81. exit(1);
  82. }
  83. }
  84. void usr1_handler(int sig) {
  85. usr1_received = 1;
  86. }
  87. int main(int argc, char **argv)
  88. {
  89. char buf[4096];
  90. int n;
  91. char *meminfo_data;
  92. int fd;
  93. struct xs_handle *xs;
  94. if (argc != 3 && argc != 4)
  95. usage();
  96. used_mem_change_threshold = atoi(argv[1]);
  97. delay = atoi(argv[2]);
  98. if (!used_mem_change_threshold || !delay)
  99. usage();
  100. if (argc == 4) {
  101. pid_t pid;
  102. sigset_t mask, oldmask;
  103. switch (pid = fork()) {
  104. case -1:
  105. perror("fork");
  106. exit(1);
  107. case 0:
  108. sigemptyset (&mask);
  109. sigaddset (&mask, SIGUSR1);
  110. /* Wait for a signal to arrive. */
  111. sigprocmask (SIG_BLOCK, &mask, &oldmask);
  112. usr1_received = 0;
  113. signal(SIGUSR1, usr1_handler);
  114. while (!usr1_received)
  115. sigsuspend (&oldmask);
  116. sigprocmask (SIG_UNBLOCK, &mask, NULL);
  117. break;
  118. default:
  119. fd = open(argv[3], O_CREAT | O_TRUNC | O_WRONLY, 0666);
  120. if (fd < 0) {
  121. perror("open pidfile");
  122. exit(1);
  123. }
  124. n = sprintf(buf, "%d\n", pid);
  125. if (write(fd, buf, n) != n) {
  126. perror("write pid");
  127. exit(1);
  128. }
  129. close(fd);
  130. exit(0);
  131. }
  132. }
  133. fd = open("/proc/meminfo", O_RDONLY);
  134. if (fd < 0) {
  135. perror("open meminfo");
  136. exit(1);
  137. }
  138. xs = xs_domain_open();
  139. if (!xs) {
  140. perror("xs_domain_open");
  141. exit(1);
  142. }
  143. if (argc == 3) {
  144. /* if not waiting for signal, fork after first info written to xenstore */
  145. n = pread(fd, buf, sizeof(buf), 0);
  146. buf[n] = 0;
  147. meminfo_data = parse(buf);
  148. if (meminfo_data)
  149. send_to_qmemman(xs, meminfo_data);
  150. if (fork() > 0)
  151. exit(0);
  152. }
  153. for (;;) {
  154. n = pread(fd, buf, sizeof(buf), 0);
  155. buf[n] = 0;
  156. meminfo_data = parse(buf);
  157. if (meminfo_data)
  158. send_to_qmemman(xs, meminfo_data);
  159. usleep(delay);
  160. }
  161. }