Кто-нибудь знает, есть ли ограничение на количество PERF_TYPE_HARDWARE
событий, которые мы можем отслеживать в одной группе PERF_FORMAT_GROUP
?
Я пытаюсь отслеживать несколько событий и обнаруживаю, что могу отслеживать 5 событий, но когда я добавляю 6-е аппаратное событие, значения всех зарегистрированных событий не обновляются.
struct read_format {
uint64_t nr; /* The number of events */
struct {
uint64_t value; /* The value of the event */
uint64_t id; /* if PERF_FORMAT_ID */
} values[nr];
};
int main() {
struct perf_event_attr attr1;
attr1.type = PERF_TYPE_HARDWARE;
attr1.config = PERF_COUNT_HW_CPU_CYCLES;
attr1.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;
int main_fd = syscall(__NR_perf_event_open, &attr1, 0, -1, -1, 0);
uint64_t id1;
ioctl(main_fd, PERF_EVENT_IOC_ID, &id1);
ioctl(main_fd, PERF_EVENT_IOC_RESET, 0);
ioctl(main_fd, PERF_EVENT_IOC_ENABLE, 0);
struct perf_event_attr attr2;
attr2.type = PERF_TYPE_HARDWARE;
attr2.config = PERF_COUNT_HW_CACHE_REFERENCES;
attr2.read_format = PERF_FORMAT_GROUP | PERF_FORMAT_ID;
int fd2 = syscall(__NR_perf_event_open, &attr2, 0, -1, main_fd, 0);
uint64_t id2;
ioctl(fd2, PERF_EVENT_IOC_ID, &id2);
ioctl(fd2, PERF_EVENT_IOC_RESET, 0);
ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
/*
commenting out attr3 through attr 7. They are the same as attr2 except the following config:
attr3.config = PERF_COUNT_HW_CACHE_MISSES;
attr4.config = PERF_COUNT_HW_BRANCH_MISSES;
attr5.config = PERF_COUNT_HW_BUS_CYCLES;
attr6.config = PERF_COUNT_HW_STALLED_CYCLES_FRONTEND;
attr7.config = PERF_COUNT_HW_STALLED_CYCLES_BACKEND;
*/
// read_values and log "START"
// action
// read_values and log "END"
return 0;
}
read_values() {
char buffer[4096];
int read_bytes = read(main_fd, &buffer, sizeof(buffer));
if (read_bytes == -1) { return 1; }
struct read_format* rf = (struct read_format*) buffer;
int values[rf->nr];
for (int i=0; i<rf->nr; i++) {
values[i] = rf->values[i].value;
}
}
В приведенном выше коде все зарегистрированные значения в «START» и «END» были обновлены, когда я открываю perf-события только для attr1–5. Однако, когда я пытаюсь открыть perf-события для 6 событий (или всех 7 аппаратных событий), все зарегистрированные значения в «START» и «END» остаются точно такими же.
Я могу получить значения всех 7 событий, если я читаю каждое из них напрямую: int fd2 = syscall(__NR_perf_event_open, &attr2, 0, -1, -1 /*!!instead of main_fd!!*/, 0);
, а затем выполняю read()
для каждого fd
. Но чтобы уменьшить количество вызовов read
, я бы предпочел читать из main_fd
и брать оттуда значения. Есть ли ограничение на количество аппаратных событий, которые можно зафиксировать в одном PERF_FORMAT_GROUP
? Я заметил, что если 6-е и 7-е события являются программными, я не вижу этой проблемы.
Он не компилируется в этом формате. Я скопировал эту структуру непосредственно из документации perf_event_open, чтобы показать файл read_format. Технически это struct { … } values[];
на моей стороне
Решил опубликовать ответ на свой вопрос, пока спускался по кроличьей норе и наткнулся на этот пост. В разделе «Группы событий»:
Количество доступных счетчиков производительности зависит от процессора. Группа не может содержать больше событий, чем доступно счетчиков. Например, процессоры Intel Core обычно имеют четыре общие счетчики производительности для ядра плюс три фиксированных счетчика для инструкций, циклы и реф-циклы. Некоторые специальные события имеют ограничения на то, какой жетон они могут использовать. расписание и может не поддерживать несколько экземпляров в одной группе. Когда слишком много событий указаны в группе, некоторые из них не будут измеряться.
Как вы можете скомпилировать
struct { … } values[nr];
?