Практическое руководство. Использование функций Alloc и Free для повышения производительности операций с памятью
Мақала
В этом документе показано, как использовать параллелизм::Alloc и concurrency::Free для повышения производительности памяти. Он сравнивает время, необходимое для отмены элементов массива параллельно для трех различных типов, которые указывают newdelete и операторы.
Free Функции Alloc наиболее полезны при частом вызове нескольких потоков и Freeв Alloc обоих случаях. Среда выполнения содержит отдельный кэш памяти для каждого потока; Таким образом, среда выполнения управляет памятью без использования блокировок или барьеров памяти.
Пример. Типы, определяющие новые и удаленные операторы
В следующем примере показаны три типа, которые указывают new операторы и delete операторы. Класс new_delete использует глобальные new и delete операторы, malloc_free класс использует торговые и бесплатные функции среды выполнения C, а Alloc_Free класс использует среду выполнения Alloc параллелизма и Free функции.
C++
// A type that defines the new and delete operators. These operators // call the global new and delete operators, respectively.classnew_delete
{public:
staticvoid* operatornew(size_t size){
return ::operatornew(size);
}
staticvoidoperatordelete(void *p){
return ::operatordelete(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators // call the C Runtime malloc and free functions, respectively.classmalloc_free
{public:
staticvoid* operatornew(size_t size){
returnmalloc(size);
}
staticvoidoperatordelete(void *p){
returnfree(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators // call the Concurrency Runtime Alloc and Free functions, respectively.classAlloc_Free
{public:
staticvoid* operatornew(size_t size){
return Alloc(size);
}
staticvoidoperatordelete(void *p){
return Free(p);
}
int _data;
};
Пример: переключение и reverse_array функции
В следующем примере показаны функции swap и reverse_array. Функция swap обменивается содержимым массива по указанным индексам. Он выделяет память из кучи для временной переменной. Функция reverse_array создает большой массив и вычисляет время, необходимое для обратного обратного массива несколько раз параллельно.
C++
// Exchanges the contents of a[index1] with a[index2].template<classT>
voidswap(T* a, intindex1, intindex2)
{// For illustration, allocate memory from the heap.// This is useful when sizeof(T) is large.
T* temp = new T;
*temp = a[index1];
a[index1] = a[index2];
a[index2] = *temp;
delete temp;
}
// Computes the time that it takes to reverse the elements of a // large array of the specified type.template <typename T>
__int64 reverse_array(){
constint size = 5000000;
T* a = new T[size];
__int64 time = 0;
constint repeat = 11;
// Repeat the operation several times to amplify the time difference.for (int i = 0; i < repeat; ++i)
{
time += time_call([&] {
parallel_for(0, size/2, [&](int index)
{
swap(a, index, size-index-1);
});
});
}
delete[] a;
return time;
}
Пример: функция wmain
В следующем примере показана wmain функция, которая вычисляет время, необходимое для reverse_array действия функции и new_deletemalloc_freeAlloc_Free типов, каждый из которых использует другую схему выделения памяти.
C++
intwmain(){
// Compute the time that it takes to reverse large arrays of // different types.// new_delete
wcout << L"Took " << reverse_array<new_delete>()
<< " ms with new/delete." << endl;
// malloc_free
wcout << L"Took " << reverse_array<malloc_free>()
<< " ms with malloc/free." << endl;
// Alloc_Free
wcout << L"Took " << reverse_array<Alloc_Free>()
<< " ms with Alloc/Free." << endl;
}
Полный пример кода
Ниже приведен полный пример.
C++
// allocators.cpp// compile with: /EHsc #include<windows.h>#include<ppl.h>#include<iostream>usingnamespace concurrency;
usingnamespacestd;
// Calls the provided work function and returns the number of milliseconds // that it takes to call that function.template <classFunction>
__int64time_call(Function&& f)
{
__int64 begin = GetTickCount();
f();
return GetTickCount() - begin;
}
// A type that defines the new and delete operators. These operators // call the global new and delete operators, respectively.classnew_delete
{public:
staticvoid* operatornew(size_t size){
return ::operatornew(size);
}
staticvoidoperatordelete(void *p){
return ::operatordelete(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators // call the C Runtime malloc and free functions, respectively.classmalloc_free
{public:
staticvoid* operatornew(size_t size){
returnmalloc(size);
}
staticvoidoperatordelete(void *p){
returnfree(p);
}
int _data;
};
// A type that defines the new and delete operators. These operators // call the Concurrency Runtime Alloc and Free functions, respectively.classAlloc_Free
{public:
staticvoid* operatornew(size_t size){
return Alloc(size);
}
staticvoidoperatordelete(void *p){
return Free(p);
}
int _data;
};
// Exchanges the contents of a[index1] with a[index2].template<classT>
voidswap(T* a, intindex1, intindex2)
{// For illustration, allocate memory from the heap.// This is useful when sizeof(T) is large.
T* temp = new T;
*temp = a[index1];
a[index1] = a[index2];
a[index2] = *temp;
delete temp;
}
// Computes the time that it takes to reverse the elements of a // large array of the specified type.template <typename T>
__int64 reverse_array(){
constint size = 5000000;
T* a = new T[size];
__int64 time = 0;
constint repeat = 11;
// Repeat the operation several times to amplify the time difference.for (int i = 0; i < repeat; ++i)
{
time += time_call([&] {
parallel_for(0, size/2, [&](int index)
{
swap(a, index, size-index-1);
});
});
}
delete[] a;
return time;
}
intwmain(){
// Compute the time that it takes to reverse large arrays of // different types.// new_delete
wcout << L"Took " << reverse_array<new_delete>()
<< " ms with new/delete." << endl;
// malloc_free
wcout << L"Took " << reverse_array<malloc_free>()
<< " ms with malloc/free." << endl;
// Alloc_Free
wcout << L"Took " << reverse_array<Alloc_Free>()
<< " ms with Alloc/Free." << endl;
}
В этом примере создается следующий пример выходных данных для компьютера с четырьмя процессорами.
Output
Took 2031 ms with new/delete.
Took 1672 ms with malloc/free.
Took 656 ms with Alloc/Free.
В этом примере тип, использующий Alloc и Free функции, обеспечивает лучшую производительность памяти, так как FreeAlloc функции оптимизированы для частого выделения и освобождения блоков памяти из нескольких потоков.
Компиляция кода
Скопируйте пример кода и вставьте его в проект Visual Studio или вставьте его в файл с именем allocators.cpp , а затем выполните следующую команду в окне командной строки Visual Studio.
Azure HPC — это специально разработанная облачная возможность для рабочей нагрузки HPC и ИИ, использующая современные отраслевые процессоры и обмен данными по сети InfiniBand для обеспечения максимальной производительности, масштабируемости и ценности приложений. Azure HPC позволяет реализовывать инновации, повышать продуктивность и развивать гибкость бизнеса за счет высокодоступного набора технологий HPC и ИИ с возможностью их динамического распределения в соответствии с изменением коммерческих и техническ