217478ddca954a9d3fc4c4c99bd9f3c93e498bb1
[kmemtrace-user.git] / kmemtraced.c
blob217478ddca954a9d3fc4c4c99bd9f3c93e498bb1
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 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);
118 return NULL;
121 static void copy_kallsyms(void)
123 int in_fd, out_fd;
124 char buf[256];
125 ssize_t count;
127 in_fd = open("/proc/kallsyms", O_RDONLY);
128 if (in_fd == -1)
129 goto err;
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;
138 while ((count = read(in_fd, buf, 256)) > 0)
139 write(out_fd, buf, count);
140 if (count < 0)
141 goto err;
143 return;
145 err:
146 panic("copy_kallsyms: %s\n", strerror(errno));
149 int main(int argc, char *argv[])
151 unsigned long nr_cpus;
152 pthread_t *readers;
153 sigset_t signals;
154 unsigned long i;
155 int signal;
157 sigemptyset(&signals);
158 sigaddset(&signals, SIGINT);
159 sigaddset(&signals, SIGTERM);
160 pthread_sigmask(SIG_BLOCK, &signals, NULL);
162 nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
164 readers = calloc(nr_cpus, sizeof(pthread_t));
165 if (!readers)
166 panic("Out of memory!\n");
168 write_str("/sys/kernel/debug/kmemtrace/enabled", "0");
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 printf("Logging... Press Control-C to stop.\n");
185 while (sigwait(&signals, &signal) == 0) {
186 if (signal == SIGINT || signal == SIGTERM)
188 * No synchronization needed, we wait for
189 * threads to end.
191 terminate = 1;
192 break;
195 write_str("/sys/kernel/debug/kmemtrace/enabled", "0");
197 for (i = 0; i < nr_cpus; i++)
198 pthread_join(readers[i], NULL);
200 return EXIT_SUCCESS;