CUDA 2D Arrays - Учет высоты тона до распределения? - PullRequest
1 голос
/ 29 февраля 2012

У меня есть рабочий процесс, который работает следующим образом:

  1. Загрузка начальных значений
  2. Обработка значений до промежуточных результатов A
  3. Процесс A для получения промежуточных результатов B
  4. Процесс B с промежуточными результатами C
  5. Процесс C и B для промежуточных результатов D и E
  6. Сумма Частичная 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).

Ответы [ 2 ]

1 голос
/ 06 марта 2012

Шаг в байтах рассчитывается следующим образом:

pitch_size = DIV_UP(width_in_bytes, prop.textureAlignment);

Где DIV_UP округляет первый аргумент до следующего более высокого кратного второго аргумента.

Вы можете запросить prop.textureAlignment, позвонив cudaGetDeviceProperties().

0 голосов
/ 05 декабря 2013

Разве шаг в байтах не должен быть:

pitch_size = DIV_UP(width_in_bytes, prop.textureAlignment)*prop.textureAlignment;

вместо:

pitch_size = DIV_UP(width_in_bytes, prop.textureAlignment);
...