LINUX.ORG.RU
ФорумTalks

Расскажите про современный Hyper-threading

 ,


1

3

На момент появления, технология Hyper-threading решала вопрос неполной загрузки супер-сверх-длинного конвеера ЦП. Да, речь про времена интел прескот. И это было понятно.

Сейчас у интеля очень эффективное ядро с лучшей однопоточной производительностью. И почему-то есть гипертрейдинг. А что оно, собственно, делает в современных ЦП?

★★★★★

Дело не только и не столько в конвейере. Разные команды используют разные блоки процессора, и пока, например, команда

mov RAX, [0DEADBEEFh]

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

quwy
()

Непонятно что делает. Но все проги показывают, что у меня 4 ядра (физических - 2) и нагрузку на них показывают.

Так что это как-то работает. Колдунство.

utanho ★★★★★
()
Ответ на: комментарий от targitaj

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

cobold ★★★★★
()
Ответ на: комментарий от DumLemming

А то что один поток на ядре выдаёт меньше попугаев чем два - это такие технологии энегросбережения, да?

Не, очевидно же, спецом зарезали, чтобы не палиться)

goingUp ★★★★★
()
Ответ на: комментарий от quwy

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

Допустим, есть одно ядро (два потока) и 8 потоков в программе/ОС, 7 из которых чаще стопорятся на запросе к памяти, а последний 8-ой чаще готов числодробить. То даже если сначала один из первых 7-ми и 8-ой попадут на исполнение, потом 8-ой будет прерван и на исполнении окажутся оба блокирующих по памяти. В итоге ядро всё равно будет чаще простаивать, т.к. 8-ой поток - всего один из 8-ми, которому чаще всего хватает данных для перемолки.

gag ★★★★★
()
Ответ на: комментарий от DumLemming

Это смотря что у вас за попугаи. В среди игроков существует поверье что, если smt/ht выключить, то фпс в определенных играх вырастет. Сам не пробовал к стыду своему, но признаться некоторая логика в этом есть

cobold ★★★★★
()

Уже не будет, скорее всего с 15 поколения. После ещё через поколение может будет x86s, где выпилят 16, 32 бит совместимость.

ac130kz ★★
()
Ответ на: комментарий от cobold

Это смотря что у вас за попугаи. В среди игроков существует поверье что, если smt/ht выключить, то фпс в определенных играх вырастет. Сам не пробовал к стыду своему, но признаться некоторая логика в этом есть

Это стандартная рекомендация от AMD, Intel, RedHat, SLES и пр. для максимизации performance в одном потоке.

soomrack ★★★★
()

Hyper-threading решала вопрос неполной загрузки супер-сверх-длинного конвеера ЦП

Решала вопрос загрузки как можно большего числа исполнительных блоков. Ничего с тех пор не поменялось.

ox55ff ★★★★★
()

Сейчас у интеля очень эффективное ядро с лучшей однопоточной производительностью

хватит врать

B084 ★★
()

что оно, собственно, делает в современных ЦП?

То же самое что и раньше.

no-such-file ★★★★★
()
Ответ на: комментарий от gag

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

quwy
()
Ответ на: комментарий от DarkAmateur

Пушо это не спарк, набор регистров и длина конвейера не резиновые.

harbinger
()
Ответ на: комментарий от targitaj

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

Например в skylake 4 ALU на ядро https://en.wikichip.org/wiki/intel/microarchitectures/skylake_(server):

Execution Unit# of UnitsInstructions
ALU4add, and, cmp, or, test, xor, movzx, movsx, mov, (v)movdqu, (v)movdqa, (v)movap*, (v)movup*
DIV1divp*, divs*, vdiv*, sqrt*, vsqrt*, rcp*, vrcp*, rsqrt*, idiv
Shift2sal, shl, rol, adc, sarx, adcx, adox, etc…
Shuffle1(v)shufp*, vperm*, (v)pack*, (v)unpck*, (v)punpck*, (v)pshuf*, (v)pslldq, (v)alignr, (v)pmovzx*, vbroadcast*, (v)pslldq, (v)psrldq, (v)pblendw
Slow Int1mul, imul, bsr, rcl, shld, mulx, pdep, etc…
Bit Manipulation2andn, bextr, blsi, blsmsk, bzhi, etc
FP Mov1(v)movsd/ss, (v)movd gpr
SIMD Misc1STTNI, (v)pclmulqdq, (v)psadw, vector shift count in xmm
Vec ALU3(v)pand, (v)por, (v)pxor, (v)movq, (v)movq, (v)movap*, (v)movup*, (v)andp*, (v)orp*, (v)paddb/w/d/q, (v)blendv*, (v)blendp*, (v)pblendd
Vec Shift2(v)psllv*, (v)psrlv*, vector shift count in imm8
Vec Add2(v)addp*, (v)cmpp*, (v)max*, (v)min*, (v)padds*, (v)paddus*, (v)psign, (v)pabs, (v)pavgb, (v)pcmpeq*, (v)pmax, (v)cvtps2dq, (v)cvtdq2ps, (v)cvtsd2si, (v)cvtss2si
Vec Mul2(v)mul*, (v)pmul*, (v)pmadd*

