Введение. 3

Технология SIMD.. 4

Краткое обозрение технологий SIMD.. 5

Технология MMX.. 5

SSE.. 5

SSE2. 6

SSE3. 6

Микроархитектура Intel NetBurst 7

Цели, для которых была разработана Микроархитектура Intel NetBurst 7

Обзор конвейера микроархитектуры Intel NetBurst 7

Блок начальной загрузки. 8

Беспорядочное ядро. 9

Секция изъятий. 9

Обзор блока начальной загрузки конвейера. 11

Предвыборка. 11

Декодер. 11

Исполнительный кэш трасс. 11

Предсказание ветвей. 11

Обзор исполнительного ядра. 13

Задержка инструкций и производительность. 13

Исполнительные блоки и выводные порты.. 13

Кэши. 15

Предвыборка данных. 16

Плюсы и минусы программной и аппаратной предвыборки. 16

Загрузка и хранение. 18

Управление хранением.. 18

Технология Hyper-Threading. 19

Ресурсы процессора и технология Hyper-Threading. 20

Реплицированные ресурсы.. 20

Разделенные ресурсы.. 20

Разделяемые ресурсы.. 20

Микроархитектура конвейера и технология НТ. 21

Блок начальной загрузки конвейера. 21

Исполнительное ядро. 21

Извлечение. 21

Список использованной литературы.. 22


Введение

В этой работе проводиться обзор основных моментов необходимых для оптимизации программного обеспечения для текущего поколения процессоров основанных на технологии IA-32, таких как Intel Pentium 4, Intel Xeon и Intel Pentium M. Работа дает базу для понимания правильного подхода к кодированию для технологии IA-32.

Ключевые моменты, повышающие производительность процессоров текущего поколения на базе IA-32:

·     Расширение инструкций SIMD поддерживающих технологию MMX, потоковые расширения инструкций SIMD (SSE), потоковые расширения инструкций SIMD второй редакции (SSE2) и потоковые расширения инструкций SIMD третьей редакции (SSE3)

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

·     Поддержка технологии Hyper Threading

Процессоры Intel Pentium 4 и Intel Xeon построены на микроархитектуре NetBurst. Микроархитектура процессора Intel Pentium M основывается на балансе производительности и низкого энергопотребления.


Технология SIMD

Один из путей к увеличению производительности процессора – это использование технологии вычислений основанной на том, что одна команда оперирует многими данными (single-instruction, multiple data (SIMD)).

Вычисления с помощью SIMD (рисунок 1) представлены в архитектуре IA-32 технологией MMX.Технология MMX позволяет вычислениям SIMD производиться над упакованными целыми числами в виде байтов, слов и двойных слов. Эти целые содержаться в наборе из восьми 64-битных регистрах называемых MMX регистрами (рисунок 2).

В процессоре Intel Pentium III технология SIMD была расширена с помощью потоковых расширений SIMD (SSE). SSE позволяет производить вычисления SIMD над операндами, содержащими четыре упакованных элемента с плавающей точкой одинарной точности. Эти операнды могут храниться как в памяти, так и в одном из 128-битных регистров называемых XMM регистрами (рисунок 2). SSE также расширяет вычислительные способности SIMD, путем добавления дополнительных 64-битных MMX команд.

Рисунок 1 показывает типичную схему вычислений SIMD. Два блока по четыре упакованных элемента данных (X1, X2, X3, X4 и Y1, Y2, Y3,Y4), обрабатываемых параллельно с помощью одной операцией над каждой парой элементов данных (X1 и Y1, X2 и Y2, X3 и Y3 и X4 и Y4). Результаты четырех параллельных вычислений сортируются в набор из четырех элементов данных.

Рисунок 1. Схема вычислений SIMD

В процессорах Pentium 4 и Intel Xeon модель вычислений SIMD была далее расширена с помощью SSE2 и SSE3.

SSE2 работает с операндами, хранящимися в памяти или в XMM регистрах. Технология SSE2 расширяет вычисления SIMD для работы с упакованными элементами данных с плавающей точкой двойной точности и 128-битными упакованными целыми числами. В SSE2 введены 144 дополнительные команды для работы с двумя элементами данных с плавающей точкой двойной точности или над упакованными целыми числами в виде шестнадцати байтов, восьми слов, четырех двойных слов и двух четверных слов.

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

