Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0
2 : * Copyright(c) 2022 Cisco Systems, Inc.
3 : */
4 :
5 : #include <vppinfra/format.h>
6 : #include <vppinfra/error.h>
7 : #include <vppinfra/perfmon/perfmon.h>
8 : #include <vppinfra/format_table.h>
9 :
10 : clib_perfmon_main_t clib_perfmon_main;
11 :
12 : __clib_export clib_error_t *
13 0 : clib_perfmon_init_by_bundle_name (clib_perfmon_ctx_t *ctx, char *fmt, ...)
14 : {
15 0 : clib_perfmon_main_t *pm = &clib_perfmon_main;
16 0 : clib_perfmon_bundle_t *b = 0;
17 0 : int group_fd = -1;
18 0 : clib_error_t *err = 0;
19 : va_list va;
20 : char *bundle_name;
21 :
22 0 : struct perf_event_attr pe = {
23 : .size = sizeof (struct perf_event_attr),
24 : .disabled = 1,
25 : .exclude_kernel = 1,
26 : .exclude_hv = 1,
27 : .pinned = 1,
28 : .exclusive = 1,
29 : .read_format = (PERF_FORMAT_GROUP | PERF_FORMAT_TOTAL_TIME_ENABLED |
30 : PERF_FORMAT_TOTAL_TIME_RUNNING),
31 : };
32 :
33 0 : va_start (va, fmt);
34 0 : bundle_name = (char *) va_format (0, fmt, &va);
35 0 : va_end (va);
36 0 : vec_add1 (bundle_name, 0);
37 :
38 0 : for (clib_perfmon_bundle_reg_t *r = pm->bundle_regs; r; r = r->next)
39 : {
40 0 : if (strncmp (r->bundle->name, bundle_name, vec_len (bundle_name) - 1))
41 0 : continue;
42 0 : b = r->bundle;
43 0 : break;
44 : }
45 :
46 0 : if (b == 0)
47 : {
48 0 : err = clib_error_return (0, "Unknown bundle '%s'", bundle_name);
49 0 : goto done;
50 : }
51 :
52 0 : clib_memset_u8 (ctx, 0, sizeof (clib_perfmon_ctx_t));
53 0 : vec_validate_init_empty (ctx->fds, b->n_events - 1, -1);
54 0 : ctx->bundle = b;
55 :
56 0 : for (int i = 0; i < b->n_events; i++)
57 : {
58 0 : pe.config = b->config[i];
59 0 : pe.type = b->type;
60 0 : int fd = syscall (__NR_perf_event_open, &pe, /* pid */ 0, /* cpu */ -1,
61 : /* group_fd */ group_fd, /* flags */ 0);
62 0 : if (fd < 0)
63 : {
64 0 : err = clib_error_return_unix (0, "perf_event_open[%u]", i);
65 0 : goto done;
66 : }
67 :
68 0 : if (ctx->debug)
69 0 : fformat (stderr, "perf event %u open, fd %d\n", i, fd);
70 :
71 0 : if (group_fd == -1)
72 : {
73 0 : group_fd = fd;
74 0 : pe.pinned = 0;
75 0 : pe.exclusive = 0;
76 : }
77 :
78 0 : ctx->fds[i] = fd;
79 : }
80 :
81 0 : ctx->group_fd = group_fd;
82 0 : ctx->data = vec_new (u64, 3 + b->n_events);
83 0 : ctx->ref_clock = os_cpu_clock_frequency ();
84 0 : vec_validate (ctx->capture_groups, 0);
85 :
86 0 : done:
87 0 : if (err)
88 0 : clib_perfmon_free (ctx);
89 :
90 0 : vec_free (bundle_name);
91 0 : return err;
92 : }
93 :
94 : __clib_export void
95 0 : clib_perfmon_free (clib_perfmon_ctx_t *ctx)
96 : {
97 0 : clib_perfmon_clear (ctx);
98 0 : vec_free (ctx->captures);
99 0 : vec_free (ctx->capture_groups);
100 :
101 0 : for (int i = 0; i < vec_len (ctx->fds); i++)
102 0 : if (ctx->fds[i] > -1)
103 0 : close (ctx->fds[i]);
104 0 : vec_free (ctx->fds);
105 0 : vec_free (ctx->data);
106 0 : }
107 :
108 : __clib_export void
109 0 : clib_perfmon_clear (clib_perfmon_ctx_t *ctx)
110 : {
111 0 : for (int i = 0; i < vec_len (ctx->captures); i++)
112 0 : vec_free (ctx->captures[i].desc);
113 0 : vec_reset_length (ctx->captures);
114 0 : for (int i = 0; i < vec_len (ctx->capture_groups); i++)
115 0 : vec_free (ctx->capture_groups[i].name);
116 0 : vec_reset_length (ctx->capture_groups);
117 0 : }
118 :
119 : __clib_export u64 *
120 0 : clib_perfmon_capture (clib_perfmon_ctx_t *ctx, u32 n_ops, char *fmt, ...)
121 : {
122 0 : u32 read_size = (ctx->bundle->n_events + 3) * sizeof (u64);
123 : clib_perfmon_capture_t *c;
124 : u64 d[CLIB_PERFMON_MAX_EVENTS + 3];
125 : va_list va;
126 :
127 0 : if ((read (ctx->group_fd, d, read_size) != read_size))
128 : {
129 0 : if (ctx->debug)
130 0 : fformat (stderr, "reading of %u bytes failed, %s (%d)\n", read_size,
131 0 : strerror (errno), errno);
132 0 : return 0;
133 : }
134 :
135 0 : if (ctx->debug)
136 : {
137 0 : fformat (stderr, "read events: %lu enabled: %lu running: %lu ", d[0],
138 : d[1], d[2]);
139 0 : fformat (stderr, "data: [%lu", d[3]);
140 0 : for (int i = 1; i < ctx->bundle->n_events; i++)
141 0 : fformat (stderr, ", %lu", d[i + 3]);
142 0 : fformat (stderr, "]\n");
143 : }
144 :
145 0 : vec_add2 (ctx->captures, c, 1);
146 :
147 0 : va_start (va, fmt);
148 0 : c->desc = va_format (0, fmt, &va);
149 0 : va_end (va);
150 :
151 0 : c->n_ops = n_ops;
152 0 : c->group = vec_len (ctx->capture_groups) - 1;
153 0 : c->time_enabled = d[1];
154 0 : c->time_running = d[2];
155 0 : for (int i = 0; i < CLIB_PERFMON_MAX_EVENTS; i++)
156 0 : c->data[i] = d[i + 3];
157 :
158 0 : return ctx->data + vec_len (ctx->data) - ctx->bundle->n_events;
159 : }
160 :
161 : __clib_export void
162 0 : clib_perfmon_capture_group (clib_perfmon_ctx_t *ctx, char *fmt, ...)
163 : {
164 : clib_perfmon_capture_group_t *cg;
165 : va_list va;
166 :
167 0 : cg = vec_end (ctx->capture_groups) - 1;
168 :
169 0 : if (cg->name != 0)
170 0 : vec_add2 (ctx->capture_groups, cg, 1);
171 :
172 0 : va_start (va, fmt);
173 0 : cg->name = va_format (0, fmt, &va);
174 0 : va_end (va);
175 0 : ASSERT (cg->name);
176 0 : }
177 :
178 : __clib_export void
179 0 : clib_perfmon_warmup (clib_perfmon_ctx_t *ctx)
180 : {
181 0 : for (u64 i = 0; i < (u64) ctx->ref_clock; i++)
182 0 : asm volatile("" : : "r"(i * i) : "memory");
183 0 : }
184 :
185 : __clib_export u8 *
186 0 : format_perfmon_bundle (u8 *s, va_list *args)
187 : {
188 0 : clib_perfmon_ctx_t *ctx = va_arg (*args, clib_perfmon_ctx_t *);
189 : clib_perfmon_capture_t *c;
190 0 : clib_perfmon_capture_group_t *cg = 0;
191 0 : char **hdr = ctx->bundle->column_headers;
192 0 : table_t _t = {}, *t = &_t;
193 0 : u32 n_row = 0, col = 0;
194 :
195 0 : table_add_header_row (t, 0);
196 :
197 0 : for (char **h = ctx->bundle->column_headers; h[0]; h++)
198 0 : n_row++;
199 :
200 0 : vec_foreach (c, ctx->captures)
201 : {
202 0 : if (cg != ctx->capture_groups + c->group)
203 : {
204 0 : cg = ctx->capture_groups + c->group;
205 0 : table_format_cell (t, col, -1, "%v", cg->name);
206 0 : table_set_cell_align (t, col, -1, TTAA_LEFT);
207 0 : table_set_cell_fg_color (t, col, -1, TTAC_BRIGHT_RED);
208 :
209 0 : table_format_cell (t, col, 0, "Ops");
210 0 : table_set_cell_fg_color (t, col, 0, TTAC_BRIGHT_YELLOW);
211 :
212 0 : for (int i = 0; i < n_row; i++)
213 : {
214 0 : table_format_cell (t, col, i + 1, "%s", hdr[i]);
215 0 : table_set_cell_fg_color (t, col, i + 1, TTAC_BRIGHT_YELLOW);
216 : }
217 0 : col++;
218 : }
219 0 : table_format_cell (t, col, -1, "%v", c->desc);
220 0 : table_format_cell (t, col, 0, "%7u", c->n_ops);
221 0 : for (int i = 0; i < n_row; i++)
222 0 : table_format_cell (t, col, i + 1, "%U", ctx->bundle->format_fn, ctx, c,
223 : i);
224 0 : col++;
225 : }
226 :
227 0 : s = format (s, "%U", format_table, t);
228 0 : table_free (t);
229 0 : return s;
230 : }
|