Просвещайся.

ox55ff ★★★★★
()
Ответ на: комментарий от slyjoeh

Если учитывать производительность на условный мегагерц частоты, то m1 и m2 значительно быстрее.

Интел просто задрал частоты по самое немогу

B084 ★★
()
Ответ на: комментарий от B084

Если учитывать производительность на условный мегагерц частоты, то m1 и m2 значительно быстрее.

А смысл их учитывать, если нет высоких частот? Другое дело (следствие частот) производительность на ватт.

exst ★★★★
()
Ответ на: комментарий от DarkAmateur

HT дает в среднем прирост 35%. Т.е. смотри кол-во потоков увеличили на 100%, а прирост получили 35%, если увеличить до 4 потоков на ядро, получим около 10%. Эти потоки шарят между собой L1/L2 кэши, шину, TLB. Есть задачи, которые паралелятся лучше, для них есть Xeon Phi с 4t/1c. Так же существовали sparc в конфиге 16c 128t, есть IBM Power9 с 4t/1c

cobold ★★★★★
()
Ответ на: комментарий от B084

Эдак можно сказать что apple silicon просто задрал L1/L2 кэши и подсистему памяти. В сухом остатке то что? Кесарю - кесарево, слесарю - слесарево.

cobold ★★★★★
()
Ответ на: комментарий от B084

У apple silicon нейросетка же. Когда задача идет мимо нее, а это случается очень часто, проц превращается в тыкву и жор неимоверный.

slyjoeh ★★★
()
Последнее исправление: slyjoeh (всего исправлений: 1)
Ответ на: комментарий от cobold

кеши лишь следствие

у эпла очень широкая архитектура, которая может исполнять до восьми инструкци за такт. и очень глубокий OoO, который способен заполнить исполнительные блоки независимыми друг от друга инструкциями, позволяя работать со скоростью 8-ми инструкций за такт довольно часто. следствие этого - необходимость в больших Кешах, особенно l1i

а Интел что, сделал свою архитектору шире только в alder lake, и какой ценой - проц опять под двести ватт жрет

B084 ★★
()
Ответ на: комментарий от ox55ff

И в результате получить то, что мы имеем на синем говне - фризы на ровном месте. Вот из-за этих переключений.

targitaj ★★★★★
() автор топика
Ответ на: комментарий от slyjoeh

У apple silicon нейросетка же. Когда задача идет мимо нее, а это случается очень часто, проц превращается в тыкву и жор неимоверный.

Вы откуда такое вычитали? Я и на интеле устраивал «жор неимоверный» без шуток, случайно не прибитая простая команда в терминале, и вот привет, ноут жрет «как не в себя». Команда реально простая, типа watch ls.

anc ★★★★★
()
Ответ на: комментарий от ox55ff

Каким образом два конвеера будут использовать одно устройство? Каким образом бранчпредиктор будет эти конвееры обслуживать? Нет там никаких дополнительных конвееров и в них нет никакого смысла, потому что процессору контексты надо разделять не между коммандами, а между данными в регистрах, надо каким то образом разделить их и не позволить командам из одного потока получить регистры другого.

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

uin ★★★
()

Уточните, про какое «сейчас» идет речь. В Skylake примерно половина десктопных процов было без HT, в Cofee Lake 3/4 десктопных процов без HT.

Сейчас у интеля очень эффективное ядро с лучшей однопоточной производительностью

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

byko3y ★★★★
()
Ответ на: комментарий от B084

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

Вы говорите «эпл», будто эпл что-то разрабатывает. Так и пишите «армовая архитектура с широким конвеером». Это ведь A78 с минимальной адаптацией.

