Add debugging stats to hashtable.
[kmemtrace-user.git] / kmemtraced.c
blob167b9a5f0685737b46a66c24b7c696b75e97e0aa
1 /*
2 * Copyright (C) 2008 Pekka Enberg, Eduard - Gabriel Munteanu
4 * This file is released under GPL version 2.
5 */
7 #define _GNU_SOURCE
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <pthread.h>
13 #include <poll.h>
14 #include <sched.h>
15 #include <signal.h>
16 #include <stdarg.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23 #include <sys/syscall.h>
24 #include <sys/sendfile.h>
25 #include <unistd.h>
27 #include "common.h"
28 #include "kmemtrace.h"
30 static volatile int terminate;
32 static void write_str(const char *filename, const char *value)
34 int fd;
36 fd = open(filename, O_RDWR);
37 if (fd < 0)
38 panic("Could not open() file %s: %s\n", filename, strerror(errno));
40 if (write(fd, value, strlen(value)) < 0)
41 panic("Could not write() to file %s: %s\n", filename, strerror(errno));
43 close(fd);
46 static int open_channel(int cpu)
48 char filename[PATH_MAX];
49 int fd;
51 sprintf(filename, "/sys/kernel/debug/kmemtrace/cpu%d", cpu);
52 fd = open(filename, O_RDONLY | O_NONBLOCK);
53 if (fd < 0)
54 panic("Could not open() file %s: %s\n", filename, strerror(errno));
55 return fd;
58 static int open_log(int cpu)
60 char filename[PATH_MAX];
61 int fd;
63 sprintf(filename, "cpu%d.out", cpu);
64 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC,
65 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
66 if (fd < 0)
67 panic("Could not open() file %s: %s\n",
68 filename, strerror(errno));
70 return fd;
73 static void reader_set_affinity(unsigned long cpu)
75 int err;
76 cpu_set_t cpumask;
78 CPU_ZERO(&cpumask);
79 CPU_SET(cpu, &cpumask);
80 err = sched_setaffinity(syscall(SYS_gettid),
81 sizeof(cpu_set_t), &cpumask);
83 if (err == -1)
84 panic("reader_set_affinity: %s\n", strerror(errno));
87 static void *reader_thread(void *data)
89 unsigned long cpu = (unsigned long) data;
90 int relay_fd, log_fd;
91 int pipe_fd[2];
92 long retval;
94 reader_set_affinity(cpu);
96 relay_fd = open_channel(cpu);
97 log_fd = open_log(cpu);
99 if (pipe(pipe_fd))
100 panic("pipe() failed: %s\n", strerror(errno));
102 do {
104 * We don't strip extra features (due to ABI changes) from
105 * events; do that when actually parsing the data.
107 retval = splice(relay_fd, NULL, pipe_fd[1], NULL,
108 128, SPLICE_F_MOVE);
109 if (retval < 0)
110 panic("splice() (from) failed: %s\n",
111 strerror(errno));
112 if (!retval)
113 continue;
114 retval = splice(pipe_fd[0], NULL, log_fd, NULL,
115 128, SPLICE_F_MOVE);
116 if (retval < 0)
117 panic("splice() (to) failed: %s\n", strerror(errno));
118 } while (!terminate);
120 return NULL;
123 static void copy_kallsyms(void)
125 int in_fd, out_fd;
126 char buf[256];
127 ssize_t count;
129 in_fd = open("/proc/kallsyms", O_RDONLY);
130 if (in_fd == -1)
131 goto err;
133 out_fd = open("kallsyms", O_CREAT | O_WRONLY | O_TRUNC,
134 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
135 if (out_fd == -1) {
136 close(in_fd);
137 goto err;
140 while ((count = read(in_fd, buf, 256)) > 0)
141 write(out_fd, buf, count);
142 if (count < 0)
143 goto err;
145 return;
147 err:
148 panic("copy_kallsyms: %s\n", strerror(errno));
151 int main(int argc, char *argv[])
153 unsigned long nr_cpus;
154 pthread_t *readers;
155 sigset_t signals;
156 unsigned long i;
157 int signal;
159 sigemptyset(&signals);
160 sigaddset(&signals, SIGINT);
161 sigaddset(&signals, SIGTERM);
162 pthread_sigmask(SIG_BLOCK, &signals, NULL);
164 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
166 readers = calloc(nr_cpus, sizeof(pthread_t));
167 if (!readers)
168 panic("Out of memory!\n");
170 printf("Copying /proc/kallsyms...\n");
171 copy_kallsyms();
173 for (i = 0; i < nr_cpus; i++) {
174 int err;
176 err = pthread_create(&readers[i], NULL, reader_thread,
177 (void *) i);
178 if (err)
179 panic("Could not pthread_create(): %s!\n",
180 strerror(errno));
183 write_str("/sys/kernel/debug/kmemtrace/enabled", "1");
185 printf("Logging... Press Control-C to stop.\n");
187 while (sigwait(&signals, &signal) == 0) {
188 if (signal == SIGINT || signal == SIGTERM)
190 * No synchronization needed, we wait for
191 * threads to end.
193 terminate = 1;
194 break;
197 write_str("/sys/kernel/debug/kmemtrace/enabled", "0");
199 for (i = 0; i < nr_cpus; i++)
200 pthread_join(readers[i], NULL);
202 return EXIT_SUCCESS;