#include #include #include #include #ifdef USE_XENSTORE_H /* Xen >= 4.2 */ #include #else #include #endif #include #include #include long prev_used_mem; int used_mem_change_threshold; int delay; int usr1_received; const char *parse(const char *meminfo_buf, const char* dom_current_buf) { const char *ptr = meminfo_buf; static char outbuf[4096]; long long val; int len; int ret; long long MemTotal = 0, MemFree = 0, Buffers = 0, Cached = 0, SwapTotal = 0, SwapFree = 0; unsigned long long key; long long used_mem, used_mem_diff; int nitems = 0; while (nitems != (1<<6)-1 || !*ptr) { ret = sscanf(ptr, "%*s %lld kB\n%n", &val, &len); if (ret < 1 || len < (int)sizeof (unsigned long long)) { ptr += len; continue; } key = *(unsigned long long *) ptr; if (key == *(unsigned long long *) "MemTotal:") { MemTotal = val; nitems |= 1; } else if (key == *(unsigned long long *) "MemFree:") { MemFree = val; nitems |= 2; } else if (key == *(unsigned long long *) "Buffers:") { Buffers = val; nitems |= 4; } else if (key == *(unsigned long long *) "Cached: ") { Cached = val; nitems |= 8; } else if (key == *(unsigned long long *) "SwapTotal:") { SwapTotal = val; nitems |= 16; } else if (key == *(unsigned long long *) "SwapFree:") { SwapFree = val; nitems |= 32; } ptr += len; } if(dom_current_buf) { long long DomTotal = strtoll(dom_current_buf, 0, 10); if(DomTotal) MemTotal = DomTotal; } used_mem = MemTotal - Buffers - Cached - MemFree + SwapTotal - SwapFree; if (used_mem < 0) return NULL; used_mem_diff = used_mem - prev_used_mem; if (used_mem_diff < 0) used_mem_diff = -used_mem_diff; if (used_mem_diff > used_mem_change_threshold || prev_used_mem == 0 || (used_mem > prev_used_mem && used_mem / 10 > (MemTotal+12) / 13 && used_mem_diff > used_mem_change_threshold/2)) { prev_used_mem = used_mem; sprintf(outbuf, "%lld", used_mem); return outbuf; } return NULL; } void usage(void) { fprintf(stderr, "usage: meminfo_writer threshold_in_kb delay_in_us [pidfile]\n"); fprintf(stderr, " When pidfile set, meminfo-writer will:\n"); fprintf(stderr, " - fork into background\n"); fprintf(stderr, " - wait for SIGUSR1 (in background) before starting main work\n"); exit(1); } void send_to_qmemman(struct xs_handle *xs, const char *data) { if (!xs_write(xs, XBT_NULL, "memory/meminfo", data, strlen(data))) { syslog(LOG_DAEMON | LOG_ERR, "error writing xenstore ?"); exit(1); } } void usr1_handler(int sig __attribute__((__unused__))) { usr1_received = 1; } static inline void pread0_string(int fd, char* buf, size_t buf_size) { int n = pread(fd, buf, buf_size - 1, 0); if (n < 0) { perror("pread"); exit(1); } buf[n] = 0; } static void update(struct xs_handle *xs, int meminfo_fd, int dom_current_fd) { char dom_current_buf[32]; char dom_current_buf2[32]; char meminfo_buf[4096]; const char *meminfo_data; pread0_string(dom_current_fd, dom_current_buf, sizeof(dom_current_buf)); /* check until the dom current reading is stable to avoid races */ for(;;) { pread0_string(meminfo_fd, meminfo_buf, sizeof(meminfo_buf)); pread0_string(dom_current_fd, dom_current_buf2, sizeof(dom_current_buf2)); if(!strcmp(dom_current_buf, dom_current_buf2)) break; pread0_string(meminfo_fd, meminfo_buf, sizeof(meminfo_buf)); pread0_string(dom_current_fd, dom_current_buf, sizeof(dom_current_buf)); if(!strcmp(dom_current_buf, dom_current_buf2)) break; } meminfo_data = parse(meminfo_buf, dom_current_buf); if (meminfo_data) send_to_qmemman(xs, meminfo_data); } int main(int argc, char **argv) { int meminfo_fd, dom_current_fd; struct xs_handle *xs; int n; if (argc != 3 && argc != 4) usage(); used_mem_change_threshold = atoi(argv[1]); delay = atoi(argv[2]); if (used_mem_change_threshold <= 0 || delay <= 0) usage(); if (argc == 4) { pid_t pid; sigset_t mask, oldmask; int fd; char buf[32]; switch (pid = fork()) { case -1: perror("fork"); exit(1); case 0: sigemptyset (&mask); sigaddset (&mask, SIGUSR1); /* Wait for a signal to arrive. */ sigprocmask (SIG_BLOCK, &mask, &oldmask); usr1_received = 0; signal(SIGUSR1, usr1_handler); while (!usr1_received) sigsuspend (&oldmask); sigprocmask (SIG_UNBLOCK, &mask, NULL); break; default: fd = open(argv[3], O_CREAT | O_TRUNC | O_WRONLY, 0666); if (fd < 0) { perror("open pidfile"); kill(pid,9); exit(1); } n = sprintf(buf, "%d\n", pid); if (write(fd, buf, n) != n) { perror("write pid"); kill(pid,9); exit(1); } close(fd); exit(0); } } meminfo_fd = open("/proc/meminfo", O_RDONLY); if (meminfo_fd < 0) { perror("open /proc/meminfo"); exit(1); } dom_current_fd = open("/sys/devices/system/xen_memory/xen_memory0/info/current_kb", O_RDONLY); if (dom_current_fd < 0) { perror("open /sys/devices/system/xen_memory/xen_memory0/info/current_kb"); exit(1); } xs = xs_domain_open(); if (!xs) { perror("xs_domain_open"); exit(1); } if (argc == 3) { /* if not waiting for signal, fork after first info written to xenstore */ update(xs, meminfo_fd, dom_current_fd); n = fork(); if (n < 0) { perror("fork"); exit(1); } if (n > 0) exit(0); usleep(delay); } for (;;) { update(xs, meminfo_fd, dom_current_fd); usleep(delay); } }