Полный набор технологий SIMD (MMX, SSE, SSE2, SSE3) в технологии IA-32 дает возможность программисту разрабатывать алгоритмы, совмещающие операции над упакованными 64-битными и 128-битными целыми, и операндами с плавающей точкой одинарной и двойной точности.

Рисунок 2. Регистры SIMD

SIMD улучшает выполнение 3D графики, распознавание речи, обработки изображений, научных приложений и приложений удовлетворяющих следующим характеристикам:

·     Внутренняя параллельность

·     Рекурсивный доступ к областям памяти

·     Локальные рекурсивные операции над данными

·     Контроль над потоком независимых данных

Инструкции SIMD для работы с числами с плавающей точкой полностью поддерживают стандарт IEEE 754 «для бинарной арифметики чисел с плавающей точкой». Они доступны во всех режимах работы процессора.

Технологии SSE, SSE2 и MMX – это архитектурные дополнения архитектуры IA-32. SSE и SSE2 также включают инструкции кэширования и организации памяти, которые могут улучшить использование КЭШа и производительность приложений.

Краткое обозрение технологий SIMD Технология MMX

Технология MMX основывается на:

·     64-битных MMX-регистрах

·     поддержке операций SIMD над упакованными целыми в виде байтов, слов и двойных слов

Инструкции MMX полезны в мультимедийных и коммуникационных приложениях

SSE

SSE основывается на:

·     128-битных XMM-регистрах

·     128-битных типах данных, содержащих четыре упакованных операнда с плавающей точкой одинарной точности

·     инструкциях предвыборки данных

·     инструкциях хранения в течение неопределенного срока и других инструкций кэширования и упорядочивания памяти

·     дополнительной поддержке 64-битных целых SIMD

Инструкции SSE полезны при обработке трехмерной геометрии, 3D-рендеринга, распознавания речи, а также для кодирования и декодирования видео.

SSE2

SSE2 добавляют следующее:

·     128-битный тип данных с двумя упакованными операндами с плавающей точкой двойной точности

·     128-битные типы данных для целочисленных операций SIMD над целыми в виде шестнадцати байт, восьми слов, четырех двойных слов или двух четверных слов.

·     Поддержку арифметики SIMD над 64-битными целочисленными операндами

·     Инструкции для конвертирования между новыми и существующими типами данных

·     Дополнительная поддержка перемешивания данных

·     Дополнительная поддержка операций кэширования и упорядочивания памяти

Инструкции SSE2 полезны для обработки 3D графики, кодирования и декодирования видео и шифрования.

SSE3

SSE3 добавляет следующее:

·     SIMD операции с плавающей точкой для ассиметричных и горизонтальных вычислений

·     Специальную 128-битную загрузочную инструкцию для избежания разделения нити КЭШа

·     x87 FPU – инструкцию для конвертирования в целое независимо от FCW (floating-point control word)

·     инструкции для поддержки синхронизации потоков

Инструкции SSE3 могут применяться в научных, видео и многопоточных приложениях.


Микроархитектура Intel NetBurst

В этом разделе описываются основные моменты микроархитектуры Intel NetBurst. Он дает техническую базу необходимую для понимания оптимизационных рекомендаций и правил кодирования процессоров Intel Pentium 4 и Intel Xeon.

Микроархитектура Intel NetBurst она спроектирована для достижения высокой производительности при целочисленных вычислениях и вычислениях операндов с плавающей точкой на высоких частотах. Она основывается на следующих моментах:

·     гиперковейерная технология позволяющая работать на высоких частотах (до 10 ГГц)

·     высокопроизводительный, четырехкратный шинный интерфейс для системной шины микроархитектуры Intel NetBurst

·     скоростной движок для снижения задержек исполнения целочисленных инструкций

·     спекулятивное разупорядоченное исполнение для поддержки параллелизма

·     суперскалярная выдача для поддержки параллелизма

·     поддержка аппаратного переименования регистров для исключения ограничений пространства имен

·     64-байтные нити КЭШа

·     аппаратная предвыборка

Цели, для которых была разработана Микроархитектура Intel NetBurst

Цели, для которых была разработана Микроархитектура Intel NetBurst:

·     для обеспечения наследственности приложений IA-32 и приложений основанных на SIMD на высокопроизводительных системах

·     для оперирования на высоких тактовых частотах и для масштабирования высокой производительности и высоких тактовых частот в будущем

Преимущества микроархитектуры Intel NetBurst:

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

