217478ddca954a9d3fc4c4c99bd9f3c93e498bb1
[kmemtrace-user.git] / kmemtraced.c
1 /*
2 * Copyright (C) 2008 Pekka Enberg, Eduard - Gabriel Munteanu
3 *
4 * This file is released under GPL version 2.
5 */
6
7 #define _GNU_SOURCE
8
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>
26
27 #include "common.h"
28 #include "kmemtrace.h"
29
30 static volatile int terminate;
31
32 static void write_str(const char *filename, const char *value)
33 {
34 int fd;
35
36 fd = open(filename, O_RDWR);
37 if (fd < 0)
38 panic("Could not open() file %s: %s\n", filename, strerror(errno));
39
40 if (write(fd, value, strlen(value)) < 0)
41 panic("Could not write() to file %s: %s\n", filename, strerror(errno));
42
43 close(fd);
44 }
45
46 static int open_channel(int cpu)
47 {
48 char filename[PATH_MAX];
49 int fd;
50
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;
56 }
57
58 static int open_log(int cpu)
59 {
60 char filename[PATH_MAX];
61 int fd;
62
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));
69
70 return fd;
71 }
72
73 static void reader_set_affinity(unsigned long cpu)
74 {
75 int err;
76 cpu_set_t cpumask;
77
78 CPU_ZERO(&cpumask);
79 CPU_SET(cpu, &cpumask);
80 err = sched_setaffinity(syscall(SYS_gettid),
81 sizeof(cpu_set_t), &cpumask);
82
83 if (err == -1)
84 panic("reader_set_affinity: %s\n", strerror(errno));
85 }
86
87 static void *reader_thread(void *data)
88 {
89 unsigned long cpu = (unsigned long) data;
90 int relay_fd, log_fd;
91 int pipe_fd[2];
92 long retval;
93
94 reader_set_affinity(cpu);
95
96 relay_fd = open_channel(cpu);
97 log_fd = open_log(cpu);
98
99 if (pipe(pipe_fd))
100 panic("pipe() failed: %s\n", strerror(errno));
101
102 do {
103 /*
104 * We don't strip extra features (due to ABI changes) from
105 * events; do that when actually parsing the data.
106 */
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 retval = splice(pipe_fd[0], NULL, log_fd, NULL,
113 128, SPLICE_F_MOVE);
114 if (retval < 0)
115 panic("splice() (to) failed: %s\n", strerror(errno));
116 } while (!terminate);
117
118 return NULL;
119 }
120
121 static void copy_kallsyms(void)
122 {
123 int in_fd, out_fd;
124 char buf[256];
125 ssize_t count;
126
127 in_fd = open("/proc/kallsyms", O_RDONLY);
128 if (in_fd == -1)
129 goto err;
130
131 out_fd = open("kallsyms", O_CREAT | O_WRONLY | O_TRUNC,
132 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
133 if (out_fd == -1) {
134 close(in_fd);
135 goto err;
136 }
137
138 while ((count = read(in_fd, buf, 256)) > 0)
139 write(out_fd, buf, count);
140 if (count < 0)
141 goto err;
142
143 return;
144
145 err:
146 panic("copy_kallsyms: %s\n", strerror(errno));
147 }
148
149 int main(int argc, char *argv[])
150 {
151 unsigned long nr_cpus;
152 pthread_t *readers;
153 sigset_t signals;
154 unsigned long i;
155 int signal;
156
157 sigemptyset(&signals);
158 sigaddset(&signals, SIGINT);
159 sigaddset(&signals, SIGTERM);
160 pthread_sigmask(SIG_BLOCK, &signals, NULL);
161
162 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
163
164 readers = calloc(nr_cpus, sizeof(pthread_t));
165 if (!readers)
166 panic("Out of memory!\n");
167
168 write_str("/sys/kernel/debug/kmemtrace/enabled", "0");
169
170 printf("Copying /proc/kallsyms...\n");
171 copy_kallsyms();
172
173 for (i = 0; i < nr_cpus; i++) {
174 int err;
175
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));
181 }
182
183 printf("Logging... Press Control-C to stop.\n");
184
185 while (sigwait(&signals, &signal) == 0) {
186 if (signal == SIGINT || signal == SIGTERM)
187 /*
188 * No synchronization needed, we wait for
189 * threads to end.
190 */
191 terminate = 1;
192 break;
193 }
194
195 write_str("/sys/kernel/debug/kmemtrace/enabled", "0");
196
197 for (i = 0; i < nr_cpus; i++)
198 pthread_join(readers[i], NULL);
199
200 return EXIT_SUCCESS;
201 }