Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * sampleip: sample instruction pointer and frequency count in a BPF map.
  4 *
  5 * Copyright 2016 Netflix, Inc.
  6 */
  7#include <stdio.h>
  8#include <stdlib.h>
  9#include <unistd.h>
 10#include <errno.h>
 11#include <signal.h>
 12#include <string.h>
 13#include <assert.h>
 14#include <linux/perf_event.h>
 15#include <linux/ptrace.h>
 16#include <linux/bpf.h>
 17#include <sys/ioctl.h>
 18#include "libbpf.h"
 19#include "bpf_load.h"
 20#include "perf-sys.h"
 21#include "trace_helpers.h"
 22
 23#define DEFAULT_FREQ	99
 24#define DEFAULT_SECS	5
 25#define MAX_IPS		8192
 26#define PAGE_OFFSET	0xffff880000000000
 27
 28static int nr_cpus;
 29
 30static void usage(void)
 31{
 32	printf("USAGE: sampleip [-F freq] [duration]\n");
 33	printf("       -F freq    # sample frequency (Hertz), default 99\n");
 34	printf("       duration   # sampling duration (seconds), default 5\n");
 35}
 36
 37static int sampling_start(int *pmu_fd, int freq)
 38{
 39	int i;
 40
 41	struct perf_event_attr pe_sample_attr = {
 42		.type = PERF_TYPE_SOFTWARE,
 43		.freq = 1,
 44		.sample_period = freq,
 45		.config = PERF_COUNT_SW_CPU_CLOCK,
 46		.inherit = 1,
 47	};
 48
 49	for (i = 0; i < nr_cpus; i++) {
 50		pmu_fd[i] = sys_perf_event_open(&pe_sample_attr, -1 /* pid */, i,
 51					    -1 /* group_fd */, 0 /* flags */);
 52		if (pmu_fd[i] < 0) {
 53			fprintf(stderr, "ERROR: Initializing perf sampling\n");
 54			return 1;
 55		}
 56		assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_SET_BPF,
 57			     prog_fd[0]) == 0);
 58		assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE, 0) == 0);
 59	}
 60
 61	return 0;
 62}
 63
 64static void sampling_end(int *pmu_fd)
 65{
 66	int i;
 67
 68	for (i = 0; i < nr_cpus; i++)
 69		close(pmu_fd[i]);
 70}
 71
 72struct ipcount {
 73	__u64 ip;
 74	__u32 count;
 75};
 76
 77/* used for sorting */
 78struct ipcount counts[MAX_IPS];
 79
 80static int count_cmp(const void *p1, const void *p2)
 81{
 82	return ((struct ipcount *)p1)->count - ((struct ipcount *)p2)->count;
 83}
 84
 85static void print_ip_map(int fd)
 86{
 87	struct ksym *sym;
 88	__u64 key, next_key;
 89	__u32 value;
 90	int i, max;
 91
 92	printf("%-19s %-32s %s\n", "ADDR", "KSYM", "COUNT");
 93
 94	/* fetch IPs and counts */
 95	key = 0, i = 0;
 96	while (bpf_map_get_next_key(fd, &key, &next_key) == 0) {
 97		bpf_map_lookup_elem(fd, &next_key, &value);
 98		counts[i].ip = next_key;
 99		counts[i++].count = value;
100		key = next_key;
101	}
102	max = i;
103
104	/* sort and print */
105	qsort(counts, max, sizeof(struct ipcount), count_cmp);
106	for (i = 0; i < max; i++) {
107		if (counts[i].ip > PAGE_OFFSET) {
108			sym = ksym_search(counts[i].ip);
109			if (!sym) {
110				printf("ksym not found. Is kallsyms loaded?\n");
111				continue;
112			}
113
114			printf("0x%-17llx %-32s %u\n", counts[i].ip, sym->name,
115			       counts[i].count);
116		} else {
117			printf("0x%-17llx %-32s %u\n", counts[i].ip, "(user)",
118			       counts[i].count);
119		}
120	}
121
122	if (max == MAX_IPS) {
123		printf("WARNING: IP hash was full (max %d entries); ", max);
124		printf("may have dropped samples\n");
125	}
126}
127
128static void int_exit(int sig)
129{
130	printf("\n");
131	print_ip_map(map_fd[0]);
132	exit(0);
133}
134
135int main(int argc, char **argv)
136{
137	char filename[256];
138	int *pmu_fd, opt, freq = DEFAULT_FREQ, secs = DEFAULT_SECS;
139
140	/* process arguments */
141	while ((opt = getopt(argc, argv, "F:h")) != -1) {
142		switch (opt) {
143		case 'F':
144			freq = atoi(optarg);
145			break;
146		case 'h':
147		default:
148			usage();
149			return 0;
150		}
151	}
152	if (argc - optind == 1)
153		secs = atoi(argv[optind]);
154	if (freq == 0 || secs == 0) {
155		usage();
156		return 1;
157	}
158
159	/* initialize kernel symbol translation */
160	if (load_kallsyms()) {
161		fprintf(stderr, "ERROR: loading /proc/kallsyms\n");
162		return 2;
163	}
164
165	/* create perf FDs for each CPU */
166	nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
167	pmu_fd = malloc(nr_cpus * sizeof(int));
168	if (pmu_fd == NULL) {
169		fprintf(stderr, "ERROR: malloc of pmu_fd\n");
170		return 1;
171	}
172
173	/* load BPF program */
174	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
175	if (load_bpf_file(filename)) {
176		fprintf(stderr, "ERROR: loading BPF program (errno %d):\n",
177			errno);
178		if (strcmp(bpf_log_buf, "") == 0)
179			fprintf(stderr, "Try: ulimit -l unlimited\n");
180		else
181			fprintf(stderr, "%s", bpf_log_buf);
182		return 1;
183	}
184	signal(SIGINT, int_exit);
185	signal(SIGTERM, int_exit);
186
187	/* do sampling */
188	printf("Sampling at %d Hertz for %d seconds. Ctrl-C also ends.\n",
189	       freq, secs);
190	if (sampling_start(pmu_fd, freq) != 0)
191		return 1;
192	sleep(secs);
193	sampling_end(pmu_fd);
194	free(pmu_fd);
195
196	/* output sample counts */
197	print_ip_map(map_fd[0]);
198
199	return 0;
200}