- •Содержание
- •Лекционный курс модуль Вводный
- •1. Цели и задачи курса
- •2. Микропроцессор и микропроцессорная система
- •3. Основные понятия и определения
- •4. Характеристики микропроцессоров
- •5. Классификация микропроцессоров
- •6. Эволюция микропроцессоров
- •Модуль I. Организация микропроцессорной системы
- •1. Основные типы архитектур микропроцессорных систем. Фон-неймановская (принстонская) и гарвардская архитектуры. Организация пространств памяти и ввода-вывода.
- •5. Прямой доступ к памяти. Организация прямого доступа к памяти. Контроллер пдп.
- •6. Память микропроцессорной системы. Функции памяти. Архитектура и иерархия памяти. Организация кэш-памяти. Виртуальная память.
- •Увеличение разрядности основной памяти
- •Память с расслоением
- •Использование специфических свойств динамических зупв
- •Страничная организация памяти
- •Сегментация памяти
- •Модуль II. Универсальные микропроцессоры
- •1. Определение понятия «архитектура». Архитектура системы команд. Классификация процессоров cisc и risc. Определение понятия "архитектура"
- •Архитектура системы команд. Классификация процессоров (cisc и risc)
- •2. Методы адресации и типы данных. Типы команд. Команды управления потоком команд. Методы адресации
- •Типы команд
- •Команды управления потоком команд
- •3. Конвейеризация и параллелизм. Конвейерная организация обработки данных. Простейшая организация конвейера и оценка его производительности.
- •Простейшая организация конвейера и оценка его производительности
- •Конфликты по данным, остановы конвейера и реализация механизма обходов
- •Классификация конфликтов по данным
- •Конфликты по данным, приводящие к приостановке конвейера
- •Методика планирования компилятора для устранения конфликтов по данным
- •Сокращение потерь на выполнение команд перехода и минимизация конфликтов по управлению
- •Снижение потерь на выполнение команд условного перехода
- •5. Проблемы реализации точного прерывания в конвейере. Обработка многотактных операций и механизмы обходов в длинных конвейерах Проблемы реализации точного прерывания в конвейере
- •Обработка многотактных операций и механизмы обходов в длинных конвейерах
- •Конфликты и ускоренные пересылки в длинных конвейерах
- •Поддержка точных прерываний в длинных конвейерах
- •Параллелизм уровня команд: зависимости и конфликты по данным
- •Параллелизм уровня цикла: концепции и методы
- •Основы планирования загрузки конвейера и разворачивание циклов
- •7. Зависимости. Классификация зависимостей и их применение. Устранение зависимостей по данным и механизмы динамического планирования. Зависимости. Их классификация и применение.
- •Устранение зависимостей по данным и механизмы динамического планирования Основная идея динамической оптимизации
- •Динамическая оптимизация с централизованной схемой обнаружения конфликтов
- •Другой подход к динамическому планированию - алгоритм Томасуло
- •Дальнейшее уменьшение приостановок по управлению: буфера целевых адресов переходов
- •9. Одновременная выдача нескольких команд для выполнения и динамическое планирование.
- •10. Архитектура машин с длинным командным словом (vliw). Средства поддержки большой степени распараллеливания.
- •Средства поддержки большой степени распараллеливания
- •Обнаружение и устранение зависимостей
- •Программная конвейеризация: символическое разворачивание циклов
- •Трассировочное планирование
- •Аппаратные средства поддержки большой степени распараллеливания
- •Условные команды
- •Выполнение по предположению (speculation)
- •11. Архитектура epic.
- •Модуль III. Микроконтроллеры и специализированные микропроцессоры
- •2. Специализированные микропроцессоры. Цифровые процессоры обработки сигналов.
- •Модуль Заключительный Перспективы развития микропроцессорной техники.
- •Лабораторный курс
- •7 Семестр. Лабораторная работа 1.
- •Лабораторная работа 2.
- •Лабораторная работа 3.
- •Лабораторная работа 4.
- •8 Семестр. Лабораторная работа 1.
- •1. Общие сведения
- •2. Настройка и запуск Code Composer Studio (simulation)
- •3. Особенности проектирования в иср Code Composer Studio
- •4. Реализация проекта в иср Code Composer Studio
- •5. Тестирование проекта в иср Code Composer Studio
- •6. Аппаратная реализация проекта в иср Code Composer Studio
- •Лабораторная работа 2.
- •1. Подключение файлов ввода/вывода с помощью точек зондирования
- •2. Работа с файлами по средствам функций языка с
- •3. Работа с dsp/bios для генерации звукового сигнала платой dsk5510
- •Лабораторная работа 3.
- •1 Цифровая фильтрация
- •2. Реализация ких фильтра на симуляторе dsk5510
- •3. Реализация ких фильтра на dsk5510 для фильтрации звукового сигнала в реальном времени.
- •Лабораторная работа 4.
- •1. Фильтры с бесконечной импульсной характеристикой – бих
- •2. Реализация бих фильтра на симуляторе dsk5510
- •Фильтр низкой частоты с нормальной частотой среза 0.1
- •Фильтр низкой частоты с нормальной частотой среза 0.2
- •Полосовой фильтр с нормальной частотой среза 0.165 – 0.33
- •3. Реализация бих фильтра на dsk5510 для фильтрации звукового сигнала в реальном времени.
- •Фильтр низкой частоты с нормальной частотой среза 0.1
- •Фильтр низкой частоты с нормальной частотой среза 0.2
- •Полосовой фильтр с нормальной частотой среза 0.165 – 0.33
- •Оценка работы студентов. Рейтинговая система.
- •1. Общие положения
- •2. Организация рейтингового контроля успеваемости студентов дневной формы обучения
- •3. Выставление оценок по рейтинговой системе
- •4. Организация рейтингового контроля успеваемости студентов заочной формы обучения
- •Учебно-методические материалы Основная литература
- •Дополнительная литература
Лабораторный курс
7 Семестр. Лабораторная работа 1.
СУПЕРСКАЛЯРНЫЕ ВЫЧИСЛЕНИЯ. Параллельное выполнение вычислений.
Цель работы: Реализовать программу, демонстрирующую преимущества суперскалярной архитектуры.
Краткие теоретические сведения
Для роста производительности вычислительных машин необходима параллельная выдача нескольких команд в каждом такте. Этот принцип реализуют суперскалярные машины. Суперскалярные машины могут выдавать на выполнение в каждом такте переменное число команд, и работа их конвейеров может планироваться как статически с помощью компилятора, так и с помощью аппаратных средств динамической оптимизации. Суперскалярные машины используют параллелизм на уровне команд путем посылки нескольких команд из обычного потока команд в несколько функциональных устройств. Таким образом, основная идея суперскалярной архитектуры заключается в параллельном выполнении вычислений. В данной лабораторной работе необходимо оценить время последовательного выполнения большого объема вычислений и сравнить это время со временем выполнения этих же вычислений, но уже параллельно. Для реализации параллельных вычислений создадим два потока, каждый из которых будет выполнять половину вычислений. В качестве времени окончания работы параллельных вычислений необходимо выбрать из двух времен максимальное время. Замерять время выполнения операций можно с помощью функции ftime(). Выглядит это следующим образом. С помощью функции ftime() получаем некоторое начальное время выполнения. Затем в цикле выполняем необходимое количество операций и снова получаем значение времени. Далее находим разницу времен после и до цикла. Полученное значение времени и есть время, затраченное процессором на выполнение цикла операций. Оценивать время выполнения цикла операций необходимо в миллисекундах. Вместо функции ftime() можно использовать функцию GetTickCount().
С запуском нового потока в существующем процессе (а первый поток запускается системой при создании процесса) уже связана одна тонкость. В Platform SDK, в разделе, посвященном процессам и потокам, говорится, что для запуска нового потока предназначена API-функция CreateThread. Этой функции надо передать адрес, с которого начнется исполнение потока, иначе говоря, указатель на функцию потока и кучу дополнительных параметров. Можно также использовать функцию стандартной библиотеки _beginthreadex. Ее параметры и возвращаемое значение практически полностью соответствуют CreateThread, хотя есть и небольшие различия. В случае неудачи одна из них возвращает NULL, а другая -1. Хэндл потока у API функции описан как HANDLE, а у С-функции, как unsigned long, хотя на самом деле это одна и та же величина. Существует еще функция _beginthread (без «ex»). В однопоточной версии стандартной библиотеки функции _beginthread и _beginthreadex вообще отсутствуют. Итак, чтобы стандартная библиотека С могла правильно работать, для запуска нового потока следует использовать _beginthreadex.
Теперь перейдем к вопросу о том, как поток правильно завершить. Прежде всего, хочу обратить особое внимание на то, что для этого никогда нельзя использовать функцию TerminateThread!
Почему же в обычном приложении нельзя использовать TerminateThread, и для чего же эта функция все-таки существует? Все дело в том, что TerminateThread предназначена не для завершения, а для аварийной остановки потока. Она существует лишь на «пожарный случай», когда завершить поток корректно нет возможности, например, если он банально зациклился. Поэтому место этой функции (вместе с TerminateProcess) – лишь в специальных системных приложениях вроде менеджера задач (Task Manager) или отладчика. И даже в таких приложениях к этим функциям стоит прибегать лишь в крайнем случае. Таким образом, если вы используете TerminateThread для уничтожения собственных потоков, это автоматически означает, что ваше приложение работает в аварийном режиме! Соответственно ожидать стабильной и надежной работы от него не приходится.
Чем же грозит насильственное «убийство» потоков? В первую очередь утечкой ресурсов. Почти в каждой программе нам приходится получать от системы различные ресурсы, которые по окончании работы необходимо освободить: память, файлы, объекты графического интерфейса, COM-интерфейсы и т.п. Поэтому если поток прекратил работу раньше времени, то функции, освобождающие эти объекты, не будут вызваны, и ресурсы будут висеть мертвым грузом до самого окончания работы, причем в лучшем случае заказавшего их процесса, а в худшем случае всей операционной системы. Еще больше неприятностей могут доставить эксклюзивно используемые ресурсы, работать с которыми одновременно может только один процесс или поток. Если такой ресурс вовремя не освободить, им не сможет пользоваться вообще никто!
Следует еще раз обратить внимание на стандартную библиотеку C. Она не только сама заказывает некоторые ресурсы при запуске потока/процесса, но еще и устроена так, что должна отслеживать запуск/завершение каждого потока в процессе. Поэтому поток должен завершаться так, чтобы стандартная библиотека правильно отработала это событие.
Наконец, вряд ли кто сможет предсказать, какие возникнут побочные эффекты, если поток будет уничтожен во время вызова API-функции. Впрочем даже если ваш рабочий поток не обращается к системе, добиться, чтобы его аварийная остановка не вызывала побочных эффектов обойдется вам значительно дороже, чем просто использовать штатный механизм завершения потока.
Как же все-таки правильно завершить поток? В Platform SDK сказано, что для этого он сам должен вызвать API-функцию ExitThread. Правда здесь, как и в случае с CreateThread, оказывается, что на самом деле вместо нее следует использовать ее эквивалент из стандартной библиотеки _endthreadex (которая внутри себя вызовет ExitThread). Но, пожалуй, все-таки самый надежный способ завершить поток – это просто дать функции потока завершиться и вернуть управление системе. Исполнение потока начинается с некоего системного кода, которой уже в свою очередь вызывает функцию, указатель на которую вы передали _beginthreadex (или непосредственно CreateThread, если вы не пользуетесь стандартной библиотекой). Как только ваша функция завершит работу, системный код вызовет _endthreadex (или соответственно сразу ExitThread) автоматически. Почему же не советуют явно вызывать _endthreadex? Не забывайте, что перед завершением поток должен освободить все занятые ресурсы. Что касается ресурсов, используемых стандартной библиотекой, их освободит _endthreadex. Но практически любая программа сама использует ресурсы, и за их освобождение ответственность несете вы сами. В большинстве случаев во избежание путаницы освобождать ресурсы удобно в той же самой функции, в которой они были выделены. Поэтому если _endthreadex будет вызвана в одной из вложенных функций, то ресурсы, выделенные в вызывающих функциях, останутся не освобожденными. При программировании на C++ освобождение ресурсов и прочая «чистка» чаще всего происходит в деструкторах. Это удобно, поскольку деструкторы локальных переменных вызываются автоматически при выходе из процедуры, в которой они были созданы. Но если будет вызвана _endthreadex, этого не произойдет! Поэтому с этой функцией стоит быть аккуратным даже в процедуре самого верхнего уровня.
В заключение следует упомянуть функцию CloseHandle. Иногда начинающие ошибочно полагают, что эта функция может остановить поток или процесс. Нет, эта функция предназначена всего лишь для того, чтобы закрывать описатели или «хэндлы», возвращаемые функциями CreateThread, CreateProcess и некоторыми другими. Хэндлы как потока, так и процесса, остаются в силе даже посте того, как поток или процесс был завершен. Как мы видим, это дает возможность легко проверить из другого потока, работает ли еще поток или уже завершился, и даже точно отследить момент его завершения. Поэтому для того, чтобы освободить системные ресурсы, хэндл потока должен быть закрыт явным образом. Для этого и нужна функция CloseHandle. Впрочем, если вы вызовете ее еще до завершения потока, вы всего лишь лишитесь описателя, но никак не повлияете на сам поток.
Задание
Написать программу на языке программирования С/С++, выполняющую следующие действия:
Произвести в цикле порядка одного миллиона операций сложения и замерить время выполнения всего цикла;
Разделить все вычисления на две равные части, и запустить их на выполнение параллельно, для чего создать два потока и замерить время работы каждого из них;
Выбрать максимальное время из двух поточных времен и сравнить его со временем последовательного выполнения вычислений, сделать выводы о преимуществе использования параллельных вычислений.
Допустимая среда разработки – Borland C++ Builder5.0, Borland C++ Builder6.0, Microsoft Visual C++6.0, Microsoft Visual C++7.0 и т.д.
Порядок выполнения работы
Написать программу, реализующую поставленную задачу.
Откомпилировать программу.
Запустить программу. Убедиться в ее корректной работе.
Уметь объяснить работу программы.
Оформить отчет.
Содержание отчета
Ф.И.О., группа, номер, название лабораторной работы и название дисциплины.
Цель работы.
Краткое описание алгоритма работы программы.
Результат работы программы.
Листинг программы.
Выводы.
Рекомендуемая литература
Дж. Рихтер “Windows для профессионалов”;
MSDN.