Проблема глубоких OoO в том, что жор электричества растет примерно пропорционально параллелизации, в том числе из-за большего размера кэша — а зачем оно надо, особенно на мобильных процах? На серверах, внезапно, потребление энергии является ограничивающим фактором, но не из-за батарейки, а из-за тепловыделения. Да, по сравнению с x86 выглядит лучше, но по сравнению с x86 всё выглядит лучше, потому что это давно неактуальная архитектура, которая живет по традиционной айтишной инерции, составляющей порядка 10-20 лет, и только сейчас платформы 12-летней давности начинают неспешно внедряться в сервера.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Разрабатывают.
Эпл еще во времена айфона 4 купили фирму которая системы на кристале соединяла из покупных ядер, и помоему замнтересовала эпл тем что делала какие то доработки в gpu PowerVR. Раньше в айфонах стояли микросхемы самсунга, с A4 начались свои системы на кристале. Спустя десятилетия вливаний бабла в эту контору, к A7X полностью избавились от необходимости покупать PowerVR, а спустя еще пару лет сделали остаточный прощевай ядрам Cortex.

То что m1 использует систему команд aarch, не значит что его ядро разработали арм. Есть специальная лицензия позволяющая разрабатывать свой арм-совместимый чип, такие есть у самсунга и квалкома к примеру.

uin ★★★
()
Ответ на: комментарий от byko3y

Да, по сравнению с x86 выглядит лучше, но по сравнению с x86 всё выглядит лучше, потому что это давно неактуальная архитектура

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

uin ★★★
()
Ответ на: комментарий от uin

Эпл еще во времена айфона 4 купили фирму которая системы на кристале соединяла из покупных ядер, и помоему замнтересовала эпл тем что делала какие то доработки в gpu PowerVR

Давай не мешать всё в кучу, GPU — это совершенно иной вопрос, оно занимает отдельное место на SoC. И да, Apple в том числе заманила к себе инженеров из AMD с этой целью.

Спустя десятилетия вливаний бабла в эту контору, к A7X полностью избавились от необходимости покупать PowerVR, а спустя еще пару лет сделали остаточный прощевай ядрам Cortex

Процессоры A12-13-14-15-16 — это и есть кортексы A7*/A71* с минимальными модификациями, они совпадают по фичам, отличаясь лишь всякими ширинами пайплайнов, размерами кэшей, и расширениями.

То что m1 использует систему команд aarch, не значит что его ядро разработали арм. Есть специальная лицензия позволяющая разрабатывать свой арм-совместимый чип, такие есть у самсунга и квалкома к примеру

ARM давно не производит своих микросхем, ВСЕ процессоры ARM произведены по лицензии. Другое дело, что схемотехника из того же A78 может быть повторена на 99%, как у медиатека, или на 95%, как у Apple. Это совсем не та же ситуация, что с GPU, которое скорее всего пересоздано с нуля.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Как бы там нибыло микроархитектура apple m1 разработана с нуля, она не похожа на кортексы и скорее похожа на е2к с толстым микрокодом.

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

uin ★★★
()
Ответ на: комментарий от uin

у эпл m1 точно так же все идет через жирный фронтенд с переименованием регистров, если все десктопные армы будут такими непонятно зачем тогда нужны команды фиксированной длинны

Для упрощения декодера, особенно на энергоэффективных ядрах (которые в том числе есть на M1/A14). Да, на высокоскоростных ядрах дальше идет переименования-диспетчеризация, но то уже их проблемы. И да, ARM всегда был CISC архитектурой с упрощенным декодированием инструкций — мне смешно читать, что кто-то называет RISC-ом архитектуру с 1000+ инструкциями, включая инструкции «записать все регистры в пямять» и «прочитать все регистры из памяти», а комбинации movz+movk и adr+adrp транслируются в одну инструкцию (аналог длинных инструкций mov в x86).

Из за которых к слову флаги были отменены как ненужные, в пользу условных комманд как у интела

Все архитектуры ARM до AArch64 были неполноценными, поскольку опирались на непрямое чтение констант, из-за чего на них нельзя было эффективно реализовать классические кэши. Это обычно не являлось проблемой, потому что кэшей на армах просто не было.

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

Добавь к этому еще убогий simd который очень стесняется копировать интеловские команды (чтоб не засудили) и поэтому городит вот такую херню

Лично я склоняюсь к тому, что интелевый SIMD — говно.

byko3y ★★★★
()
Ответ на: комментарий от uin

Как бы там нибыло микроархитектура apple m1 разработана с нуля, она не похожа на кортексы и скорее похожа на е2к с толстым микрокодом

Кортексы скопированы до мелочей, вроде SVE, big.LITTLE, и DynamIQ. Я могу быть не прав, но я пока не видел указаний на то, чтобы M1/A14 отличались от кортексов архитектурно, а не в мелочах, которые и так отличаются у всех лицензиатов.

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

