162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Benchmark synthesis of perf events such as at the start of a 'perf 462306a36Sopenharmony_ci * record'. Synthesis is done on the current process and the 'dummy' event 562306a36Sopenharmony_ci * handlers are invoked that support dump_trace but otherwise do nothing. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright 2019 Google LLC. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <stdio.h> 1062306a36Sopenharmony_ci#include "bench.h" 1162306a36Sopenharmony_ci#include "../util/debug.h" 1262306a36Sopenharmony_ci#include "../util/session.h" 1362306a36Sopenharmony_ci#include "../util/stat.h" 1462306a36Sopenharmony_ci#include "../util/synthetic-events.h" 1562306a36Sopenharmony_ci#include "../util/target.h" 1662306a36Sopenharmony_ci#include "../util/thread_map.h" 1762306a36Sopenharmony_ci#include "../util/tool.h" 1862306a36Sopenharmony_ci#include "../util/util.h" 1962306a36Sopenharmony_ci#include <linux/atomic.h> 2062306a36Sopenharmony_ci#include <linux/err.h> 2162306a36Sopenharmony_ci#include <linux/time64.h> 2262306a36Sopenharmony_ci#include <subcmd/parse-options.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic unsigned int min_threads = 1; 2562306a36Sopenharmony_cistatic unsigned int max_threads = UINT_MAX; 2662306a36Sopenharmony_cistatic unsigned int single_iterations = 10000; 2762306a36Sopenharmony_cistatic unsigned int multi_iterations = 10; 2862306a36Sopenharmony_cistatic bool run_st; 2962306a36Sopenharmony_cistatic bool run_mt; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic const struct option options[] = { 3262306a36Sopenharmony_ci OPT_BOOLEAN('s', "st", &run_st, "Run single threaded benchmark"), 3362306a36Sopenharmony_ci OPT_BOOLEAN('t', "mt", &run_mt, "Run multi-threaded benchmark"), 3462306a36Sopenharmony_ci OPT_UINTEGER('m', "min-threads", &min_threads, 3562306a36Sopenharmony_ci "Minimum number of threads in multithreaded bench"), 3662306a36Sopenharmony_ci OPT_UINTEGER('M', "max-threads", &max_threads, 3762306a36Sopenharmony_ci "Maximum number of threads in multithreaded bench"), 3862306a36Sopenharmony_ci OPT_UINTEGER('i', "single-iterations", &single_iterations, 3962306a36Sopenharmony_ci "Number of iterations used to compute single-threaded average"), 4062306a36Sopenharmony_ci OPT_UINTEGER('I', "multi-iterations", &multi_iterations, 4162306a36Sopenharmony_ci "Number of iterations used to compute multi-threaded average"), 4262306a36Sopenharmony_ci OPT_END() 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic const char *const bench_usage[] = { 4662306a36Sopenharmony_ci "perf bench internals synthesize <options>", 4762306a36Sopenharmony_ci NULL 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic atomic_t event_count; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic int process_synthesized_event(struct perf_tool *tool __maybe_unused, 5362306a36Sopenharmony_ci union perf_event *event __maybe_unused, 5462306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused, 5562306a36Sopenharmony_ci struct machine *machine __maybe_unused) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci atomic_inc(&event_count); 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int do_run_single_threaded(struct perf_session *session, 6262306a36Sopenharmony_ci struct perf_thread_map *threads, 6362306a36Sopenharmony_ci struct target *target, bool data_mmap) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci const unsigned int nr_threads_synthesize = 1; 6662306a36Sopenharmony_ci struct timeval start, end, diff; 6762306a36Sopenharmony_ci u64 runtime_us; 6862306a36Sopenharmony_ci unsigned int i; 6962306a36Sopenharmony_ci double time_average, time_stddev, event_average, event_stddev; 7062306a36Sopenharmony_ci int err; 7162306a36Sopenharmony_ci struct stats time_stats, event_stats; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci init_stats(&time_stats); 7462306a36Sopenharmony_ci init_stats(&event_stats); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for (i = 0; i < single_iterations; i++) { 7762306a36Sopenharmony_ci atomic_set(&event_count, 0); 7862306a36Sopenharmony_ci gettimeofday(&start, NULL); 7962306a36Sopenharmony_ci err = __machine__synthesize_threads(&session->machines.host, 8062306a36Sopenharmony_ci NULL, 8162306a36Sopenharmony_ci target, threads, 8262306a36Sopenharmony_ci process_synthesized_event, 8362306a36Sopenharmony_ci true, data_mmap, 8462306a36Sopenharmony_ci nr_threads_synthesize); 8562306a36Sopenharmony_ci if (err) 8662306a36Sopenharmony_ci return err; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci gettimeofday(&end, NULL); 8962306a36Sopenharmony_ci timersub(&end, &start, &diff); 9062306a36Sopenharmony_ci runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; 9162306a36Sopenharmony_ci update_stats(&time_stats, runtime_us); 9262306a36Sopenharmony_ci update_stats(&event_stats, atomic_read(&event_count)); 9362306a36Sopenharmony_ci } 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci time_average = avg_stats(&time_stats); 9662306a36Sopenharmony_ci time_stddev = stddev_stats(&time_stats); 9762306a36Sopenharmony_ci printf(" Average %ssynthesis took: %.3f usec (+- %.3f usec)\n", 9862306a36Sopenharmony_ci data_mmap ? "data " : "", time_average, time_stddev); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci event_average = avg_stats(&event_stats); 10162306a36Sopenharmony_ci event_stddev = stddev_stats(&event_stats); 10262306a36Sopenharmony_ci printf(" Average num. events: %.3f (+- %.3f)\n", 10362306a36Sopenharmony_ci event_average, event_stddev); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci printf(" Average time per event %.3f usec\n", 10662306a36Sopenharmony_ci time_average / event_average); 10762306a36Sopenharmony_ci return 0; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int run_single_threaded(void) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct perf_session *session; 11362306a36Sopenharmony_ci struct target target = { 11462306a36Sopenharmony_ci .pid = "self", 11562306a36Sopenharmony_ci }; 11662306a36Sopenharmony_ci struct perf_thread_map *threads; 11762306a36Sopenharmony_ci int err; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci perf_set_singlethreaded(); 12062306a36Sopenharmony_ci session = perf_session__new(NULL, NULL); 12162306a36Sopenharmony_ci if (IS_ERR(session)) { 12262306a36Sopenharmony_ci pr_err("Session creation failed.\n"); 12362306a36Sopenharmony_ci return PTR_ERR(session); 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci threads = thread_map__new_by_pid(getpid()); 12662306a36Sopenharmony_ci if (!threads) { 12762306a36Sopenharmony_ci pr_err("Thread map creation failed.\n"); 12862306a36Sopenharmony_ci err = -ENOMEM; 12962306a36Sopenharmony_ci goto err_out; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci puts( 13362306a36Sopenharmony_ci"Computing performance of single threaded perf event synthesis by\n" 13462306a36Sopenharmony_ci"synthesizing events on the perf process itself:"); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci err = do_run_single_threaded(session, threads, &target, false); 13762306a36Sopenharmony_ci if (err) 13862306a36Sopenharmony_ci goto err_out; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci err = do_run_single_threaded(session, threads, &target, true); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cierr_out: 14362306a36Sopenharmony_ci if (threads) 14462306a36Sopenharmony_ci perf_thread_map__put(threads); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci perf_session__delete(session); 14762306a36Sopenharmony_ci return err; 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int do_run_multi_threaded(struct target *target, 15162306a36Sopenharmony_ci unsigned int nr_threads_synthesize) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct timeval start, end, diff; 15462306a36Sopenharmony_ci u64 runtime_us; 15562306a36Sopenharmony_ci unsigned int i; 15662306a36Sopenharmony_ci double time_average, time_stddev, event_average, event_stddev; 15762306a36Sopenharmony_ci int err; 15862306a36Sopenharmony_ci struct stats time_stats, event_stats; 15962306a36Sopenharmony_ci struct perf_session *session; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci init_stats(&time_stats); 16262306a36Sopenharmony_ci init_stats(&event_stats); 16362306a36Sopenharmony_ci for (i = 0; i < multi_iterations; i++) { 16462306a36Sopenharmony_ci session = perf_session__new(NULL, NULL); 16562306a36Sopenharmony_ci if (IS_ERR(session)) 16662306a36Sopenharmony_ci return PTR_ERR(session); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci atomic_set(&event_count, 0); 16962306a36Sopenharmony_ci gettimeofday(&start, NULL); 17062306a36Sopenharmony_ci err = __machine__synthesize_threads(&session->machines.host, 17162306a36Sopenharmony_ci NULL, 17262306a36Sopenharmony_ci target, NULL, 17362306a36Sopenharmony_ci process_synthesized_event, 17462306a36Sopenharmony_ci true, false, 17562306a36Sopenharmony_ci nr_threads_synthesize); 17662306a36Sopenharmony_ci if (err) { 17762306a36Sopenharmony_ci perf_session__delete(session); 17862306a36Sopenharmony_ci return err; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci gettimeofday(&end, NULL); 18262306a36Sopenharmony_ci timersub(&end, &start, &diff); 18362306a36Sopenharmony_ci runtime_us = diff.tv_sec * USEC_PER_SEC + diff.tv_usec; 18462306a36Sopenharmony_ci update_stats(&time_stats, runtime_us); 18562306a36Sopenharmony_ci update_stats(&event_stats, atomic_read(&event_count)); 18662306a36Sopenharmony_ci perf_session__delete(session); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci time_average = avg_stats(&time_stats); 19062306a36Sopenharmony_ci time_stddev = stddev_stats(&time_stats); 19162306a36Sopenharmony_ci printf(" Average synthesis took: %.3f usec (+- %.3f usec)\n", 19262306a36Sopenharmony_ci time_average, time_stddev); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci event_average = avg_stats(&event_stats); 19562306a36Sopenharmony_ci event_stddev = stddev_stats(&event_stats); 19662306a36Sopenharmony_ci printf(" Average num. events: %.3f (+- %.3f)\n", 19762306a36Sopenharmony_ci event_average, event_stddev); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci printf(" Average time per event %.3f usec\n", 20062306a36Sopenharmony_ci time_average / event_average); 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int run_multi_threaded(void) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct target target = { 20762306a36Sopenharmony_ci .cpu_list = "0" 20862306a36Sopenharmony_ci }; 20962306a36Sopenharmony_ci unsigned int nr_threads_synthesize; 21062306a36Sopenharmony_ci int err; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (max_threads == UINT_MAX) 21362306a36Sopenharmony_ci max_threads = sysconf(_SC_NPROCESSORS_ONLN); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci puts( 21662306a36Sopenharmony_ci"Computing performance of multi threaded perf event synthesis by\n" 21762306a36Sopenharmony_ci"synthesizing events on CPU 0:"); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci for (nr_threads_synthesize = min_threads; 22062306a36Sopenharmony_ci nr_threads_synthesize <= max_threads; 22162306a36Sopenharmony_ci nr_threads_synthesize++) { 22262306a36Sopenharmony_ci if (nr_threads_synthesize == 1) 22362306a36Sopenharmony_ci perf_set_singlethreaded(); 22462306a36Sopenharmony_ci else 22562306a36Sopenharmony_ci perf_set_multithreaded(); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci printf(" Number of synthesis threads: %u\n", 22862306a36Sopenharmony_ci nr_threads_synthesize); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci err = do_run_multi_threaded(&target, nr_threads_synthesize); 23162306a36Sopenharmony_ci if (err) 23262306a36Sopenharmony_ci return err; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci perf_set_singlethreaded(); 23562306a36Sopenharmony_ci return 0; 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciint bench_synthesize(int argc, const char **argv) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int err = 0; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci argc = parse_options(argc, argv, options, bench_usage, 0); 24362306a36Sopenharmony_ci if (argc) { 24462306a36Sopenharmony_ci usage_with_options(bench_usage, options); 24562306a36Sopenharmony_ci exit(EXIT_FAILURE); 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * If neither single threaded or multi-threaded are specified, default 25062306a36Sopenharmony_ci * to running just single threaded. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci if (!run_st && !run_mt) 25362306a36Sopenharmony_ci run_st = true; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (run_st) 25662306a36Sopenharmony_ci err = run_single_threaded(); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (!err && run_mt) 25962306a36Sopenharmony_ci err = run_multi_threaded(); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return err; 26262306a36Sopenharmony_ci} 263