Счетчики PMU в ARM11

Я программирую распри pi model b ARM1176 bare metal (в сборке и c). Мне нужно рассчитать тактовые циклы, используемые для выполнения кода сборки.
Я использую следующий код для счетчика PMU:

mov r0,#1 

MCR p15, 0, r0, c15, c12, 0 ; Write Performance Monitor Control Register 
  /* Reset Cycle Counter */ 

mov r0,#5 

MCR p15, 0, r0, c15, c12, 0 ; Write Performance Monitor Control Register 
  /* Meaure */ 

 MRC p15, 0, r0, c15, c12, 1 @ Read Cycle Counter Register 

<MY CODES> 

MRC p15, 0, r1, c15, c12, 1 @ Read Cycle Counter Register 

Из этого, если у меня есть

add r3,#3

вместо моего кода я получаю r1=8 а также r0=0, что кажется правильным, так как arm11 имеет 8 этапов конвейера и для его выполнения требуется 8 тактов.

Но когда я добавляю больше инструкций, я получаю смешные результаты, такие как

add r3,#3

add r4,#1

r0=0,r1=97/96/94 (the result of r1 should also be constant!!!)

я использую uart увидеть результаты реестров на миником.

1 ответ

Хорошо, видеть то же самое, это очень интересно.

    @ nop
.globl test
test:
    mov r0,#1 
    MCR p15, 0, r0, c15, c12, 0 
    mov r0,#5 
    MCR p15, 0, r0, c15, c12, 0 
    MRC p15, 0, r0, c15, c12, 1 

    add r3,#3
    add r2,#1

    MRC p15, 0, r1, c15, c12, 1
    sub r0,r1,r0
    bx lr

Я вызываю это из C, поэтому, если я загляну с r4 в тестируемом коде, мне придется сохранить его в стеке, так что перепутано с r2. Без строки add r2 возвращаемое значение равнялось 8, а для строки add r2 возвращаемое значение было 0x68, а затем 0x65. Обратите внимание, что это на пи ноль. Так что некоторые часы немного быстрее твоих.

Помните, что это исходит от драма, а драм мучительно медленный. Так что вы можете увидеть что-то из этого.

Начальное выравнивание кода:

00008024 <test>:
    8024:   e3a00001    mov r0, #1
    8028:   ee0f0f1c    mcr 15, 0, r0, cr15, cr12, {0}
    802c:   e3a00005    mov r0, #5
    8030:   ee0f0f1c    mcr 15, 0, r0, cr15, cr12, {0}
    8034:   ee1f0f3c    mrc 15, 0, r0, cr15, cr12, {1}
    8038:   e2833003    add r3, r3, #3
    803c:   e2822001    add r2, r2, #1
    8040:   ee1f1f3c    mrc 15, 0, r1, cr15, cr12, {1}
    8044:   e0410000    sub r0, r1, r0
    8048:   e12fff1e    bx  lr

Да, если я раскомментирую nop перед тестом.globl и закомментирую add r2, в качестве тестируемого кода у меня будет только add r3, но nop подталкивает выравнивание всего блока кода. с добавлением r3 и без nop я получаю 8 отсчетов при добавлении r3 и nop я получаю 0x67 отсчетов.

Так что я думаю, что это всего лишь пример измерения выборки. Я не включил кеш руки, но может быть более глубокий кеш, или MMU, или другой, так как этот оперативный диск разделен между рукой и графическим процессором.

Если я сделаю еще один шаг и раскомментирую, то у nop есть как add r3, так и add r2, это 0x69. или в основном на одном уровне или чуть длиннее, чем одна инструкция, поэтому мы принудительно принесли туда.

так что в моем случае, если я добавлю больше nops, чтобы начальное чтение счетчика было выровнено по границе 8 слов, и у меня есть две измеряемые инструкции

00008030 <test>:
    8030:   e3a00001    mov r0, #1
    8034:   ee0f0f1c    mcr 15, 0, r0, cr15, cr12, {0}
    8038:   e3a00005    mov r0, #5
    803c:   ee0f0f1c    mcr 15, 0, r0, cr15, cr12, {0}
    8040:   ee1f0f3c    mrc 15, 0, r0, cr15, cr12, {1}
    8044:   e2833003    add r3, r3, #3
    8048:   e2822001    add r2, r2, #1
    804c:   ee1f1f3c    mrc 15, 0, r1, cr15, cr12, {1}
    8050:   e0410000    sub r0, r1, r0
    8054:   e12fff1e    bx  lr

Я получаю счет 8. Я положил третью инструкцию там добавить r3 и два добавить r2s. все еще счет 8.

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

00008024 <test>:
    8024:   e3a00001    mov r0, #1
    8028:   ee0f0f1c    mcr 15, 0, r0, cr15, cr12, {0}
    802c:   e3a00005    mov r0, #5
    8030:   ee0f0f1c    mcr 15, 0, r0, cr15, cr12, {0}
    8034:   ee1f0f3c    mrc 15, 0, r0, cr15, cr12, {1}
    8038:   e2833003    add r3, r3, #3
    803c:   e2822001    add r2, r2, #1
    8040:   ee1f1f3c    mrc 15, 0, r1, cr15, cr12, {1}
    8044:   e0410000    sub r0, r1, r0
    8048:   e12fff1e    bx  lr

И я делаю три запуска, ничего не меняя, а затем включаю кэш l1 (инструкция) и делаю еще три запуска, которые я получаю

00000068 
0000001D 
0000001D 
0000001F 
00000008 
00000008 

Так что я думаю, что вы имеете дело с медленным драмом, извлекающим строки, отсутствующими в кеше и и попадающими в них, и получающимися в результате выборками из строк кэша.

Если вы ожидали увидеть количество часов, необходимое для выполнения команды, которую вы не хотите, у вас не будет нулевой памяти состояния ожидания, если вы не сможете сохранить весь тестируемый код в кэше l1.

Я не думаю, что на чипе Sram можно использовать для такого рода вещей для этой фишки / платы, вы в конечном итоге попадете в драм, и этот драм передается в gpu. Таким образом, в основном время выполнения программы не должно быть детерминированным, и, как и в случае с вашим компьютером или телефоном, процессор не является узким местом, в течение долгого времени он сидел без дела, ожидая получения данных или инструкций.

Другие вопросы по тегам