·     конвейер, оптимизированный для обработки часто исполняемых инструкций (часто исполняемые инструкции при обычных условиях эффективно декодируются и исполняются с меньшими задержками)

·     внедрение специальных техник для исправления зависания конвейера. Среди них: параллельное выполнение, буферизация и спекуляция. Микроархитектура выполняет инструкции динамически и беспорядочно, так что время, которое необходимое для выполнения каждой отдельной инструкции не всегда может быть определено.

Обзор конвейера микроархитектуры Intel NetBurst

Конвейер микроархитектуры Intel NetBurst состоит из:

·     блока начальной загрузки упорядоченных команд

·     беспорядочного суперскалярного исполнительного ядра

·     блок изъятия упорядоченных команд

Блок начальной загрузки поставляет инструкцию в программном порядке в беспорядочное ядро. Оно выбирает и декодирует инструкции IA-32. Декодированные инструкции переводятся в микрокоманды. Основная задача блока начальной загрузки состоит в доставлении непрекращающегося потока микрокоманд в исполнительное ядро в программном порядке.

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

Секция изъятия убеждается, что результаты обработки произвелись в правильном порядке и что правильные архитектурные режимы обновлены.

Рисунок 3 отображает схему основных функциональных блоков конвейера микроархитектуры Intel NetBurst. Ниже перечисленные разделы проводят обзор каждого из блоков.

Рисунок 3. Микроархитектура Intel NetBurst

Блок начальной загрузки

Блок начальной загрузки микроархитектуры Intel NetBurst состоит из двух частей:

·     Блок выборки/декодирования

·     Исполнительный кэш трасс

Он выполняет следующие функции:

·     Предвыборка инструкций IA-32 предпочтительных для исполнения

·     Выборка требуемых инструкций, которые не были предвыбраны

·     Декодировка инструкций в микрокоманды

·     Генерация кода сложных инструкций и кода специального назначения

·     Доставка декодированных инструкций из исполнительного КЭШа трасс

·     Предсказание ветвлений на основе улучшенного алгоритма

Блок начальной загрузки разработан для избежания двух проблем являющихся источниками задержек:

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

·     Уменьшения бесполезного кода связанного с ветвлениями или точками ветвления внутри нити КЭШа

Инструкции декодируются и выбираются «переводящим» движком. «Переводящий» движок затем преобразует декодированные инструкции в последовательности микрокоманд называемые трассами. Далее трассы помещаются в исполнительный кэш трасс.

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

Кэш трасс может доставлять до трех микрокоманд к ядру за такт. Исполнительных кэш трасс и «переводящий» движок имеют кооперированный механизм предсказания ветвей. Точки ветвлений предсказываются на основе их линейного адреса (используя логику предсказания ветвлений и выборок) так скоро, как это возможно. Точки ветвлений берутся из исполнительного КЭШа трасс, если они были кэшированы, или из иерархии памяти. Информация «переводящего» движка о ветвлении используется при формировании трасс по наилучшим маршрутам.

Беспорядочное ядро

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

Ядро спроектировано так, чтобы организовать параллельное выполнение. Оно может отправлять до шести микрокоманд в порты вывода за цикл (рисунок 4). Заметим, что шесть микрокоманд превосходят мощность КЭШа трасс и блока изъятия. Большая мощность ядра сделана, чтобы не обращать внимание на нагрузки более трех микрокоманд и для достижения большей производительности выдачи с помощью гибкости при выдаче микрокоманд в различные исполнительные порты.

Большинство исполнительных блоков ядра могут начинать выполнение новой микрокоманды каждый цикл, так что несколько инструкций могут быть выполнены одновременно в каждом блоке конвейера. Некоторые из инструкций арифметико-логического устройства (ALU) могут выполняться дважды за цикл, множество из инструкций обработки данных с плавающей точкой обрабатываются за два цикла. Наконец, микрокоманды могут быть начаты выполняться вне программного порядка, как только их входные данные готовы и ресурсы доступны.

Секция изъятий

Секция изъятий получает результаты выполненных микрокоманд из исполнительного ядра и выстраивает их в соответствии с оригинальным порядком в программе. Для семантически правильного исполнения, результаты инструкций IA-32 должны быть восстановлены в оригинальном порядке перед их извлечением.

