File Index
Files and directories
Sign in
FILE

osnoise.c

File preview with syntax highlighting.

linux-6.19.14/tools/tracing/rtla/src/osnoise.c C
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2021 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org>
   4 */
   5
   6#define _GNU_SOURCE
   7#include <sys/types.h>
   8#include <sys/stat.h>
   9#include <pthread.h>
  10#include <stdlib.h>
  11#include <string.h>
  12#include <unistd.h>
  13#include <errno.h>
  14#include <fcntl.h>
  15#include <stdio.h>
  16#include <sched.h>
  17
  18#include "osnoise.h"
  19
  20#define DEFAULT_SAMPLE_PERIOD	1000000			/* 1s */
  21#define DEFAULT_SAMPLE_RUNTIME	1000000			/* 1s */
  22
  23/*
  24 * osnoise_get_cpus - return the original "osnoise/cpus" content
  25 *
  26 * It also saves the value to be restored.
  27 */
  28char *osnoise_get_cpus(struct osnoise_context *context)
  29{
  30	if (context->curr_cpus)
  31		return context->curr_cpus;
  32
  33	if (context->orig_cpus)
  34		return context->orig_cpus;
  35
  36	context->orig_cpus = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL);
  37
  38	/*
  39	 * The error value (NULL) is the same for tracefs_instance_file_read()
  40	 * and this functions, so:
  41	 */
  42	return context->orig_cpus;
  43}
  44
  45/*
  46 * osnoise_set_cpus - configure osnoise to run on *cpus
  47 *
  48 * "osnoise/cpus" file is used to set the cpus in which osnoise/timerlat
  49 * will run. This function opens this file, saves the current value,
  50 * and set the cpus passed as argument.
  51 */
  52int osnoise_set_cpus(struct osnoise_context *context, char *cpus)
  53{
  54	char *orig_cpus = osnoise_get_cpus(context);
  55	char buffer[1024];
  56	int retval;
  57
  58	if (!orig_cpus)
  59		return -1;
  60
  61	context->curr_cpus = strdup(cpus);
  62	if (!context->curr_cpus)
  63		return -1;
  64
  65	snprintf(buffer, 1024, "%s\n", cpus);
  66
  67	debug_msg("setting cpus to %s from %s", cpus, context->orig_cpus);
  68
  69	retval = tracefs_instance_file_write(NULL, "osnoise/cpus", buffer);
  70	if (retval < 0) {
  71		free(context->curr_cpus);
  72		context->curr_cpus = NULL;
  73		return -1;
  74	}
  75
  76	return 0;
  77}
  78
  79/*
  80 * osnoise_restore_cpus - restore the original "osnoise/cpus"
  81 *
  82 * osnoise_set_cpus() saves the original data for the "osnoise/cpus"
  83 * file. This function restore the original config it was previously
  84 * modified.
  85 */
  86void osnoise_restore_cpus(struct osnoise_context *context)
  87{
  88	int retval;
  89
  90	if (!context->orig_cpus)
  91		return;
  92
  93	if (!context->curr_cpus)
  94		return;
  95
  96	/* nothing to do? */
  97	if (!strcmp(context->orig_cpus, context->curr_cpus))
  98		goto out_done;
  99
 100	debug_msg("restoring cpus to %s", context->orig_cpus);
 101
 102	retval = tracefs_instance_file_write(NULL, "osnoise/cpus", context->orig_cpus);
 103	if (retval < 0)
 104		err_msg("could not restore original osnoise cpus\n");
 105
 106out_done:
 107	free(context->curr_cpus);
 108	context->curr_cpus = NULL;
 109}
 110
 111/*
 112 * osnoise_put_cpus - restore cpus config and cleanup data
 113 */
 114void osnoise_put_cpus(struct osnoise_context *context)
 115{
 116	osnoise_restore_cpus(context);
 117
 118	if (!context->orig_cpus)
 119		return;
 120
 121	free(context->orig_cpus);
 122	context->orig_cpus = NULL;
 123}
 124
 125/*
 126 * osnoise_read_ll_config - read a long long value from a config
 127 *
 128 * returns -1 on error.
 129 */
 130static long long osnoise_read_ll_config(char *rel_path)
 131{
 132	long long retval;
 133	char *buffer;
 134
 135	buffer = tracefs_instance_file_read(NULL, rel_path, NULL);
 136	if (!buffer)
 137		return -1;
 138
 139	/* get_llong_from_str returns -1 on error */
 140	retval = get_llong_from_str(buffer);
 141
 142	debug_msg("reading %s returned %lld\n", rel_path, retval);
 143
 144	free(buffer);
 145
 146	return retval;
 147}
 148
 149/*
 150 * osnoise_write_ll_config - write a long long value to a config in rel_path
 151 *
 152 * returns -1 on error.
 153 */
 154static long long osnoise_write_ll_config(char *rel_path, long long value)
 155{
 156	char buffer[BUFF_U64_STR_SIZE];
 157	long long retval;
 158
 159	snprintf(buffer, sizeof(buffer), "%lld\n", value);
 160
 161	debug_msg("setting %s to %lld\n", rel_path, value);
 162
 163	retval = tracefs_instance_file_write(NULL, rel_path, buffer);
 164	return retval;
 165}
 166
 167/*
 168 * osnoise_get_runtime - return the original "osnoise/runtime_us" value
 169 *
 170 * It also saves the value to be restored.
 171 */
 172unsigned long long osnoise_get_runtime(struct osnoise_context *context)
 173{
 174	long long runtime_us;
 175
 176	if (context->runtime_us != OSNOISE_TIME_INIT_VAL)
 177		return context->runtime_us;
 178
 179	if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
 180		return context->orig_runtime_us;
 181
 182	runtime_us = osnoise_read_ll_config("osnoise/runtime_us");
 183	if (runtime_us < 0)
 184		goto out_err;
 185
 186	context->orig_runtime_us = runtime_us;
 187	return runtime_us;
 188
 189out_err:
 190	return OSNOISE_TIME_INIT_VAL;
 191}
 192
 193/*
 194 * osnoise_get_period - return the original "osnoise/period_us" value
 195 *
 196 * It also saves the value to be restored.
 197 */
 198unsigned long long osnoise_get_period(struct osnoise_context *context)
 199{
 200	long long period_us;
 201
 202	if (context->period_us != OSNOISE_TIME_INIT_VAL)
 203		return context->period_us;
 204
 205	if (context->orig_period_us != OSNOISE_TIME_INIT_VAL)
 206		return context->orig_period_us;
 207
 208	period_us = osnoise_read_ll_config("osnoise/period_us");
 209	if (period_us < 0)
 210		goto out_err;
 211
 212	context->orig_period_us = period_us;
 213	return period_us;
 214
 215out_err:
 216	return OSNOISE_TIME_INIT_VAL;
 217}
 218
 219static int __osnoise_write_runtime(struct osnoise_context *context,
 220				   unsigned long long runtime)
 221{
 222	int retval;
 223
 224	if (context->orig_runtime_us == OSNOISE_TIME_INIT_VAL)
 225		return -1;
 226
 227	retval = osnoise_write_ll_config("osnoise/runtime_us", runtime);
 228	if (retval < 0)
 229		return -1;
 230
 231	context->runtime_us = runtime;
 232	return 0;
 233}
 234
 235static int __osnoise_write_period(struct osnoise_context *context,
 236				  unsigned long long period)
 237{
 238	int retval;
 239
 240	if (context->orig_period_us == OSNOISE_TIME_INIT_VAL)
 241		return -1;
 242
 243	retval = osnoise_write_ll_config("osnoise/period_us", period);
 244	if (retval < 0)
 245		return -1;
 246
 247	context->period_us = period;
 248	return 0;
 249}
 250
 251/*
 252 * osnoise_set_runtime_period - set osnoise runtime and period
 253 *
 254 * Osnoise's runtime and period are related as runtime <= period.
 255 * Thus, this function saves the original values, and then tries
 256 * to set the runtime and period if they are != 0.
 257 */
 258int osnoise_set_runtime_period(struct osnoise_context *context,
 259			       unsigned long long runtime,
 260			       unsigned long long period)
 261{
 262	unsigned long long curr_runtime_us;
 263	unsigned long long curr_period_us;
 264	int retval;
 265
 266	if (!period && !runtime)
 267		return 0;
 268
 269	curr_runtime_us = osnoise_get_runtime(context);
 270	curr_period_us = osnoise_get_period(context);
 271
 272	/* error getting any value? */
 273	if (curr_period_us == OSNOISE_TIME_INIT_VAL || curr_runtime_us == OSNOISE_TIME_INIT_VAL)
 274		return -1;
 275
 276	if (!period) {
 277		if (runtime > curr_period_us)
 278			return -1;
 279		return __osnoise_write_runtime(context, runtime);
 280	} else if (!runtime) {
 281		if (period < curr_runtime_us)
 282			return -1;
 283		return __osnoise_write_period(context, period);
 284	}
 285
 286	if (runtime > curr_period_us) {
 287		retval = __osnoise_write_period(context, period);
 288		if (retval)
 289			return -1;
 290		retval = __osnoise_write_runtime(context, runtime);
 291		if (retval)
 292			return -1;
 293	} else {
 294		retval = __osnoise_write_runtime(context, runtime);
 295		if (retval)
 296			return -1;
 297		retval = __osnoise_write_period(context, period);
 298		if (retval)
 299			return -1;
 300	}
 301
 302	return 0;
 303}
 304
 305/*
 306 * osnoise_restore_runtime_period - restore the original runtime and period
 307 */
 308void osnoise_restore_runtime_period(struct osnoise_context *context)
 309{
 310	unsigned long long orig_runtime = context->orig_runtime_us;
 311	unsigned long long orig_period = context->orig_period_us;
 312	unsigned long long curr_runtime = context->runtime_us;
 313	unsigned long long curr_period = context->period_us;
 314	int retval;
 315
 316	if ((orig_runtime == OSNOISE_TIME_INIT_VAL) && (orig_period == OSNOISE_TIME_INIT_VAL))
 317		return;
 318
 319	if ((orig_period == curr_period) && (orig_runtime == curr_runtime))
 320		goto out_done;
 321
 322	retval = osnoise_set_runtime_period(context, orig_runtime, orig_period);
 323	if (retval)
 324		err_msg("Could not restore original osnoise runtime/period\n");
 325
 326out_done:
 327	context->runtime_us = OSNOISE_TIME_INIT_VAL;
 328	context->period_us = OSNOISE_TIME_INIT_VAL;
 329}
 330
 331/*
 332 * osnoise_put_runtime_period - restore original values and cleanup data
 333 */
 334void osnoise_put_runtime_period(struct osnoise_context *context)
 335{
 336	osnoise_restore_runtime_period(context);
 337
 338	if (context->orig_runtime_us != OSNOISE_TIME_INIT_VAL)
 339		context->orig_runtime_us = OSNOISE_TIME_INIT_VAL;
 340
 341	if (context->orig_period_us != OSNOISE_TIME_INIT_VAL)
 342		context->orig_period_us = OSNOISE_TIME_INIT_VAL;
 343}
 344
 345/*
 346 * osnoise_get_timerlat_period_us - read and save the original "timerlat_period_us"
 347 */
 348static long long
 349osnoise_get_timerlat_period_us(struct osnoise_context *context)
 350{
 351	long long timerlat_period_us;
 352
 353	if (context->timerlat_period_us != OSNOISE_TIME_INIT_VAL)
 354		return context->timerlat_period_us;
 355
 356	if (context->orig_timerlat_period_us != OSNOISE_TIME_INIT_VAL)
 357		return context->orig_timerlat_period_us;
 358
 359	timerlat_period_us = osnoise_read_ll_config("osnoise/timerlat_period_us");
 360	if (timerlat_period_us < 0)
 361		goto out_err;
 362
 363	context->orig_timerlat_period_us = timerlat_period_us;
 364	return timerlat_period_us;
 365
 366out_err:
 367	return OSNOISE_TIME_INIT_VAL;
 368}
 369
 370/*
 371 * osnoise_set_timerlat_period_us - set "timerlat_period_us"
 372 */
 373int osnoise_set_timerlat_period_us(struct osnoise_context *context, long long timerlat_period_us)
 374{
 375	long long curr_timerlat_period_us = osnoise_get_timerlat_period_us(context);
 376	int retval;
 377
 378	if (curr_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
 379		return -1;
 380
 381	retval = osnoise_write_ll_config("osnoise/timerlat_period_us", timerlat_period_us);
 382	if (retval < 0)
 383		return -1;
 384
 385	context->timerlat_period_us = timerlat_period_us;
 386
 387	return 0;
 388}
 389
 390/*
 391 * osnoise_restore_timerlat_period_us - restore "timerlat_period_us"
 392 */
 393void osnoise_restore_timerlat_period_us(struct osnoise_context *context)
 394{
 395	int retval;
 396
 397	if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
 398		return;
 399
 400	if (context->orig_timerlat_period_us == context->timerlat_period_us)
 401		goto out_done;
 402
 403	retval = osnoise_write_ll_config("osnoise/timerlat_period_us", context->orig_timerlat_period_us);
 404	if (retval < 0)
 405		err_msg("Could not restore original osnoise timerlat_period_us\n");
 406
 407out_done:
 408	context->timerlat_period_us = OSNOISE_TIME_INIT_VAL;
 409}
 410
 411/*
 412 * osnoise_put_timerlat_period_us - restore original values and cleanup data
 413 */
 414void osnoise_put_timerlat_period_us(struct osnoise_context *context)
 415{
 416	osnoise_restore_timerlat_period_us(context);
 417
 418	if (context->orig_timerlat_period_us == OSNOISE_TIME_INIT_VAL)
 419		return;
 420
 421	context->orig_timerlat_period_us = OSNOISE_TIME_INIT_VAL;
 422}
 423
 424/*
 425 * osnoise_get_stop_us - read and save the original "stop_tracing_us"
 426 */
 427static long long
 428osnoise_get_stop_us(struct osnoise_context *context)
 429{
 430	long long stop_us;
 431
 432	if (context->stop_us != OSNOISE_OPTION_INIT_VAL)
 433		return context->stop_us;
 434
 435	if (context->orig_stop_us != OSNOISE_OPTION_INIT_VAL)
 436		return context->orig_stop_us;
 437
 438	stop_us = osnoise_read_ll_config("osnoise/stop_tracing_us");
 439	if (stop_us < 0)
 440		goto out_err;
 441
 442	context->orig_stop_us = stop_us;
 443	return stop_us;
 444
 445out_err:
 446	return OSNOISE_OPTION_INIT_VAL;
 447}
 448
 449/*
 450 * osnoise_set_stop_us - set "stop_tracing_us"
 451 */
 452int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us)
 453{
 454	long long curr_stop_us = osnoise_get_stop_us(context);
 455	int retval;
 456
 457	if (curr_stop_us == OSNOISE_OPTION_INIT_VAL)
 458		return -1;
 459
 460	retval = osnoise_write_ll_config("osnoise/stop_tracing_us", stop_us);
 461	if (retval < 0)
 462		return -1;
 463
 464	context->stop_us = stop_us;
 465
 466	return 0;
 467}
 468
 469/*
 470 * osnoise_restore_stop_us - restore the original "stop_tracing_us"
 471 */
 472void osnoise_restore_stop_us(struct osnoise_context *context)
 473{
 474	int retval;
 475
 476	if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL)
 477		return;
 478
 479	if (context->orig_stop_us == context->stop_us)
 480		goto out_done;
 481
 482	retval = osnoise_write_ll_config("osnoise/stop_tracing_us", context->orig_stop_us);
 483	if (retval < 0)
 484		err_msg("Could not restore original osnoise stop_us\n");
 485
 486out_done:
 487	context->stop_us = OSNOISE_OPTION_INIT_VAL;
 488}
 489
 490/*
 491 * osnoise_put_stop_us - restore original values and cleanup data
 492 */
 493void osnoise_put_stop_us(struct osnoise_context *context)
 494{
 495	osnoise_restore_stop_us(context);
 496
 497	if (context->orig_stop_us == OSNOISE_OPTION_INIT_VAL)
 498		return;
 499
 500	context->orig_stop_us = OSNOISE_OPTION_INIT_VAL;
 501}
 502
 503/*
 504 * osnoise_get_stop_total_us - read and save the original "stop_tracing_total_us"
 505 */
 506static long long
 507osnoise_get_stop_total_us(struct osnoise_context *context)
 508{
 509	long long stop_total_us;
 510
 511	if (context->stop_total_us != OSNOISE_OPTION_INIT_VAL)
 512		return context->stop_total_us;
 513
 514	if (context->orig_stop_total_us != OSNOISE_OPTION_INIT_VAL)
 515		return context->orig_stop_total_us;
 516
 517	stop_total_us = osnoise_read_ll_config("osnoise/stop_tracing_total_us");
 518	if (stop_total_us < 0)
 519		goto out_err;
 520
 521	context->orig_stop_total_us = stop_total_us;
 522	return stop_total_us;
 523
 524out_err:
 525	return OSNOISE_OPTION_INIT_VAL;
 526}
 527
 528/*
 529 * osnoise_set_stop_total_us - set "stop_tracing_total_us"
 530 */
 531int osnoise_set_stop_total_us(struct osnoise_context *context, long long stop_total_us)
 532{
 533	long long curr_stop_total_us = osnoise_get_stop_total_us(context);
 534	int retval;
 535
 536	if (curr_stop_total_us == OSNOISE_OPTION_INIT_VAL)
 537		return -1;
 538
 539	retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us", stop_total_us);
 540	if (retval < 0)
 541		return -1;
 542
 543	context->stop_total_us = stop_total_us;
 544
 545	return 0;
 546}
 547
 548/*
 549 * osnoise_restore_stop_total_us - restore the original "stop_tracing_total_us"
 550 */
 551void osnoise_restore_stop_total_us(struct osnoise_context *context)
 552{
 553	int retval;
 554
 555	if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL)
 556		return;
 557
 558	if (context->orig_stop_total_us == context->stop_total_us)
 559		goto out_done;
 560
 561	retval = osnoise_write_ll_config("osnoise/stop_tracing_total_us",
 562			context->orig_stop_total_us);
 563	if (retval < 0)
 564		err_msg("Could not restore original osnoise stop_total_us\n");
 565
 566out_done:
 567	context->stop_total_us = OSNOISE_OPTION_INIT_VAL;
 568}
 569
 570/*
 571 * osnoise_put_stop_total_us - restore original values and cleanup data
 572 */
 573void osnoise_put_stop_total_us(struct osnoise_context *context)
 574{
 575	osnoise_restore_stop_total_us(context);
 576
 577	if (context->orig_stop_total_us == OSNOISE_OPTION_INIT_VAL)
 578		return;
 579
 580	context->orig_stop_total_us = OSNOISE_OPTION_INIT_VAL;
 581}
 582
 583/*
 584 * osnoise_get_print_stack - read and save the original "print_stack"
 585 */
 586static long long
 587osnoise_get_print_stack(struct osnoise_context *context)
 588{
 589	long long print_stack;
 590
 591	if (context->print_stack != OSNOISE_OPTION_INIT_VAL)
 592		return context->print_stack;
 593
 594	if (context->orig_print_stack != OSNOISE_OPTION_INIT_VAL)
 595		return context->orig_print_stack;
 596
 597	print_stack = osnoise_read_ll_config("osnoise/print_stack");
 598	if (print_stack < 0)
 599		goto out_err;
 600
 601	context->orig_print_stack = print_stack;
 602	return print_stack;
 603
 604out_err:
 605	return OSNOISE_OPTION_INIT_VAL;
 606}
 607
 608/*
 609 * osnoise_set_print_stack - set "print_stack"
 610 */
 611int osnoise_set_print_stack(struct osnoise_context *context, long long print_stack)
 612{
 613	long long curr_print_stack = osnoise_get_print_stack(context);
 614	int retval;
 615
 616	if (curr_print_stack == OSNOISE_OPTION_INIT_VAL)
 617		return -1;
 618
 619	retval = osnoise_write_ll_config("osnoise/print_stack", print_stack);
 620	if (retval < 0)
 621		return -1;
 622
 623	context->print_stack = print_stack;
 624
 625	return 0;
 626}
 627
 628/*
 629 * osnoise_restore_print_stack - restore the original "print_stack"
 630 */
 631void osnoise_restore_print_stack(struct osnoise_context *context)
 632{
 633	int retval;
 634
 635	if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL)
 636		return;
 637
 638	if (context->orig_print_stack == context->print_stack)
 639		goto out_done;
 640
 641	retval = osnoise_write_ll_config("osnoise/print_stack", context->orig_print_stack);
 642	if (retval < 0)
 643		err_msg("Could not restore original osnoise print_stack\n");
 644
 645out_done:
 646	context->print_stack = OSNOISE_OPTION_INIT_VAL;
 647}
 648
 649/*
 650 * osnoise_put_print_stack - restore original values and cleanup data
 651 */
 652void osnoise_put_print_stack(struct osnoise_context *context)
 653{
 654	osnoise_restore_print_stack(context);
 655
 656	if (context->orig_print_stack == OSNOISE_OPTION_INIT_VAL)
 657		return;
 658
 659	context->orig_print_stack = OSNOISE_OPTION_INIT_VAL;
 660}
 661
 662/*
 663 * osnoise_get_tracing_thresh - read and save the original "tracing_thresh"
 664 */
 665static long long
 666osnoise_get_tracing_thresh(struct osnoise_context *context)
 667{
 668	long long tracing_thresh;
 669
 670	if (context->tracing_thresh != OSNOISE_OPTION_INIT_VAL)
 671		return context->tracing_thresh;
 672
 673	if (context->orig_tracing_thresh != OSNOISE_OPTION_INIT_VAL)
 674		return context->orig_tracing_thresh;
 675
 676	tracing_thresh = osnoise_read_ll_config("tracing_thresh");
 677	if (tracing_thresh < 0)
 678		goto out_err;
 679
 680	context->orig_tracing_thresh = tracing_thresh;
 681	return tracing_thresh;
 682
 683out_err:
 684	return OSNOISE_OPTION_INIT_VAL;
 685}
 686
 687/*
 688 * osnoise_set_tracing_thresh - set "tracing_thresh"
 689 */
 690int osnoise_set_tracing_thresh(struct osnoise_context *context, long long tracing_thresh)
 691{
 692	long long curr_tracing_thresh = osnoise_get_tracing_thresh(context);
 693	int retval;
 694
 695	if (curr_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
 696		return -1;
 697
 698	retval = osnoise_write_ll_config("tracing_thresh", tracing_thresh);
 699	if (retval < 0)
 700		return -1;
 701
 702	context->tracing_thresh = tracing_thresh;
 703
 704	return 0;
 705}
 706
 707/*
 708 * osnoise_restore_tracing_thresh - restore the original "tracing_thresh"
 709 */
 710void osnoise_restore_tracing_thresh(struct osnoise_context *context)
 711{
 712	int retval;
 713
 714	if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
 715		return;
 716
 717	if (context->orig_tracing_thresh == context->tracing_thresh)
 718		goto out_done;
 719
 720	retval = osnoise_write_ll_config("tracing_thresh", context->orig_tracing_thresh);
 721	if (retval < 0)
 722		err_msg("Could not restore original tracing_thresh\n");
 723
 724out_done:
 725	context->tracing_thresh = OSNOISE_OPTION_INIT_VAL;
 726}
 727
 728/*
 729 * osnoise_put_tracing_thresh - restore original values and cleanup data
 730 */
 731void osnoise_put_tracing_thresh(struct osnoise_context *context)
 732{
 733	osnoise_restore_tracing_thresh(context);
 734
 735	if (context->orig_tracing_thresh == OSNOISE_OPTION_INIT_VAL)
 736		return;
 737
 738	context->orig_tracing_thresh = OSNOISE_OPTION_INIT_VAL;
 739}
 740
 741static int osnoise_options_get_option(char *option)
 742{
 743	char *options = tracefs_instance_file_read(NULL, "osnoise/options", NULL);
 744	char no_option[128];
 745	int retval = 0;
 746	char *opt;
 747
 748	if (!options)
 749		return OSNOISE_OPTION_INIT_VAL;
 750
 751	/*
 752	 * Check first if the option is disabled.
 753	 */
 754	snprintf(no_option, sizeof(no_option), "NO_%s", option);
 755
 756	opt = strstr(options, no_option);
 757	if (opt)
 758		goto out_free;
 759
 760	/*
 761	 * Now that it is not disabled, if the string is there, it is
 762	 * enabled. If the string is not there, the option does not exist.
 763	 */
 764	opt = strstr(options, option);
 765	if (opt)
 766		retval = 1;
 767	else
 768		retval = OSNOISE_OPTION_INIT_VAL;
 769
 770out_free:
 771	free(options);
 772	return retval;
 773}
 774
 775static int osnoise_options_set_option(char *option, bool onoff)
 776{
 777	char no_option[128];
 778
 779	if (onoff)
 780		return tracefs_instance_file_write(NULL, "osnoise/options", option);
 781
 782	snprintf(no_option, sizeof(no_option), "NO_%s", option);
 783
 784	return tracefs_instance_file_write(NULL, "osnoise/options", no_option);
 785}
 786
 787static int osnoise_get_irq_disable(struct osnoise_context *context)
 788{
 789	if (context->opt_irq_disable != OSNOISE_OPTION_INIT_VAL)
 790		return context->opt_irq_disable;
 791
 792	if (context->orig_opt_irq_disable != OSNOISE_OPTION_INIT_VAL)
 793		return context->orig_opt_irq_disable;
 794
 795	context->orig_opt_irq_disable = osnoise_options_get_option("OSNOISE_IRQ_DISABLE");
 796
 797	return context->orig_opt_irq_disable;
 798}
 799
 800int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff)
 801{
 802	int opt_irq_disable = osnoise_get_irq_disable(context);
 803	int retval;
 804
 805	if (opt_irq_disable == OSNOISE_OPTION_INIT_VAL)
 806		return -1;
 807
 808	if (opt_irq_disable == onoff)
 809		return 0;
 810
 811	retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", onoff);
 812	if (retval < 0)
 813		return -1;
 814
 815	context->opt_irq_disable = onoff;
 816
 817	return 0;
 818}
 819
 820static void osnoise_restore_irq_disable(struct osnoise_context *context)
 821{
 822	int retval;
 823
 824	if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL)
 825		return;
 826
 827	if (context->orig_opt_irq_disable == context->opt_irq_disable)
 828		goto out_done;
 829
 830	retval = osnoise_options_set_option("OSNOISE_IRQ_DISABLE", context->orig_opt_irq_disable);
 831	if (retval < 0)
 832		err_msg("Could not restore original OSNOISE_IRQ_DISABLE option\n");
 833
 834out_done:
 835	context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
 836}
 837
 838static void osnoise_put_irq_disable(struct osnoise_context *context)
 839{
 840	osnoise_restore_irq_disable(context);
 841
 842	if (context->orig_opt_irq_disable == OSNOISE_OPTION_INIT_VAL)
 843		return;
 844
 845	context->orig_opt_irq_disable = OSNOISE_OPTION_INIT_VAL;
 846}
 847
 848static int osnoise_get_workload(struct osnoise_context *context)
 849{
 850	if (context->opt_workload != OSNOISE_OPTION_INIT_VAL)
 851		return context->opt_workload;
 852
 853	if (context->orig_opt_workload != OSNOISE_OPTION_INIT_VAL)
 854		return context->orig_opt_workload;
 855
 856	context->orig_opt_workload = osnoise_options_get_option("OSNOISE_WORKLOAD");
 857
 858	return context->orig_opt_workload;
 859}
 860
 861int osnoise_set_workload(struct osnoise_context *context, bool onoff)
 862{
 863	int opt_workload = osnoise_get_workload(context);
 864	int retval;
 865
 866	if (opt_workload == OSNOISE_OPTION_INIT_VAL)
 867		return -1;
 868
 869	if (opt_workload == onoff)
 870		return 0;
 871
 872	retval = osnoise_options_set_option("OSNOISE_WORKLOAD", onoff);
 873	if (retval < 0)
 874		return -2;
 875
 876	context->opt_workload = onoff;
 877
 878	return 0;
 879}
 880
 881static void osnoise_restore_workload(struct osnoise_context *context)
 882{
 883	int retval;
 884
 885	if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL)
 886		return;
 887
 888	if (context->orig_opt_workload == context->opt_workload)
 889		goto out_done;
 890
 891	retval = osnoise_options_set_option("OSNOISE_WORKLOAD", context->orig_opt_workload);
 892	if (retval < 0)
 893		err_msg("Could not restore original OSNOISE_WORKLOAD option\n");
 894
 895out_done:
 896	context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
 897}
 898
 899static void osnoise_put_workload(struct osnoise_context *context)
 900{
 901	osnoise_restore_workload(context);
 902
 903	if (context->orig_opt_workload == OSNOISE_OPTION_INIT_VAL)
 904		return;
 905
 906	context->orig_opt_workload = OSNOISE_OPTION_INIT_VAL;
 907}
 908
 909enum {
 910	FLAG_CONTEXT_NEWLY_CREATED	= (1 << 0),
 911	FLAG_CONTEXT_DELETED		= (1 << 1),
 912};
 913
 914/*
 915 * osnoise_get_context - increase the usage of a context and return it
 916 */
 917int osnoise_get_context(struct osnoise_context *context)
 918{
 919	int ret;
 920
 921	if (context->flags & FLAG_CONTEXT_DELETED) {
 922		ret = -1;
 923	} else {
 924		context->ref++;
 925		ret = 0;
 926	}
 927
 928	return ret;
 929}
 930
 931/*
 932 * osnoise_context_alloc - alloc an osnoise_context
 933 *
 934 * The osnoise context contains the information of the "osnoise/" configs.
 935 * It is used to set and restore the config.
 936 */
 937struct osnoise_context *osnoise_context_alloc(void)
 938{
 939	struct osnoise_context *context;
 940
 941	context = calloc(1, sizeof(*context));
 942	if (!context)
 943		return NULL;
 944
 945	context->orig_stop_us		= OSNOISE_OPTION_INIT_VAL;
 946	context->stop_us		= OSNOISE_OPTION_INIT_VAL;
 947
 948	context->orig_stop_total_us	= OSNOISE_OPTION_INIT_VAL;
 949	context->stop_total_us		= OSNOISE_OPTION_INIT_VAL;
 950
 951	context->orig_print_stack	= OSNOISE_OPTION_INIT_VAL;
 952	context->print_stack		= OSNOISE_OPTION_INIT_VAL;
 953
 954	context->orig_tracing_thresh	= OSNOISE_OPTION_INIT_VAL;
 955	context->tracing_thresh		= OSNOISE_OPTION_INIT_VAL;
 956
 957	context->orig_opt_irq_disable	= OSNOISE_OPTION_INIT_VAL;
 958	context->opt_irq_disable	= OSNOISE_OPTION_INIT_VAL;
 959
 960	context->orig_opt_workload	= OSNOISE_OPTION_INIT_VAL;
 961	context->opt_workload		= OSNOISE_OPTION_INIT_VAL;
 962
 963	osnoise_get_context(context);
 964
 965	return context;
 966}
 967
 968/*
 969 * osnoise_put_context - put the osnoise_put_context
 970 *
 971 * If there is no other user for the context, the original data
 972 * is restored.
 973 */
 974void osnoise_put_context(struct osnoise_context *context)
 975{
 976	if (--context->ref < 1)
 977		context->flags |= FLAG_CONTEXT_DELETED;
 978
 979	if (!(context->flags & FLAG_CONTEXT_DELETED))
 980		return;
 981
 982	osnoise_put_cpus(context);
 983	osnoise_put_runtime_period(context);
 984	osnoise_put_stop_us(context);
 985	osnoise_put_stop_total_us(context);
 986	osnoise_put_timerlat_period_us(context);
 987	osnoise_put_print_stack(context);
 988	osnoise_put_tracing_thresh(context);
 989	osnoise_put_irq_disable(context);
 990	osnoise_put_workload(context);
 991
 992	free(context);
 993}
 994
 995/*
 996 * osnoise_destroy_tool - disable trace, restore configs and free data
 997 */
 998void osnoise_destroy_tool(struct osnoise_tool *top)
 999{
1000	if (!top)
1001		return;
1002
1003	trace_instance_destroy(&top->trace);
1004
1005	if (top->context)
1006		osnoise_put_context(top->context);
1007
1008	free(top);
1009}
1010
1011/*
1012 * osnoise_init_tool - init an osnoise tool
1013 *
1014 * It allocs data, create a context to store data and
1015 * creates a new trace instance for the tool.
1016 */
1017struct osnoise_tool *osnoise_init_tool(char *tool_name)
1018{
1019	struct osnoise_tool *top;
1020	int retval;
1021
1022	top = calloc(1, sizeof(*top));
1023	if (!top)
1024		return NULL;
1025
1026	top->context = osnoise_context_alloc();
1027	if (!top->context)
1028		goto out_err;
1029
1030	retval = trace_instance_init(&top->trace, tool_name);
1031	if (retval)
1032		goto out_err;
1033
1034	return top;
1035out_err:
1036	osnoise_destroy_tool(top);
1037	return NULL;
1038}
1039
1040/*
1041 * osnoise_init_trace_tool - init a tracer instance to trace osnoise events
1042 */
1043struct osnoise_tool *osnoise_init_trace_tool(const char *tracer)
1044{
1045	struct osnoise_tool *trace;
1046	int retval;
1047
1048	trace = osnoise_init_tool("osnoise_trace");
1049	if (!trace)
1050		return NULL;
1051
1052	retval = tracefs_event_enable(trace->trace.inst, "osnoise", NULL);
1053	if (retval < 0 && !errno) {
1054		err_msg("Could not find osnoise events\n");
1055		goto out_err;
1056	}
1057
1058	retval = enable_tracer_by_name(trace->trace.inst, tracer);
1059	if (retval) {
1060		err_msg("Could not enable %s tracer for tracing\n", tracer);
1061		goto out_err;
1062	}
1063
1064	return trace;
1065out_err:
1066	osnoise_destroy_tool(trace);
1067	return NULL;
1068}
1069
1070bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record)
1071{
1072	/*
1073	 * The tool instance is always present, it is the one used to collect
1074	 * data.
1075	 */
1076	if (!tracefs_trace_is_on(tool->trace.inst))
1077		return true;
1078
1079	/*
1080	 * The trace record instance is only enabled when -t is set. IOW, when the system
1081	 * is tracing.
1082	 */
1083	return record && !tracefs_trace_is_on(record->trace.inst);
1084}
1085
1086/*
1087 * osnoise_report_missed_events - report number of events dropped by trace
1088 * buffer
1089 */
1090void
1091osnoise_report_missed_events(struct osnoise_tool *tool)
1092{
1093	unsigned long long total_events;
1094
1095	if (tool->trace.missed_events == UINT64_MAX)
1096		printf("unknown number of events missed, results might not be accurate\n");
1097	else if (tool->trace.missed_events > 0) {
1098		total_events = tool->trace.processed_events + tool->trace.missed_events;
1099
1100		printf("%lld (%.2f%%) events missed, results might not be accurate\n",
1101		       tool->trace.missed_events,
1102		       (double) tool->trace.missed_events / total_events * 100.0);
1103	}
1104}
1105
1106/*
1107 * osnoise_apply_config - apply osnoise configs to the initialized tool
1108 */
1109int
1110osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params)
1111{
1112	int retval;
1113
1114	params->common.kernel_workload = true;
1115
1116	if (params->runtime || params->period) {
1117		retval = osnoise_set_runtime_period(tool->context,
1118						    params->runtime,
1119						    params->period);
1120	} else {
1121		retval = osnoise_set_runtime_period(tool->context,
1122						    DEFAULT_SAMPLE_PERIOD,
1123						    DEFAULT_SAMPLE_RUNTIME);
1124	}
1125
1126	if (retval) {
1127		err_msg("Failed to set runtime and/or period\n");
1128		goto out_err;
1129	}
1130
1131	retval = osnoise_set_stop_us(tool->context, params->common.stop_us);
1132	if (retval) {
1133		err_msg("Failed to set stop us\n");
1134		goto out_err;
1135	}
1136
1137	retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us);
1138	if (retval) {
1139		err_msg("Failed to set stop total us\n");
1140		goto out_err;
1141	}
1142
1143	retval = osnoise_set_tracing_thresh(tool->context, params->threshold);
1144	if (retval) {
1145		err_msg("Failed to set tracing_thresh\n");
1146		goto out_err;
1147	}
1148
1149	return common_apply_config(tool, &params->common);
1150
1151out_err:
1152	return -1;
1153}
1154
1155int osnoise_enable(struct osnoise_tool *tool)
1156{
1157	struct osnoise_params *params = to_osnoise_params(tool->params);
1158	int retval;
1159
1160	/*
1161	 * Start the tracer here, after having set all instances.
1162	 *
1163	 * Let the trace instance start first for the case of hitting a stop
1164	 * tracing while enabling other instances. The trace instance is the
1165	 * one with most valuable information.
1166	 */
1167	if (tool->record)
1168		trace_instance_start(&tool->record->trace);
1169	trace_instance_start(&tool->trace);
1170
1171	if (params->common.warmup > 0) {
1172		debug_msg("Warming up for %d seconds\n", params->common.warmup);
1173		sleep(params->common.warmup);
1174		if (stop_tracing)
1175			return -1;
1176
1177		/*
1178		 * Clean up the buffer. The osnoise workload do not run
1179		 * with tracing off to avoid creating a performance penalty
1180		 * when not needed.
1181		 */
1182		retval = tracefs_instance_file_write(tool->trace.inst, "trace", "");
1183		if (retval < 0) {
1184			debug_msg("Error cleaning up the buffer");
1185			return retval;
1186		}
1187
1188	}
1189
1190	return 0;
1191}
1192
1193static void osnoise_usage(int err)
1194{
1195	int i;
1196
1197	static const char *msg[] = {
1198		"",
1199		"osnoise version " VERSION,
1200		"",
1201		"  usage: [rtla] osnoise [MODE] ...",
1202		"",
1203		"  modes:",
1204		"     top   - prints the summary from osnoise tracer",
1205		"     hist  - prints a histogram of osnoise samples",
1206		"",
1207		"if no MODE is given, the top mode is called, passing the arguments",
1208		NULL,
1209	};
1210
1211	for (i = 0; msg[i]; i++)
1212		fprintf(stderr, "%s\n", msg[i]);
1213	exit(err);
1214}
1215
1216int osnoise_main(int argc, char *argv[])
1217{
1218	if (argc == 0)
1219		goto usage;
1220
1221	/*
1222	 * if osnoise was called without any argument, run the
1223	 * default cmdline.
1224	 */
1225	if (argc == 1) {
1226		run_tool(&osnoise_top_ops, argc, argv);
1227		exit(0);
1228	}
1229
1230	if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
1231		osnoise_usage(0);
1232	} else if (strncmp(argv[1], "-", 1) == 0) {
1233		/* the user skipped the tool, call the default one */
1234		run_tool(&osnoise_top_ops, argc, argv);
1235		exit(0);
1236	} else if (strcmp(argv[1], "top") == 0) {
1237		run_tool(&osnoise_top_ops, argc-1, &argv[1]);
1238		exit(0);
1239	} else if (strcmp(argv[1], "hist") == 0) {
1240		run_tool(&osnoise_hist_ops, argc-1, &argv[1]);
1241		exit(0);
1242	}
1243
1244usage:
1245	osnoise_usage(1);
1246	exit(1);
1247}
1248
1249int hwnoise_main(int argc, char *argv[])
1250{
1251	run_tool(&osnoise_top_ops, argc, argv);
1252	exit(0);
1253}
~/ Read-only file preview.