На M1 и A14 стоят одинаковые ЦП.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

кто-то называет RISC-ом архитектуру с 1000+ инструкциями

По такой логике тогда и power с mips это циски.

Лично я склоняюсь к тому, что интелевый SIMD — говно.

Подозреваю по такой же логике какой записываешь риск в циск.

Я могу быть не прав, но я пока не видел указаний на то, чтобы M1/A14 отличались от кортексов архитектурно, а не в мелочах

Могстроузная подсистема памяти, банально размер кэшей: cortex-a78

apple m1

Даже нижние «энергоэффективные» ни на какой из предлагаемых армов не походят, а походят на верхние просто в два раза урезанные.

L2 Shared Cache вообще нигде кроме интелловских чипов не встречается, у всех L2 локальный и сверху идет общий L3, потому что это проще. И только интел в core 2 заморочилась с общим L2 кэшом - 2МB на два ядра в 65нм, и 3MB в 45нм, потом был откат назад, потому что надо было представить на рынок полноценные многоядерные чипы со встронным контроллером, а не двухъядерники лепить на одной подложке. Потом уже не знаю, но помоему только в пентиумах это продолжало применяться, а в больших процессорах поперла кольцевая шина с банками L3 кэша, в такой схеме общий L2 уже не имеет смысла.

uin ★★★
()
Ответ на: комментарий от uin

По такой логике тогда и power с mips это циски

Старые SPARC и MIPS были типичными RISC, на порядок проще ARM и x86, про современные не подскажу.

Лично я склоняюсь к тому, что интелевый SIMD — говно.

Подозреваю по такой же логике какой записываешь риск в циск

Я про ужасную совместимость-переносимость интелевого SIMD.

L2 Shared Cache вообще нигде кроме интелловских чипов не встречается, у всех L2 локальный и сверху идет общий L3, потому что это проще.

Пф-ф-ф:
https://www.anandtech.com/show/8718/the-samsung-galaxy-note-4-exynos-review/5
Это Cortex-A57. В интернетах есть поверхностные указания на разделяемый L2 кэш на группу ядер в архитектуре big.LITTLE, но каких-то глубоких технических подробностей быстро не нашлось.

Разделяемый кэш есть в любом случае, и не важно, называется ли он L2 или L3, потому аргумент про «проще» не засчитывается. Предполагаю, что в случае M1 L2 просто не используется, а последний уровень наращивается через CoreLink:
https://developer.arm.com/Processors/CoreLink CCI-400
Это та самая архитектура big.LITTLE, которая рисуется в интернетах (L1 в ядре, L2 на группу энергоэффективности, дальше межпроцессорное соединение). Но, опять же, пока у нас нет фактов, а есть только догадки. Тем не менее, главное — что подобная M1 архитектура кэшей у Cortex уже была до Apple.

Даже нижние «энергоэффективные» ни на какой из предлагаемых армов не походят, а походят на верхние просто в два раза урезанные

Максимальные подробности по схемотехнике M1, которые мне удалось находить — это квадратик на месте ядра. Всё, дальше додумывай что хочешь. Пока что ты мне принес очередные квадратики.

И только интел в core 2 заморочилась с общим L2 кэшом - 2МB на два ядра в 65нм, и 3MB в 45нм

Поправь меня, если я не прав, но в core 2 не было L3 кэша. Логично, что функцию кэша последнего уровня выполнял L2.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Старые SPARC и MIPS были типичными RISC

А новые ты выписал, потому что захотелось. Понятно.

Я про ужасную совместимость-переносимость интелевого SIMD.

А чей ассемблер имеет хоть какую то совместимость-переносимость? Каждый городит свое isa по своему, никаких общих стандартов нет.

Кэш L2, с другой стороны, настраивается индивидуально для каждого SoC. A57 поддерживает кэш L2 размером от 512 КБ до 2 МБ, при этом кэш является 16-портовым-ассоциативным. Каждое ядро A57 получает свой собственный интерфейс к кэшу L2, поэтому на уровне интерфейса нет разделения полосы пропускания.

Cortex-A57 cores clocked at 2.0 GHz. Each A57 ARM core in the SOC features 512KB of L2 cache for a total of 4 MB for the eight cores.