Когда микрокоманда завершена и ее результаты записаны по назначению, она извлекается. За цикл могут быть извлечены три микрокоманды. Переупорядочивающий буфер (ROB) – это блок в процессоре который буферизирует завершенные микрокоманды, обновляет их архитектурный вид и производит упорядочивание в исключительных ситуациях.

Секция изъятия так же наблюдает за ветвлениями и отсылает обновленную информацию о точках ветвления в буфер точек ветвлений (BTB). Это позволяет обновлять историю ветвлений. Рисунок 3 отображает пути часто го исполнения внутри микроархитектуры Intel NetBurst, такие как исполнительные циклы, взаимодействующие с иерархией уровней КЭШа и системной шиной.

Следующие разделы дают более детальное описание операций блока начальной загрузки и исполнительного ядра.


Обзор блока начальной загрузки конвейера

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

Предвыборка

Микроархитектура Intel NetBurst использует следующие механизмы предвыборки:

·     Аппаратный выборщик инструкций, автоматически предвыбирающий инструкции

·     Аппаратный механизм, который автоматически выбирает данные и инструкции и помещает их в унифицированный кэш второго уровня

·     Механизм выборки только данных состоящий из двух частей:

1.    аппаратный механизм для выборки смежных нитей КЭШа в 128-байтном секторе, содержащем данные необходимые в случае сбоя нити, или необходимы для предвыборки нитей КЭШа

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

Аппаратный выборщик инструкций читает инструкции по пути, предсказанному в буфере точек ветвления (BTB), в потоковые буферы инструкций. Данные считываются в 32-байтные блоки, начиная с адреса точки. Второй и третий механизм будут рассмотрены позднее.

Декодер

Блок начальной загрузки микроархитектуры Intel NetBurst имеет один декодер, который декодирует инструкции с максимальной частотой в одну инструкцию за такт. Некоторые сложные инструкции должны поддерживаться с помощью ROM-микрокода. Операции декодера связанны с КЭШем трасс.

Исполнительный кэш трасс

Исполнительный кэш трасс (TC) – это основной кэш инструкций в микроархитектуре Intel NetBurst. Кэш трасс хранит декодированные инструкции (микрокоманды) IA-32.

В реализации процессоров Intel Pentium 4 и Intel Xeon, кэш трасс может хранить до 12 тысяч микрокоманд и выдавать до трех микрокоманд за цикл. Кэш трасс не хранит все микрокоманды необходимые для обработки в исполнительном ядре. В некоторых ситуациях, исполнительному ядру необходимо выполнить поток микрокода, вместо трасс микрокоманд, хранящихся в КЭШе трасс.

Процессоры Intel Pentium 4 и Intel Xeon оптимизированы для выполнения часто-используемых IA-32 инструкций, в то время как только некоторые инструкции вовлекают в процесс декодирования ROM-микрокода.

Предсказание ветвей

Предсказание ветвей очень важно для производительности процессоров с большим конвейером. Это позволяет процессору начать работу задолго до того как будет дотошно известен результат ветвления. Задержка при ветвлении – это расплата за неправильное предсказание ветвление. Для процессоров Intel Pentium 4 и Intel Xeon задержка при правильном предсказании может быть нулевой. Задержка же при неправильном предсказании может быть множество циклов, обычно она равна глубине конвейера.

Предсказание ветвей в микроархитектуре Intel NetBurst затрагивает все ближние ветвления (условные вызовы, безусловные вызовы, возвраты и тупиковые ветви). Но не затрагивает дальние переходы (дальние вызовы, неопределенные возвраты, программные прерывания).

Механизмы внедренные для более точного предсказания ветвей и затрат на их обработку:

·     Возможность динамически предсказывать направление и точку ветвления, основанная на линейном адресе инструкции, используя буфер точек ветвления (BTB)

·     Если нет возможности динамического предсказания или оно не правильное, то существует возможность статического предсказания результата основанного на замене цели: задняя ветвь берется за основную, а основная не берется.

·     Возможность предсказания адресов возвратов, с помощью 16-разрядного стека адресов возвратов

·     Возможность строить трассы инструкций по всей взятой ветви для избежания расплаты за неправильно предсказание

Статический предсказатель. Как только инструкция ветвления декодирована, направление ветви (вперед или назад) становиться известным. Если BTB нет упоминаний об этом ветвлении, статический предсказатель делает предсказание, основываясь на направлении ветви. Механизм статических предсказаний предсказывает задние условные цели (например, с отрицательным перемещением, такие как ветви оканчивающиеся циклом) как основные. Вперед направленные ветви предсказываются как не основные.

