Совет разработчикам: Так как основная цель профилирования - перехват вызовов функций из кода пользователя, то реализация нижних уровней, позволяющая перехват и профилирование вызовов функций оставляется на усмотрение разработчика. Если реализация привязок С++ к MPI выполнена над привязками другого языка (такого как Си), или если привязки С++ находятся над интерфейсом профилирования другого языка, то дополнительный интерфейс не нужен, так как реализация MPI нижнего уровня уже соответствует требованиям интерфейса профилирования MPI.
Реализации MPI с чистым С++, которые не имеют доступа к другим интерфейсам профилирования, должны реализовать интерфейс, соответствующий требованиям, отмеченным в этой главе.
Высококачественные реализации могут реализовать интерфейс, описанный в этой главе с целью распространения переносимых библиотек профилирования С++. Разработчики могут пожелать предоставить выбор - встраивать интерфейс профилирования для С++ или нет; те реализации С++, которые уже находятся над привязками другого языка или другого интерфейса должны будут вставить третий уровень для реализации интерфейса профилирования С++.[]
Для соответствия рекомендациям для интерфейса профилирования С++ для MPI, реализация функций MPI должна:
Это необходимо, чтобы позволить отдельной библиотеке профилирования быть реализованной правильно, так как (по крайней мере, с семантикой компоновщика в UNIX) библиотека профилирования должна содержать эти надстройки для ожидаемой работы. Это требование позволяет автору библиотеки профилирования выделить эти функции из оригинальной библиотеки MPI и добавить их в библиотеку профилирования без добавления бесполезного кода.
``Настоящие'' точки входа для каждой процедуры могут быть предоставлены в поле имен PMPI (namespace PMPI). Обычная версия тогда может быть предоставлена в поле имен MPI.
Вложение экземпляров объектов PMPI в дескриптор MPI предоставляет отношение ``включает'', что необходимо для схемы профилирования .
Каждый экземпляр объекта MPI просто ``надстраивается'' над экземпляром объекта PMPI. Объекты MPI могут производить операции профилирования до вызова соответствующей функции их внутреннего объекта PMPI. Это справедливо как для базовых классов, так и для порожденных; иерархия PMPI прямо соответствует иерархии MPI.
Ключом к тому, чтобы заставить профилирование заработать при простой перекомпоновке программы, является заголовочный файл, который объявляет все функции MPI. Функции должны быть определены в другом месте и скомпилированы в библиотеку. Константы MPI должны быть объявлены как extern в поле имен MPI. Например, этот фрагмент из демонстрационного файла mpi.h:
Пример 8.6 Демонстрационный файл mpi.h.
namespace PMPI {
class Comm {
public:
int Get_size() const;
};
// и т.д.
};
namespace MPI {
public:
class Comm {
public:
int Get_size() const;
private:
PMPI::Comm pmpi_comm;
};
};
Заметьте - все конструкторы, оператор присваивания и деструктор в классе MPI должны будут инициализировать/уничтожить соответствующий внутренний объект
PMPI.
Объявления функций должны быть в отдельных объектных файлах; член-функции класса PMPI и версии член-функций класса MPI без профилирования могут быть скомпилированы в libmpi.a, когда версии с профилированием могут быть скомпилированы в libpmpi.a. Заметьте, что член-функции класса PMPI и константы MPI должны быть в отдельных от член-функций класса MPI без профилирования объектных файлах библиотеки libmpi.a, чтобы предотвратить многократное определение имен член-функций класса MPI при одновременной компоновке libmpi.a и libpmpi.a. Например:
Пример 8.7 pmpi.cc будет скомпилирован в libmpi.a.
int PMPI::Comm::Get_size() const
{
// Реализация MPI_COMM_SIZE
}
Пример 8.8 constants.cc, будет скомпилирован в libmpi.a.
const MPI::Intracomm MPI::COMM_WORLD;
Пример 8.9 mpi_no_profile.cc, будет скомпилирован в libmpi.a.
int MPI::Comm::Get_size() const
{
return pmpi_comm.Get_size();
}
Пример 8.10 mpi_profile.cc, будет скомпилирован в libpmpi.a.
int MPI::Comm::Get_size() const
{
// профилирование
int ret = pmpi_comm.Get_size();
// дальнейшее профилирование
return ret;
}