Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

tracing/boot: Add per-event histogram action options

Add a hist-trigger action syntax support to boot-time tracing.
Currently, boot-time tracing supports per-event actions as option
strings. However, for the histogram action, it has a special syntax
and usually needs a long action definition.
To make it readable and fit to the bootconfig syntax, this introduces
a new options for histogram.

Here are the histogram action options for boot-time tracing.

ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist {
keys = <KEY>[,...]
values = <VAL>[,...]
sort = <SORT-KEY>[,...]
size = <ENTRIES>
name = <HISTNAME>
var { <VAR> = <EXPR> ... }
pause|continue|clear
onmax|onchange { var = <VAR>; <ACTION> [= <PARAM>] }
onmatch { event = <EVENT>; <ACTION> [= <PARAM>] }
filter = <FILTER>
}

Where <ACTION> is one of below;

trace = <EVENT>, <ARG1>[, ...]
save = <ARG1>[, ...]
snapshot

Link: https://lkml.kernel.org/r/162856124106.203126.10501871028479029087.stgit@devnote2

Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

authored by

Masami Hiramatsu and committed by
Steven Rostedt (VMware)
e66ed86c c3b1c377

+231
+231
kernel/trace/trace_boot.c
··· 171 171 } 172 172 #endif 173 173 174 + #ifdef CONFIG_HIST_TRIGGERS 175 + static int __init __printf(3, 4) 176 + append_printf(char **bufp, char *end, const char *fmt, ...) 177 + { 178 + va_list args; 179 + int ret; 180 + 181 + if (*bufp == end) 182 + return -ENOSPC; 183 + 184 + va_start(args, fmt); 185 + ret = vsnprintf(*bufp, end - *bufp, fmt, args); 186 + if (ret < end - *bufp) { 187 + *bufp += ret; 188 + } else { 189 + *bufp = end; 190 + ret = -ERANGE; 191 + } 192 + va_end(args); 193 + 194 + return ret; 195 + } 196 + 197 + static int __init 198 + append_str_nospace(char **bufp, char *end, const char *str) 199 + { 200 + char *p = *bufp; 201 + int len; 202 + 203 + while (p < end - 1 && *str != '\0') { 204 + if (!isspace(*str)) 205 + *(p++) = *str; 206 + str++; 207 + } 208 + *p = '\0'; 209 + if (p == end - 1) { 210 + *bufp = end; 211 + return -ENOSPC; 212 + } 213 + len = p - *bufp; 214 + *bufp = p; 215 + return (int)len; 216 + } 217 + 218 + static int __init 219 + trace_boot_hist_add_array(struct xbc_node *hnode, char **bufp, 220 + char *end, const char *key) 221 + { 222 + struct xbc_node *knode, *anode; 223 + const char *p; 224 + char sep; 225 + 226 + knode = xbc_node_find_child(hnode, key); 227 + if (knode) { 228 + anode = xbc_node_get_child(knode); 229 + if (!anode) { 230 + pr_err("hist.%s requires value(s).\n", key); 231 + return -EINVAL; 232 + } 233 + 234 + append_printf(bufp, end, ":%s", key); 235 + sep = '='; 236 + xbc_array_for_each_value(anode, p) { 237 + append_printf(bufp, end, "%c%s", sep, p); 238 + if (sep == '=') 239 + sep = ','; 240 + } 241 + } else 242 + return -ENOENT; 243 + 244 + return 0; 245 + } 246 + 247 + static int __init 248 + trace_boot_hist_add_handler(struct xbc_node *hnode, char **bufp, 249 + char *end, const char *param) 250 + { 251 + struct xbc_node *knode, *anode; 252 + const char *p; 253 + char sep; 254 + 255 + /* Compose 'handler' parameter */ 256 + p = xbc_node_find_value(hnode, param, NULL); 257 + if (!p) { 258 + pr_err("hist.%s requires '%s' option.\n", 259 + xbc_node_get_data(hnode), param); 260 + return -EINVAL; 261 + } 262 + append_printf(bufp, end, ":%s(%s)", xbc_node_get_data(hnode), p); 263 + 264 + /* Compose 'action' parameter */ 265 + knode = xbc_node_find_child(hnode, "trace"); 266 + if (!knode) 267 + knode = xbc_node_find_child(hnode, "save"); 268 + 269 + if (knode) { 270 + anode = xbc_node_get_child(knode); 271 + if (!anode || !xbc_node_is_value(anode)) { 272 + pr_err("hist.%s.%s requires value(s).\n", 273 + xbc_node_get_data(hnode), 274 + xbc_node_get_data(knode)); 275 + return -EINVAL; 276 + } 277 + 278 + append_printf(bufp, end, ".%s", xbc_node_get_data(knode)); 279 + sep = '('; 280 + xbc_array_for_each_value(anode, p) { 281 + append_printf(bufp, end, "%c%s", sep, p); 282 + if (sep == '(') 283 + sep = ','; 284 + } 285 + append_printf(bufp, end, ")"); 286 + } else if (xbc_node_find_child(hnode, "snapshot")) { 287 + append_printf(bufp, end, ".snapshot()"); 288 + } else { 289 + pr_err("hist.%s requires an action.\n", 290 + xbc_node_get_data(hnode)); 291 + return -EINVAL; 292 + } 293 + 294 + return 0; 295 + } 296 + 297 + /* 298 + * Histogram boottime tracing syntax. 299 + * 300 + * ftrace.[instance.INSTANCE.]event.GROUP.EVENT.hist { 301 + * keys = <KEY>[,...] 302 + * values = <VAL>[,...] 303 + * sort = <SORT-KEY>[,...] 304 + * size = <ENTRIES> 305 + * name = <HISTNAME> 306 + * var { <VAR> = <EXPR> ... } 307 + * pause|continue|clear 308 + * onmax|onchange { var = <VAR>; <ACTION> [= <PARAM>] } 309 + * onmatch { event = <EVENT>; <ACTION> [= <PARAM>] } 310 + * filter = <FILTER> 311 + * } 312 + * 313 + * Where <ACTION> are; 314 + * 315 + * trace = <EVENT>, <ARG1>[, ...] 316 + * save = <ARG1>[, ...] 317 + * snapshot 318 + */ 319 + static int __init 320 + trace_boot_compose_hist_cmd(struct xbc_node *hnode, char *buf, size_t size) 321 + { 322 + struct xbc_node *node, *knode; 323 + char *end = buf + size; 324 + const char *p; 325 + int ret = 0; 326 + 327 + append_printf(&buf, end, "hist"); 328 + 329 + ret = trace_boot_hist_add_array(hnode, &buf, end, "keys"); 330 + if (ret < 0) { 331 + if (ret == -ENOENT) 332 + pr_err("hist requires keys.\n"); 333 + return -EINVAL; 334 + } 335 + 336 + ret = trace_boot_hist_add_array(hnode, &buf, end, "values"); 337 + if (ret == -EINVAL) 338 + return ret; 339 + ret = trace_boot_hist_add_array(hnode, &buf, end, "sort"); 340 + if (ret == -EINVAL) 341 + return ret; 342 + 343 + p = xbc_node_find_value(hnode, "size", NULL); 344 + if (p) 345 + append_printf(&buf, end, ":size=%s", p); 346 + 347 + p = xbc_node_find_value(hnode, "name", NULL); 348 + if (p) 349 + append_printf(&buf, end, ":name=%s", p); 350 + 351 + node = xbc_node_find_child(hnode, "var"); 352 + if (node) { 353 + xbc_node_for_each_key_value(node, knode, p) { 354 + /* Expression must not include spaces. */ 355 + append_printf(&buf, end, ":%s=", 356 + xbc_node_get_data(knode)); 357 + append_str_nospace(&buf, end, p); 358 + } 359 + } 360 + 361 + /* Histogram control attributes (mutual exclusive) */ 362 + if (xbc_node_find_child(hnode, "pause")) 363 + append_printf(&buf, end, ":pause"); 364 + else if (xbc_node_find_child(hnode, "continue")) 365 + append_printf(&buf, end, ":continue"); 366 + else if (xbc_node_find_child(hnode, "clear")) 367 + append_printf(&buf, end, ":clear"); 368 + 369 + /* Histogram handler and actions */ 370 + node = xbc_node_find_child(hnode, "onmax"); 371 + if (node && trace_boot_hist_add_handler(node, &buf, end, "var") < 0) 372 + return -EINVAL; 373 + node = xbc_node_find_child(hnode, "onchange"); 374 + if (node && trace_boot_hist_add_handler(node, &buf, end, "var") < 0) 375 + return -EINVAL; 376 + node = xbc_node_find_child(hnode, "onmatch"); 377 + if (node && trace_boot_hist_add_handler(node, &buf, end, "event") < 0) 378 + return -EINVAL; 379 + 380 + p = xbc_node_find_value(hnode, "filter", NULL); 381 + if (p) 382 + append_printf(&buf, end, " if %s", p); 383 + 384 + if (buf == end) { 385 + pr_err("hist exceeds the max command length.\n"); 386 + return -E2BIG; 387 + } 388 + 389 + return 0; 390 + } 391 + #else 392 + static int __init 393 + trace_boot_compose_hist_cmd(struct xbc_node *hnode, char *buf, size_t size) 394 + { 395 + return -EOPNOTSUPP; 396 + } 397 + #endif 398 + 174 399 static void __init 175 400 trace_boot_init_one_event(struct trace_array *tr, struct xbc_node *gnode, 176 401 struct xbc_node *enode) ··· 436 211 pr_err("action string is too long: %s\n", p); 437 212 else if (trigger_process_regex(file, buf) < 0) 438 213 pr_err("Failed to apply an action: %s\n", buf); 214 + } 215 + anode = xbc_node_find_child(enode, "hist"); 216 + if (anode && 217 + trace_boot_compose_hist_cmd(anode, buf, ARRAY_SIZE(buf)) == 0) { 218 + if (trigger_process_regex(file, buf) < 0) 219 + pr_err("Failed to apply hist trigger: %s\n", buf); 439 220 } 440 221 } else if (xbc_node_find_value(enode, "actions", NULL)) 441 222 pr_err("Failed to apply event actions because CONFIG_HIST_TRIGGERS is not set.\n");