Ну ты понял, есть 16портовый интерфейс и размер от 512кб, можешь поделить его с A53 и сделать общим, а можешь отдать весь и сделать локальным. Эпл m1 в принципе реализует что то похожее, как я понял у маленьких ядер кэш совмещенный с большими ядрами, а у больших + ещё 4мб своих, это именно что похоже на core 2 где два ядра подключены к одному кэшу, а не делят один интерфейс. Но это только кэш второго уровня, а еще есть кэш инструкций 128KB у «маленьких» и 192KB у больших, только одно это опровергает твою теорию о том что там просто арм ядро, нет ни одного арм ядра с такими кэшами. Как тебе и сказали туда вхерачили очень длинный OoO фронтенд, бакенд тоже свой, с дырой в безопасности связанной с гуляющими из процедуры в процедуру булевыми предикатами.

uin ★★★
()
Последнее исправление: uin (всего исправлений: 1)
Ответ на: комментарий от uin

Старые SPARC и MIPS были типичными RISC

А новые ты выписал, потому что захотелось

Потому что они находятся в промежуточном положении, и мне даже не интересно выяснять, к чему они ближе. Это лишь с ARM однозначно понятно, что он всегда был CISC архитектурой с самого начала, в какой-то момент просто став на 100% удовлетворять самым строгим определениям CISC, требующим переменную длину инструкции, появившуюся в Thumb.

А чей ассемблер имеет хоть какую то совместимость-переносимость? Каждый городит свое isa по своему, никаких общих стандартов нет

У SVE хорошая переносимость, пользователи GPGPU не дадут соврать.

Кэш L2, с другой стороны, настраивается индивидуально для каждого SoC. A57 поддерживает кэш L2 размером от 512 КБ до 2 МБ, при этом кэш является 16-портовым-ассоциативным. Каждое ядро A57 получает свой собственный интерфейс к кэшу L2, поэтому на уровне интерфейса нет разделения полосы пропускания.

Каждая пара ядер имеет по 1 МБ L2 кэша, поверх них еще один разделяемый уровень

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

Эпл m1 в принципе реализует что то похожее, как я понял у маленьких ядер кэш совмещенный с большими ядрами, а у больших + ещё 4мб своих, это именно что похоже на core 2 где два ядра подключены к одному кэшу, а не делят один интерфейс.

Откуда инфа о том, кто там как делит кэши в M1?

еще есть кэш инструкций 128KB у «маленьких» и 192KB у больших

Я тебя умоляю, удвоить кэш — это серьезная архитектурная задача? Я потому и писал, что Apple взял от арма только 95% схемотехники, всё остальное делал сам.

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

У A77 и Neoverse N1 плюс-минус подобная суперскалярность. Вот про дыру в безопасности это интересный аргумент. Если подобной нет в обычных армах — это указывает на уникальную кастомизацию в этом месте.

byko3y ★★★★
()
Ответ на: комментарий от byko3y

Потому что они находятся в промежуточном положении, и мне даже не интересно выяснять, к чему они ближе

Академически чистый RISC как и VLIW никому не нужен, если там нет нужного набора комманд и код выполняется медленнее. А классический риск не может быть быстрым, потому что если риск без фронтенда то у тебя 32 регистра и при возвратах нужно постоянно восстанавливать их со стека.
Спарк в рамках классического риска решил вопрос окном, теперь при переходах и возвратах окно просто туда сюда ездит. Но и это решение упирается в те же риск грабли - окно занимает всегда 32 регистра, не больше и не меньше, хотя на реальных задачах в процедуре может потребоваться 48 регистров или скажем 4 вызовова по 8 регистров в каждом. Переименование эффективней использует регистровый фаил, поэтому его в рсновном все используют, а окна больше никто , (кроме эльбруса, но у эльбруса широкие команды в них есть место куда впихнуть операции динамического задания размеров окна + сама идея подразумевает перекладывать такие вещи на компилятор).

И то же самое примерно с риск командами - для того что бы декодировать fp16 (используется в сжатых данных) в fp32 нужно примерно 20 риск комманд, в основном простых-битовых но блин 20 комманд. Еще и фиксированной длинны вся эта мелочь заполоняет и так небольшой кэш инструкции, так не лучше ли закодировать алгоритм конвертации fp16<->fp32 в одну команду и добавить в расширенный набор инструкций? Вот ты и раздул ISA до 1000+ комманд и даже если начнешь с чистого листа все равно получиться только выкинуть неиспользующиеся но vmax vmin все равно добавишь потому что используются они часто и заменяют 3-4 комманды.

Переименование - чек
Толстый набор инструкций - чек

Остается только переменную длинну ввести для пущей экономии кэшей.

uin ★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)