Search
Write a publication
Pull to refresh
27
0
Виктор @byman

Пользователь

Send message

обычно используют кальку "байпас" или просто - обходной путь. Но у Вас как-то живее. Если бы кэш был ОН, а память ОНА, то фраза "она меня пробросила" была бы в точку :)

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

Здесь Вы сделали изобретение до которого в свое время не могли додуматься инженеры Analog Devices в своих DSP, У них традиционно были две памяти - память программ и память данных. Но память программ делалась двухпортовой т.к. в одном такте DSP мог делать две операции с данными. Одна из таких операций могла давать конфликт с чтением команды из памяти программ. И только со временем у них появился кэш, который хранил только "конфликтные" инструкции.

Впечатляющий труд. В однотактную модель Вы смогли вместить и кэш-память. Очень интересное слово "проброс". Никогда не встречал. Насколько я понял, так Вы обозначаете ситуацию когда вместо кэша результат дает память. По сути сейчас (из той версии кода, что я смотрел) у Вас кэш и внешняя память работают параллельно за один такт. Если где-то подкачал кэш - выручает память. Поэтому никаких потерь в коремарке и не обнаружилось.

По всему видно у Вас хороший компилятор, т.к. мой даже не стал векторизовать начальный код :) Да и интринсики у меня тоже не работают :) Пришлось мне Ваш итоговый код набрать ассемблером

unsigned int task_1_vector_fast(unsigned int n) {
	unsigned int sum;
	n--;
	    asm volatile("vsetivli x0, 3, e32, m1");
	   	asm volatile("vmv.v.x v3,  %0 ;" ::"r"(n)); // v3=n-1
		asm volatile("vle32.v v1, (%0);" ::"r"(c)); // v1  = c
		asm volatile("vmul.vv v4,v3,v1 ;"); // v4 = klm = (n-1)*c
		asm volatile("vle32.v v2, (%0);" ::"r"(d)); // v2 = d
		asm volatile("vsrl.vi v4,v4,16;");  // klm>>=16
		asm volatile("vmv.v.i v8, 0");      // sum=0
		asm volatile("vadd.vi v5,v4,1 ;");  // v5=klm+1
		asm volatile("vmul.vv v6,v4,v5 ;"); // v6 = klm*(klm+1)
		asm volatile("vmul.vv v6,v6,v2 ;"); // v6 = d * klm*(klm+1)
		asm volatile("vsra.vi v6,v6,1;");   // v6 = d * klm*(klm+1)/2
		asm volatile("vredsum.vs  v8, v6, v8");
		asm volatile("vmv.x.s %0, v8" : "=r"(sum) :);  // return = sum

	return sum;
}

Скалярный вариант исполнился за 19 тактов, а векторный за 26. Итого 0.73 У Вас 0.69. Практически одинаковое "ускорение" от векторизации :)

Вы в своем коде напрочь игнорируете скобки, там где они и не нужны особо. Это явный признак профи (старичка). Я вот себе такого не позволяю и все беру в скобки, и потом пересчитываю чтобы открывающих было ровно столько сколько закрывающих

Я пишу if(nres==0) уже лет 25 и даже не задумываюсь, что это признак новичка :) Я просто на это не обращаю внимания. Вот если бы книга Харрисов уже тогда была мне доступна, то у меня вошло бы в привычку писать if(!nres)

надеюсь, что это еще не завершение. У автора часто звучит "кэши", "ООО". Так что продолжение должно следовать. Не боги процессоры обжигают :)

Я Харрисов не читал.

Значит у Вас талант к процессорам ибо Вы идеально точно повторили в первой части однотактную модель, приведенную в их книге.

А я вот не понял ни вопроса Юрия , ни Вашего ответа. Вот если бы вопрос был в стиле книги Харрисов (еще раз спасибо DmitryZlobec) :"Какое несоответствие между рисунком паровозика и приложенной к нему модели ?" Такой вопрос был бы мне понятен.

Отличный результат. В части 3 я Вам написал в комментарии:

В РС пишется то, что и ранее. А вот наружу выдается  pc_result и там защелкивается в буфере синхронной памяти. Так работает память. Для данных вы читаемые данные не получите в текущем такте, только в следующем. И нужен будет дополнительный порт записи в РОНы. Еще нужен будет bypass для загружаемых данных чтобы следующая команда не тормозила, если эти данные нужны ей.

И у Вас будет и синхронная стандартная память, и однотактная модель.

К моему удовольствию, Вы сделали то, о чем я Вас просил. Вам нужно только еще почитать как делать побайтовую запись в память и все будет отлично. Проблема чтения после записи Вами выдумана по незнанию как работает синхронная память. Команда записи может выполняться в том же такте , что и команды АЛУ. Результат АЛУ можно было и не передавать на следующую стадию, а писать сразу в РОН. А вот что Вы хорошо сделали, так это bypass данных команд LD.

В итоге у вас все та же однотактная модель ,но с синхронной памятью . И это уже здорово.

Кстати, именно поэтому Вы не потеряли на коремарке ничего. Ну только несколько сотен тактов на выдуманной (для данной модели !) проблеме чтения после записи.

Если добавить unroll-loops да inline , то даже до 3.72 добираемся :) Правда кода в 3 раза больше.

С векторным расширением это уже совсем другая модель и она проигрывает по коремаркам модели автора :)

Кстати, автору нужно как-то назвать ядро. А то без имени уже третью часть.

Вы можете и в сети найти такой модуль, но лучше самому добавить. Там простые команды. Когда-то в этом расширении были сложные команды, но в окончательной редакции их повыбрасывали. Обратите внимание на деление В расширения на группы. Можете добавлять по частям zba+zbb+zbs и смотреть влияние каждой подгруппы на результат.

В этой версии работает даже векторизация. Я был удивлен , когда увидел, что при выполнении коремарка шевелятся векторные регистры. Прибавка от векторного расширения составила аж 0.006 :)

Оказывается, там только оглавление и мусор. Ну да ладно. Все равно спасибо :)

Провел интересные эксперименты с моделью автора и коремарком. Как уже автор писал, у него показатель см/мгц равен 3.2 при однотактном исполнении всех команд. Вчера я добавил в его модель В-расширение . Получил 3.292 за счет набора zba_zbb_zbs. Сегодня я скачал с сайта Syntacore свежий инструмент с версией компилятора 14.2 . Прежняя версия была 13.2 . На новой версии компилятора показатель 3.3556. Видно, что прогресс у RISC-V не стоит на месте.

Спасибо. Особенно , что на русском. А то я со своим испанским ни беса, ни муччо

Возможно Вы правы. Я так вообще никогда не читал этого автора и в правильных названиях могу ошибаться. Слово "выполнение" мне непонятно. Получается, что если умножение не за 1 такт, то уже многотактовая архитектура? А если выполнение умножения поделено на две части: одна на одной стадии конвейера, а вторая на другой. Это однотактовая? Нужно как-то определиться с правильными названиями, чтобы любой мог понять о чем здесь разговор.

Вы описали конвейерную архитектуру и в ней действительно все команды могут исполняться за один такт. Но от момента начала чтения команды Х , до момента записи результата этой команды в GPR, пройдет несколько тактов. Длина (глубина) конвейера. Сейчас у нас эта длина равна 1. И лично я вижу в такой модели интересность :)

1
23 ...

Information

Rating
6,305-th
Location
Беларусь
Registered
Activity