Чтение регистров производительности из ядра - PullRequest
1 голос
/ 11 марта 2019

Я хочу прочитать определенные счетчики производительности.Я знаю, что есть такие инструменты, как perf, которые могут сделать это для меня в самом пользовательском пространстве, я хочу, чтобы код был внутри ядра Linux.

Я хочу написать механизм для мониторинга счетчиков производительности на Intel(R) Core (TM) i7-3770 CPU.Помимо использования я использую ядро ​​Ubuntu 4.19.2.Я получил следующий метод от easyperf

Вот часть моего кода для чтения инструкций.

  struct perf_event_attr *attr
  memset (&pe, 0, sizeof (struct perf_event_attr));
  pe.type = PERF_TYPE_HARDWARE;
  pe.size = sizeof (struct perf_event_attr);
  pe.config = PERF_COUNT_HW_INSTRUCTIONS;
  pe.disabled = 0;
  pe.exclude_kernel = 0;
  pe.exclude_user = 0;
  pe.exclude_hv = 0;
  pe.exclude_idle = 0;

  fd = syscall(__NR_perf_event_open, hw, pid, cpu, grp, flags);

  uint64_t perf_read(int fd) {
    uint64_t val;
    int rc;
    rc = read(fd, &val, sizeof(val));
    assert(rc == sizeof(val));
    return val;
  }

Я хочу поместить те же строки в коде ядра (в функции переключатель контекста ) и проверьте считываемые значения.

Моя конечная цель - найти способ считывать счетчики производительности для процесса, каждый раз, когда он переключается на другой, из самого ядра (4.19.2).

Для этого япроверьте код для номера системного вызова __NR_perf_event_open.Его можно найти здесь Чтобы сделать работоспособным, я скопировал код внутри отдельной функции, назвал ее perf_event_open () в том же файле и экспортировал.

Теперь проблема заключается в том, что всякий раз, когда я вызываюperf_event_open () так же, как и выше, возвращается дескриптор -2Проверяя с помощью кодов ошибок , я выяснил, что ошибка была ENOENT.В справочной странице perf_event_open () причина этой ошибки определена как неправильное поле type .

Поскольку файловые дескрипторы связаны с процессом, который их открыл,как можно использовать их из ядра?Есть ли альтернативный способ настроить pmu для начала подсчета без использования файловых дескрипторов?

1 Ответ

3 голосов
/ 11 марта 2019

Возможно, вы не хотите перепрограммировать счетчик внутри функции переключения контекста.

Проще всего было бы сделать системные вызовы из пространства пользователя для программирования PMU (для подсчета какого-либо события, возможно, установив его для подсчета в режиме ядра, но не пространство пользователя, просто счетчик реже переполняется).

Затем просто дважды используйте rdpmc (чтобы получить счетчики запуска / остановки) в своем пользовательском коде ядра. Счетчик будет работать, и я думаю, что Perf-код ядра будет обрабатывать прерывания, когда он оборачивается. (Или когда его буфер PEBS заполнен.)

IDK, если возможно запрограммировать счетчик так, чтобы он просто переносился без прерывания, для таких случаев использования, как этот, когда вас не волнует итоговое или профильное профилирование, и вы просто хотите использовать rdpmc. Если это так, сделайте это.


Старый ответ, касающийся вашего старого вопроса, основанного на глючной строке формата printf, которая печатала ненулевой мусор, даже если вы ничего не учитывали в пользовательском пространстве.

Ваш встроенный ассемблер выглядит правильно, поэтому вопрос в том, что именно этот счетчик PMU запрограммирован для подсчета в режиме ядра в контексте, где работает ваш код.

perf виртуализирует счетчики PMU при переключении контекста, создавая иллюзию perf stat подсчета одного процесса, даже если он мигрирует между процессорами. Если вы не используете perf -a для получения общесистемных подсчетов, PMU может не быть запрограммирован для подсчета чего-либо, поэтому все операции чтения дадут 0, даже если в другое время он запрограммирован для подсчета быстро меняющегося события, такого как циклы или инструкции.


Вы уверены, что perf настроен на подсчет событий пользователя + ядра, а не только событий в пространстве пользователя?

perf stat покажет что-то вроде instructions:u вместо instructions, если оно ограничено пользовательским пространством. (Это значение по умолчанию для не-root, если вы не понизили sysctl kernel.perf_event_paranoid до 0 или что-то из безопасного значения по умолчанию, которое не позволяет пользовательскому пространству узнать что-либо о ядре.)

Имеется поддержка HW для программирования счетчика для подсчета только когда CPL! = 0 (то есть не в кольце 0 / режиме ядра). Более высокие значения для kernel.perf_event_paranoid ограничивают API-интерфейс perf, чтобы не разрешать программирование счетчиков считать в режиме ядра + пользователя, но даже с paranoid = -1 их можно запрограммировать таким образом. Если вы так запрограммировали счетчик, то это все объяснит.

Нам нужно увидеть ваш код, который программирует счетчики. Это не происходит автоматически.

Ядро не просто оставляет счетчики включенными все время, когда ни один процесс не использовал функцию PAPI для включения счетчика для процесса или общесистемного счетчика; это приведет к прерываниям, которые замедляют работу системы без какой-либо выгоды.

...