Лучший способ узнать об этом — прочитать исходный код ядра Linux и посмотреть, как вы сами можете эмулировать perf record -g
.
Как вы правильно определили, запись perf events
начнется с системного вызова perf_event_open
. Итак, с чего мы можем начать,
определение perf_event_open
Если вы посмотрите на параметры системного вызова, вы увидите, что первый параметр имеет тип struct perf_event_attr *. Это параметр, который принимает атрибуты для системного вызова. Это то, что вам нужно изменить для записи цепочек вызовов. Пример кода может быть таким (помните, что вы можете настроить другие параметры и элементы структуры perf_event_attr по своему усмотрению):
int buf_size_shift = 8;
static unsigned perf_mmap_size(int buf_size_shift)
{
return ((1U << buf_size_shift) + 1) * sysconf(_SC_PAGESIZE);
}
int main(int argc, char **argv)
{
struct perf_event_attr pe;
long long count;
int fd;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HARDWARE;
pe.sample_type = PERF_SAMPLE_CALLCHAIN; /* this is what allows you to obtain callchains */
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_INSTRUCTIONS;
pe.disabled = 1;
pe.exclude_kernel = 1;
pe.sample_period = 1000;
pe.exclude_hv = 1;
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}
/* associate a buffer with the file */
struct perf_event_mmap_page *mpage;
mpage = mmap(NULL, perf_mmap_size(buf_size_shift),
PROT_READ|PROT_WRITE, MAP_SHARED,
fd, 0);
if (mpage == (struct perf_event_mmap_page *)-1L) {
close(fd);
return -1;
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
printf("Measuring instruction count for this printf\n");
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(long long));
printf("Used %lld instructions\n", count);
close(fd);
}
Примечание. Хороший и простой способ понять, как обрабатывать все эти перфорационные события, можно увидеть ниже —
ИНСТРУМЕНТЫ PMU от Энди Клин
Если вы начнете читать исходный код системного вызова, вы увидите, что функция perf_event_alloc вызывается. Эта функция, среди прочего, настроит буфер для получения цепочек вызовов с помощью perf record
.
Функция get_callchain_buffers отвечает за настройку буферы цепочки вызовов.
perf_event_open
работает через механизм выборки/подсчета, при котором, если счетчик мониторинга производительности, соответствующий событию, которое вы профилируете, переполняется, вся информация, относящаяся к событию, будет собрана и сохранена ядром в кольцевом буфере. Этот кольцевой буфер можно подготовить и получить к нему доступ через mmap(2)
.
Редактировать №1:
Блок-схема, описывающая использование mmap при выполнении perf record
, показана на изображении ниже.
![введите здесь описание изображения](https://i.stack.imgur.com/bNlOw.png)
Процесс mmaping кольцевых буферов начнется с первой функции при вызове perf record
, то есть __cmd_record, это вызывает record__open, который затем вызывает record__mmap, за которым следует вызов record__mmap_evlist, который затем вызывает perf_evlist__mmap_ex, за которым следует perf_evlist__mma p_per_cpu и, наконец, в perf_evlist__mmap_per_evsel, который выполняет большую часть тяжелой работы по созданию mmap для каждого события.
Редактировать № 2:
Да вы правы. Когда вы устанавливаете период выборки, скажем, 1000, это означает, что для каждого 1000-го возникновения события (которое по умолчанию составляет циклы) ядро будет записывать выборку этого события в этот буфер. . Это означает, что счетчики perf
будут установлены на 1000, так что они переполнятся при 0, и вы получите прерывание и, в конечном итоге, запись сэмплов.
person
Arnabjyoti Kalita
schedule
08.03.2018