tools/testing/selftests/net/bench/page_pool/time_bench.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/net/bench/page_pool/time_bench.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/net/bench/page_pool/time_bench.c
Extension
.c
Size
11828 bytes
Lines
395
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct raw_perf_event {
	uint64_t config; /* event */
	uint64_t config1; /* umask */
	struct perf_event *save;
	char *desc;
};

/* if HT is enable a maximum of 4 events (5 if one is instructions
 * retired can be specified, if HT is disabled a maximum of 8 (9 if
 * one is instructions retired) can be specified.
 *
 * From Table 19-1. Architectural Performance Events
 * Architectures Software Developer’s Manual Volume 3: System Programming
 * Guide
 */
struct raw_perf_event perf_events[] = {
	{ 0x3c, 0x00, NULL, "Unhalted CPU Cycles" },
	{ 0xc0, 0x00, NULL, "Instruction Retired" }
};

#define NUM_EVTS (ARRAY_SIZE(perf_events))

/* WARNING: PMU config is currently broken!
 */
bool time_bench_PMU_config(bool enable)
{
	int i;
	struct perf_event_attr perf_conf;
	struct perf_event *perf_event;
	int cpu;

	preempt_disable();
	cpu = smp_processor_id();
	pr_info("DEBUG: cpu:%d\n", cpu);
	preempt_enable();

	memset(&perf_conf, 0, sizeof(struct perf_event_attr));
	perf_conf.type           = PERF_TYPE_RAW;
	perf_conf.size           = sizeof(struct perf_event_attr);
	perf_conf.read_format    = PERF_FORMAT;
	perf_conf.pinned         = 1;
	perf_conf.exclude_user   = 1; /* No userspace events */
	perf_conf.exclude_kernel = 0; /* Only kernel events */

	for (i = 0; i < NUM_EVTS; i++) {
		perf_conf.disabled = enable;
		//perf_conf.disabled = (i == 0) ? 1 : 0;
		perf_conf.config   = perf_events[i].config;
		perf_conf.config1  = perf_events[i].config1;
		if (verbose)
			pr_info("%s() enable PMU counter: %s\n",
				__func__, perf_events[i].desc);
		perf_event = perf_event_create_kernel_counter(&perf_conf, cpu,
							      NULL /* task */,
							      NULL /* overflow_handler*/,
							      NULL /* context */);
		if (perf_event) {
			perf_events[i].save = perf_event;
			pr_info("%s():DEBUG perf_event success\n", __func__);

			perf_event_enable(perf_event);
		} else {
			pr_info("%s():DEBUG perf_event is NULL\n", __func__);
		}
	}

	return true;
}

/** Generic functions **
 */

/* Calculate stats, store results in record */
bool time_bench_calc_stats(struct time_bench_record *rec)
{
#define NANOSEC_PER_SEC 1000000000 /* 10^9 */
	uint64_t ns_per_call_tmp_rem = 0;
	uint32_t ns_per_call_remainder = 0;
	uint64_t pmc_ipc_tmp_rem = 0;
	uint32_t pmc_ipc_remainder = 0;
	uint32_t pmc_ipc_div = 0;
	uint32_t invoked_cnt_precision = 0;
	uint32_t invoked_cnt = 0; /* 32-bit due to div_u64_rem() */

	if (rec->flags & TIME_BENCH_LOOP) {
		if (rec->invoked_cnt < 1000) {
			pr_err("ERR: need more(>1000) loops(%llu) for timing\n",
			       rec->invoked_cnt);
			return false;
		}

Annotation

Implementation Notes