(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Ускоряем OpenMP в Visual C++ 2010

Источник: habrahabr

Одним из популярных и дешёвых средств реализации многопоточных вычислений на языке C++ является OpenMP.

 Достоинства технологии очевидны: простота; малые, и легко отключаемые изменения в коде; поддержка от авторов самых популярных компиляторов:

Visual C++
GCC 4.2
Intel C++ Compiler

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

 Проходит пара лет, вы успешно мигрируете на Visual Studio 2010,… и обнаруживаете себя сидящим в луже. Если вчера обработка большого массива данных на машинах с многоядерными процессорами проходила за считанные секунды, то сегодня наличие любого фонового приложения, занимающего собственными вычислениями одно или несколько ядер, практически вешает приложение.

 Почему так происходит, и как с этим бороться?

 В новой реализации OpenMP перед тем, как выйти из активной области в состояние Idle, ваша программа будет ждать завершения операций ввода/вывода, причём ждать с помощью активного SpinWait.

 Т.е. если мы с помощью OMP создали N потоков (по 1 на ядро), и неожиданно выяснили, что одно из ядер занято другим приложением, то с большой вероятностью на одном ядре будут выполняться 2 и больше потоков, переключение между которыми будет перемежаться 200-миллисекундными паузами.

 Но в рассчётных программах мы не хотим никаких дополнительных синхронизаций!

 Разработчики Intel об этом знают, и предлагают пользователю самому заботиться о дополнительных ограничениях с помощью опции kmp_set_blocktime(). К сожалению, их коллеги из Microsoft решили не путать пользователей лишними настройками.

 Если переписывать программу на честный threading pool лень или не позволяет религия - предлагаю воспользоваться моим опытом… даунгрейда OpenMP на оригинальную версию из Microsoft Visual Studio 2005. Также инструкция подходит для Visual Studio 2008 с минимальными изменениями.

 Во-первых, скопируем в отдельную папку vcomp.lib, vcompd.lib из комплекта Visual C++ 2005 (можно ссылаться напрямую на установленный дистрибутив, но это не так удобно). Заходим в свойства использующих OpenMP проектов, и добавляем в "Additional Library Directories" нашу директорию. Вуаля - теперь проект линкуется с "правильной", быстро работающей версией OpenMP.

 Но это ещё не все. Заменим включение <omp.h> заголовочным файлом следующего содержания:

#pragma once

#include <omp.h>

#ifndef __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX
#define __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX "Microsoft.VC80"
#endif

#ifndef _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN
#define _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "1fc8b3b9a1e18e3b"
#endif

#ifndef __OMP_CRT_ASSEMBLY_VERSION
#define __OMP_CRT_ASSEMBLY_VERSION "8.0.50727.762"
#endif

#if defined(_DEBUG)

#if defined(_M_IX86)
#pragma comment(linker,"/manifestdependency:\"type='win32' "            \
  "name='" __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugOpenMP' "         \
  "version='" __OMP_CRT_ASSEMBLY_VERSION "' "                          \
  "processorArchitecture='x86' "                                  \
  "publicKeyToken='" _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#elif defined(_M_AMD64)
#pragma comment(linker,"/manifestdependency:\"type='win32' "            \
  "name='" __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugOpenMP' "         \
  "version='" __OMP_CRT_ASSEMBLY_VERSION "' "                          \
  "processorArchitecture='amd64' "                                  \
  "publicKeyToken='" _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#elif defined(_M_IA64)
#pragma comment(linker,"/manifestdependency:\"type='win32' "            \
  "name='" __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugOpenMP' "         \
  "version='" __OMP_CRT_ASSEMBLY_VERSION "' "                          \
  "processorArchitecture='ia64' "                                  \
  "publicKeyToken='" _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#endif

#else   // _DEBUG

#if defined(_M_IX86)
#pragma comment(linker,"/manifestdependency:\"type='win32' "            \
  "name='" __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX ".OpenMP' "              \
  "version='" __OMP_CRT_ASSEMBLY_VERSION "' "                          \
  "processorArchitecture='x86' "                                  \
  "publicKeyToken='" _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#elif defined(_M_AMD64)
#pragma comment(linker,"/manifestdependency:\"type='win32' "            \
  "name='" __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX ".OpenMP' "              \
  "version='" __OMP_CRT_ASSEMBLY_VERSION "' "                          \
  "processorArchitecture='amd64' "                                  \
  "publicKeyToken='" _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#elif defined(_M_IA64)
#pragma comment(linker,"/manifestdependency:\"type='win32' "            \
  "name='" __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX ".OpenMP' "              \
  "version='" __OMP_CRT_ASSEMBLY_VERSION "' "                          \
  "processorArchitecture='ia64' "                                  \
  "publicKeyToken='" _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")
#endif

#endif  // _DEBUG

 Это необходимо для корректной подгрузки манифеста в исполняемых и .dll-файлах. Не забудьте, что даже если OpenMP используется в подгружаемых .dll-файлах, манифест нужно прописать и для исполняемого файла!

 Значения __OMP_LIBRARIES_ASSEMBLY_NAME_PREFIX, _OMP_VC_ASSEMBLY_PUBLICKEYTOKEN и __OMP_CRT_ASSEMBLY_VERSION взяты из <crtassem.h>, входящего в поставку Visual C++ 2005. Если у вас стоит другая версия (например, не установлен SP1), то указанные числа нужно заменить на собственные значения

 Проект по-прежнему не собирается - сейчас студия возмущена до предела тем, что не определён символ __You_must_link_with_Microsoft_OpenMP_library.

 Да, это был очень тонкий намёк со стороны компилятора.

 Посмотрим на содержимое сгенерированного .obj-файла. На мой взгляд, лучше всего для этого подойдёт утилита objconv в режиме дизассемблера.

 Выясняем, что нам нужно определить переменную размера byte с указанным именем. К сожалению, в C и C++ мы не сможем с точностью воссоздать импортируемый символ, поэтому придётся воспользоваться MASM32.

 Добавляем бессмысленную переменную:

PUBLIC __You_must_link_with_Microsoft_OpenMP_library
    data segment
        __You_must_link_with_Microsoft_OpenMP_library db 1
    data ends
end

 компилируем:

ml /c antiomp.asm

 и полученный на выходе antiomp.obj добавляем в Additional Input проектов, использующих OpenMP.

 Всё - у нас должен был получиться рабочий код. Проверить версию OpenMP можно двумя способами:

запустить приложение, подцепиться отладчиком и найти в списке загруженных модулей (Debug/Windows/Modules) библиотеку OpenMP
попытаться найти в исполняемых файлах подстроку vcomp100. Если всё сделано по инструкции, то этой строчки быть не должно

 Приятного параллельного программирования!

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 18.01.2012 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft Office 365 Бизнес. Подписка на 1 рабочее место на 1 год
Microsoft Office 365 Профессиональный Плюс. Подписка на 1 рабочее место на 1 год
Microsoft Office 365 для Дома 32-bit/x64. 5 ПК/Mac + 5 Планшетов + 5 Телефонов. Подписка на 1 год.
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год.
Microsoft 365 Business Basic (corporate)
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
Новые программы для Windows
Проект mic-hard - все об XP - новости, статьи, советы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100