У меня есть рабочий процесс, который работает следующим образом:
- Загрузка начальных значений
- Обработка значений до промежуточных результатов A
- Процесс A для получения промежуточных результатов B
- Процесс B с промежуточными результатами C
- Процесс C и B для промежуточных результатов D и E
- Сумма Частичная D до конечного результата F
Естественной структурой для всех моих промежуточных результатов является структура двумерного массива, которую я размещаю с помощью cudaMallocPitch ().
К сожалению, мой алгоритм требует, чтобы я одновременно держал в памяти D, E, C и B, а D & E по отдельности в 4 раза больше памяти, чем B. Из-за другого ограничения в моей обработке (итерации по структура графа в памяти), размеры A или B ограничены максимальными размерами D и E, которые, в свою очередь, определяются использованием памяти начальных значений + потребление памяти B + потребление памяти C. Эта зависимость обусловлена тем, что я «делюсь» разделами промежуточных результатов в / из памяти устройства с хоста (для размещения очень больших наборов проблем), и я не могу начать шаг 4, пока шаги 1-3 не будут выполнены для всего проблема установлена.
Как только у меня будет B для всей поставленной задачи, я могу удалить A.
В настоящее время я определяю максимальный размер D + E с помощью следующей функции:
int gpuCalculateSimulPatterns(int lines, int patterns) {
// get free memory
size_t free_mem, total_mem;
int allowed_patterns;
cudaMemGetInfo(&free_mem, &total_mem);
allowed_patterns = (free_mem - (lines*sizeof(int))) / (lines*(sizeof(int)*2.5) + lines*sizeof(char)*1.5);
return min(patterns, allowed_patterns -(allowed_patterns % 32));
}
Это "работает", но только потому, что я переоцениваю размер D или E (их размеры и использование памяти идентичны) на 25% и удваиваю ожидаемый размер B. Даже тогда я все еще сталкиваюсь с крайними случаями где мое распределение памяти не удается, потому что он исчерпал память. Я хочу более эффективно использовать память на карте и , чтобы поддерживать выравнивание, поскольку мои ядра многократно читают и записывают из / в глобальную память.
Нет, использование общей памяти не вариант, так как я использую несколько ядер в нескольких блоках, а потоки внутри блока вообще не взаимодействуют.
Я обнаружил, что cudaMallocPitch () возвращает только используемый шаг для памяти, которая была успешно распределена. Есть ли способ передать водителю запрос на выделение памяти 2D и просто спросить, какой шаг он назначит?
Я бы запустил процедуру оптимизации проб / ошибок, но связанная зависимость размера между A, B, D и E (CI вычисляет априори, поскольку он не распределен по линейной высоте), делает это паршивым решением, и это необходимо пересчитать для каждой поставленной задачи.
У кого-нибудь есть лучший подход, который позволил бы мне определить подходящий размер моих промежуточных наборов данных, который поместится в произвольном объеме памяти устройства?
EDIT:
Память для промежуточного A используется повторно, мои ограничивающие вычисления предполагают, что C + D + E + B >> Initial + A + B (что верно в силу того факта, что A & B являются 1-байтовыми символы с одинаковыми размерами, в то время как C, D, E являются целыми числами), и мне нужно только обеспечить достаточно места для B + C + D + E.
Я использую только карты Compute Capability 2.x для тестирования (Quadro 2000, Tesla C2075, GTX460).