Для использования преимуществ передних-не-основных и задних-основных статических предсказаний, код должен быть упорядочен так, чтобы нежелательные цели находились в передних ветвях.

Буфер точек ветвлений. Если доступна история ветвлений, процессор может предсказать итог ветвления даже раньше, чем инструкция ветвления будет декодирована. Процессор использует таблицу историй ветвлений и BTB для предсказания направления ветвлений, основываясь на линейном адресе инструкции. Как только ветвь изъята, BTB обновляет адреса точек.

Стек возврата. Возвраты происходят всегда. Но с тех пор как процедура может быть вызвана из нескольких мест, технология предсказания одной точки не удовлетворяет потребностям. Процессоры Intel Pentium 4 и Intel Xeon стек возвратов, который может предсказывать адрес возврата, для нескольких мест вызова процедуры. Это увеличивает выгоду от использования развернутых циклов содержащих вызовы функции. Это так же ослабляет необходимость использования ближних процедур, так как уменьшена расплата за возврат из дальних процедур.

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


Обзор исполнительного ядра

Исполнительное ядро разработано для оптимизации общей производительности путем более эффективного управления исполнением простых ситуаций. Аппаратное обеспечение спроектировано для выполнения частых операций в простых случаях как можно быстрее, за счет нечасто исполняемых операций. Некоторые части ядра могут предполагать, что текущее состояние сохраняется для возможности быстрого исполнения похожих операций. Если бы этого не было, машина бы стопорилась. Примером такой конструкции может служить управление хранением-для-загрузки (store-to-load). Если загрузка предсказана зависимой от хранения, она получает данные из этого хранилища и предварительно выполняется. Если же загрузка не зависит от хранения, загрузка задерживается до получения реальных данных из памяти, затем она выполняется.

Задержка инструкций и производительность

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

·     Выбор IA-32 инструкций так, чтобы они были декодированы меньше чем в четыре микрокоманды и/или имели меньшие задержки

·     Упорядочивание IA-32 инструкций для сохранения доступного параллелизма с помощью минимизирования цепочек длинной зависимости и перекрытия задержек длинных инструкций

·     Упорядочивание инструкций так, чтобы их операнды были готовы и их исполнительные блоки и выводные порты были свободны к моменту достижения ими диспетчера

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

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

Исполнительные блоки и выводные порты

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


Информация о работе «Архитектура IA-32»
Раздел: Информатика, программирование
Количество знаков с пробелами: 41671
Количество таблиц: 0
Количество изображений: 6

Похожие работы

Скачать
89841
0
6

... информационной причинности взаимодействий (нейтрализация энтропии), связанной с процессами отражения степеней упорядоченности (возбуждений), обладание универсальной системой пространственно-временных отношений, выделяют “абсолютный квант” в феноменальное явление физической природы. Он может быть неожиданным материальным воплощением той начальной активной субстанции, которую объективный идеализм, ...

Скачать
127005
0
0

... объемов продаж рабочих станций и серверов на архитектуре MIPS в конце 1990-х гг. Silicon Graphics пришлось обратить внимание на более производительные и перспективные архитектуры. Silicon Graphics предлагает спектр серверных решений на основе архитектуры Itanium (модельный ряд Altix), а выпуск продукции архитектуры MIPS постепенно сворачивается. В 1998-2000 гг. MIPS Technologies получила свободу ...

Скачать
60880
0
0

... и форма арочных пролетов придавали средневековым местам своеобразный живописный характер. Декоративная отделка на таких мостах отсутствовала либо была крайне сдержанна. Готика как стиль проявлялась в архитектуре мостов лишь в период позднего средневековья - конец XIY начало ХУ в в., при этом украшались, как правило, расположенные на мостах башни часовни и другие постройки. Например, на мосту ...

Скачать
93863
0
3

... , но, несомненно, оказали неоценимую помощь в принятии окончательных проектно-технических решений. 21 марта 1933 года Постановлением Совнаркома СССР была утверждена схема линий московского метрополитена протяженностью 80,3 км, насчитывающая 10 радиусов. Еще за год до этого начали закладываться первые шахты Кировско-Фрунзенского диаметра, пролегающего от Сокольников до Крымской площади через ...

0 комментариев


Наверх