Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/virtio/virtio-trace/trace-agent.c
26283 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Guest agent for virtio-trace
4
*
5
* Copyright (C) 2012 Hitachi, Ltd.
6
* Created by Yoshihiro Yunomae <[email protected]>
7
* Masami Hiramatsu <[email protected]>
8
*/
9
10
#define _GNU_SOURCE
11
#include <limits.h>
12
#include <stdio.h>
13
#include <stdlib.h>
14
#include <unistd.h>
15
#include "trace-agent.h"
16
17
#define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
18
#define PIPE_DEF_BUFS 16
19
#define PIPE_MIN_SIZE (PAGE_SIZE*PIPE_DEF_BUFS)
20
#define PIPE_MAX_SIZE (1024*1024)
21
#define TRACEFS "/sys/kernel/tracing"
22
#define DEBUGFS "/sys/kernel/debug/tracing"
23
#define READ_PATH_FMT "%s/per_cpu/cpu%d/trace_pipe_raw"
24
#define WRITE_PATH_FMT "/dev/virtio-ports/trace-path-cpu%d"
25
#define CTL_PATH "/dev/virtio-ports/agent-ctl-path"
26
27
pthread_mutex_t mutex_notify = PTHREAD_MUTEX_INITIALIZER;
28
pthread_cond_t cond_wakeup = PTHREAD_COND_INITIALIZER;
29
30
static int get_total_cpus(void)
31
{
32
int nr_cpus = (int)sysconf(_SC_NPROCESSORS_CONF);
33
34
if (nr_cpus <= 0) {
35
pr_err("Could not read cpus\n");
36
goto error;
37
} else if (nr_cpus > MAX_CPUS) {
38
pr_err("Exceed max cpus(%d)\n", (int)MAX_CPUS);
39
goto error;
40
}
41
42
return nr_cpus;
43
44
error:
45
exit(EXIT_FAILURE);
46
}
47
48
static void *agent_info_new(void)
49
{
50
struct agent_info *s;
51
int i;
52
53
s = zalloc(sizeof(struct agent_info));
54
if (s == NULL) {
55
pr_err("agent_info zalloc error\n");
56
exit(EXIT_FAILURE);
57
}
58
59
s->pipe_size = PIPE_INIT;
60
s->use_stdout = false;
61
s->cpus = get_total_cpus();
62
s->ctl_fd = -1;
63
64
/* read/write threads init */
65
for (i = 0; i < s->cpus; i++)
66
s->rw_ti[i] = rw_thread_info_new();
67
68
return s;
69
}
70
71
static unsigned long parse_size(const char *arg)
72
{
73
unsigned long value, round;
74
char *ptr;
75
76
value = strtoul(arg, &ptr, 10);
77
switch (*ptr) {
78
case 'K': case 'k':
79
value <<= 10;
80
break;
81
case 'M': case 'm':
82
value <<= 20;
83
break;
84
default:
85
break;
86
}
87
88
if (value > PIPE_MAX_SIZE) {
89
pr_err("Pipe size must be less than 1MB\n");
90
goto error;
91
} else if (value < PIPE_MIN_SIZE) {
92
pr_err("Pipe size must be over 64KB\n");
93
goto error;
94
}
95
96
/* Align buffer size with page unit */
97
round = value & (PAGE_SIZE - 1);
98
value = value - round;
99
100
return value;
101
error:
102
return 0;
103
}
104
105
static void usage(char const *prg)
106
{
107
pr_err("usage: %s [-h] [-o] [-s <size of pipe>]\n", prg);
108
}
109
110
static const char *make_path(int cpu_num, bool this_is_write_path)
111
{
112
int ret;
113
char *buf;
114
115
buf = zalloc(PATH_MAX);
116
if (buf == NULL) {
117
pr_err("Could not allocate buffer\n");
118
goto error;
119
}
120
121
if (this_is_write_path)
122
/* write(output) path */
123
ret = snprintf(buf, PATH_MAX, WRITE_PATH_FMT, cpu_num);
124
else {
125
/* read(input) path */
126
ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, TRACEFS, cpu_num);
127
if (ret > 0 && access(buf, F_OK) != 0)
128
ret = snprintf(buf, PATH_MAX, READ_PATH_FMT, DEBUGFS, cpu_num);
129
}
130
131
if (ret <= 0) {
132
pr_err("Failed to generate %s path(CPU#%d):%d\n",
133
this_is_write_path ? "read" : "write", cpu_num, ret);
134
goto error;
135
}
136
137
return buf;
138
139
error:
140
free(buf);
141
return NULL;
142
}
143
144
static const char *make_input_path(int cpu_num)
145
{
146
return make_path(cpu_num, false);
147
}
148
149
static const char *make_output_path(int cpu_num)
150
{
151
return make_path(cpu_num, true);
152
}
153
154
static void *agent_info_init(struct agent_info *s)
155
{
156
int cpu;
157
const char *in_path = NULL;
158
const char *out_path = NULL;
159
160
/* init read/write threads */
161
for (cpu = 0; cpu < s->cpus; cpu++) {
162
/* set read(input) path per read/write thread */
163
in_path = make_input_path(cpu);
164
if (in_path == NULL)
165
goto error;
166
167
/* set write(output) path per read/write thread*/
168
if (!s->use_stdout) {
169
out_path = make_output_path(cpu);
170
if (out_path == NULL)
171
goto error;
172
} else
173
/* stdout mode */
174
pr_debug("stdout mode\n");
175
176
rw_thread_init(cpu, in_path, out_path, s->use_stdout,
177
s->pipe_size, s->rw_ti[cpu]);
178
}
179
180
/* init controller of read/write threads */
181
s->ctl_fd = rw_ctl_init((const char *)CTL_PATH);
182
183
return NULL;
184
185
error:
186
exit(EXIT_FAILURE);
187
}
188
189
static void *parse_args(int argc, char *argv[], struct agent_info *s)
190
{
191
int cmd;
192
unsigned long size;
193
194
while ((cmd = getopt(argc, argv, "hos:")) != -1) {
195
switch (cmd) {
196
/* stdout mode */
197
case 'o':
198
s->use_stdout = true;
199
break;
200
/* size of pipe */
201
case 's':
202
size = parse_size(optarg);
203
if (size == 0)
204
goto error;
205
s->pipe_size = size;
206
break;
207
case 'h':
208
default:
209
usage(argv[0]);
210
goto error;
211
}
212
}
213
214
agent_info_init(s);
215
216
return NULL;
217
218
error:
219
exit(EXIT_FAILURE);
220
}
221
222
static void agent_main_loop(struct agent_info *s)
223
{
224
int cpu;
225
pthread_t rw_thread_per_cpu[MAX_CPUS];
226
227
/* Start all read/write threads */
228
for (cpu = 0; cpu < s->cpus; cpu++)
229
rw_thread_per_cpu[cpu] = rw_thread_run(s->rw_ti[cpu]);
230
231
rw_ctl_loop(s->ctl_fd);
232
233
/* Finish all read/write threads */
234
for (cpu = 0; cpu < s->cpus; cpu++) {
235
int ret;
236
237
ret = pthread_join(rw_thread_per_cpu[cpu], NULL);
238
if (ret != 0) {
239
pr_err("pthread_join() error:%d (cpu %d)\n", ret, cpu);
240
exit(EXIT_FAILURE);
241
}
242
}
243
}
244
245
static void agent_info_free(struct agent_info *s)
246
{
247
int i;
248
249
close(s->ctl_fd);
250
for (i = 0; i < s->cpus; i++) {
251
close(s->rw_ti[i]->in_fd);
252
close(s->rw_ti[i]->out_fd);
253
close(s->rw_ti[i]->read_pipe);
254
close(s->rw_ti[i]->write_pipe);
255
free(s->rw_ti[i]);
256
}
257
free(s);
258
}
259
260
int main(int argc, char *argv[])
261
{
262
struct agent_info *s = NULL;
263
264
s = agent_info_new();
265
parse_args(argc, argv, s);
266
267
agent_main_loop(s);
268
269
agent_info_free(s);
270
271
return 0;
272
}
273
274