Каков наиболее эффективный (но достаточно гибкий) способ хранения многомерных данных переменной длины?

Я хотел бы знать, что лучше всего подходит для эффективного хранения (и последующего доступа) наборов многомерных массивов данных с переменной длиной. Основное внимание уделяется производительности, но мне также нужно иметь возможность обрабатывать изменение длины отдельного набора данных во время выполнения без особых накладных расходов.

Примечание. Я знаю, что это довольно длинный вопрос, но я довольно много просмотрел и не смог найти решение или пример, который описывает проблему с достаточной точностью.

Фон

Контекст представляет собой код вычислительной гидродинамики (CFD), основанный на методе разрывных спектральных элементов Галеркина (DGSEM) (см. Коприва (2009), Реализация спектральных методов для уравнений с частными производными). Для простоты предположим, что данные представлены в 2D (на самом деле они трехмерные, но переход от 2D к 3D должен быть простым).

У меня есть сетка, состоящая из K квадратных элементов k (k = 0,...,K-1), которые могут быть разных (физических) размеров. В каждом элементе сетки (или «ячейке») k у меня есть N_k^2 точек данных. N_k — это количество точек данных в каждом измерении, которое может варьироваться в зависимости от ячейки сетки.

В каждой точке данных n_k,i (где i = 0,...,N_k^2-1) я должен хранить массив значений решения, который имеет одинаковую длину nVars во всем домене (т.е. везде) и который не меняется во время выполнения.

Размеры и изменения

Количество ячеек сетки K составляет от O(10^5) до O(10^6) и может изменяться во время выполнения.
Количество точек данных N_k в каждой ячейке сетки составляет от 2 до 8 и может > изменяются во время выполнения (и могут быть разными для разных ячеек).
Количество переменных nVars, хранящихся в каждой точке сетки, составляет от 5 до 10 и не может изменяться во время выполнения (это также одно и то же для каждой ячейки сетки).

Требования

Производительность является ключевым вопросом здесь. Мне нужно иметь возможность регулярно и упорядоченно выполнять итерации по всем точкам сетки всех ячеек эффективным образом (т.е. без слишком большого количества промахов кеша). Как правило, K и N_k не меняются очень часто во время моделирования, поэтому, например, можно использовать большой непрерывный блок памяти для всех ячеек и точек данных.

Однако мне нужно иметь возможность уточнять или огрублять сетку (т.е. удалять ячейки и создавать новые, новые могут быть добавлены в конец) во время выполнения. Мне также нужно иметь возможность изменить порядок аппроксимации N_k, поэтому количество точек данных, которые я сохраняю для каждой ячейки, также может меняться во время выполнения.

Заключение

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

Если это неправильное место, чтобы задать этот вопрос, пожалуйста, дайте мне знать, какое место было бы более подходящим.


person Michael Schlottke-Lakemper    schedule 10.07.2012    source источник
comment
Означает ли это, что вы можете гарантировать максимальное количество необходимых элементов?   -  person Nathan White    schedule 10.07.2012
comment
Только с очень большим отрывом. Вся идея заключается в том, что сетка может уточняться динамически, т.е. в зависимости от развития потокового решения в определенных точках (физического) пространства. Так что для всех намерений и целей ... вероятно, нет.   -  person Michael Schlottke-Lakemper    schedule 10.07.2012
comment
Как вы перебираете сетку? Это имеет значение? Вы получаете доступ к соседним точкам сетки во время обновления? К сожалению, сейчас у меня нет возможности посмотреть первоисточник.   -  person simon    schedule 10.07.2012
comment
В общем, да. Точки данных соседних ячеек по всем основным направлениям (-x, +x, -y, +y) будут доступны (правда, не все из них, а только точки данных, лежащие ближе всего к текущей ячейке). Однако существуют также проходы по всем ячейкам, где порядок на самом деле не имеет значения, поскольку доступ осуществляется только к внутренним точкам данных в каждой ячейке.   -  person Michael Schlottke-Lakemper    schedule 10.07.2012


Ответы (2)


Часто такие виды динамических сетчатых структур могут быть очень сложными для эффективной работы, но в блочно-структурированных адаптивных кодах уточнения сетки (распространенных в астрофизике, где сложная геометрия не важна) или коде спектральных элементов, где у вас большие размеры блоков. , это часто гораздо меньшая проблема. У вас так много работы для каждого блока/элемента (по крайней мере, 10 ^ 5 ячеек x 2 точки/ячейка в вашем случае), что стоимость переключения между блоками сравнительно невелика.

Имейте также в виду, что обычно вы не можете делать слишком много тяжелой работы над каждым элементом или блоком, пока значительный объем данных этого блока уже не находится в кэше. Вам уже придется сбросить большую часть данных блока N из кеша, прежде чем вы все равно проделаете большую работу над блоком N + 1. (В вашем коде могут быть некоторые операции, которые являются исключениями из этого, но это, вероятно, не те операции, на которые вы в любом случае тратите много времени, с кэшем или без кэша, потому что повторное использование данных невелико — например, поэлементные операции над значения ячейки). Таким образом, размещение блоков/элементов рядом друг с другом не обязательно является большой проблемой; с другой стороны, вы определенно хотите, чтобы блоки/элементы были смежными.

Также обратите внимание, что вы можете перемещать блоки, чтобы они оставались непрерывными при изменении размера, но не только все эти копии памяти также будут стирать ваш кеш, но и сами копии памяти становятся очень дорогими. Если ваша проблема заключается в заполнении значительной части памяти (а так ли это всегда?), скажем, 1 ГБ, и вам нужно переместить 20% этого места после уточнения, чтобы снова сделать все непрерывным, это 0,2 ГБ (чтение + запись). ) / ~ 20 ГБ / с ~ 20 мс по сравнению с перезагрузкой (скажем) 16 000 строк кэша со скоростью ~ 100 нс каждая ~ 1,5 мс. И ваш кеш все равно удаляется после перетасовки. Возможно, это все же стоило бы сделать, если бы вы знали, что будете выполнять уточнение/удаление определения очень редко.

Но на практике большинство кодов адаптивной сетки в астрофизической гидродинамике (где я знаю коды достаточно хорошо, чтобы сказать) просто поддерживают список блоков и их метаданных и не беспокоятся об их смежности. YMMV, конечно. Мое предложение: прежде чем тратить слишком много времени на создание идеальной структуры данных, сначала просто протестируйте операцию на двух элементах дважды; первый, с элементами в порядке и вычислениями над ними 1-2, а второй, выполняя операцию в «неправильном» порядке, 2-1, и несколько раз синхронизируя два вычисления.

person Jonathan Dursi    schedule 10.07.2012
comment
Хм. Что вы думаете о сохранении отдельного места в памяти для каждого значения N_k и хранении количества ячеек с таким количеством точек данных? Обычно N_k не должно отличаться более чем на 3-4 по всему домену, поэтому наличие 3-4 отдельных списков должно оставаться относительно простым в обращении. Конечно, это усложнило бы такие вещи, как уникальные идентификаторы ячеек, информацию о соседях и т. д. Увы, может быть, вы правы, и мне следует просто использовать простой массив указателей на объекты... - person Michael Schlottke-Lakemper; 10.07.2012

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

person Jed    schedule 26.08.2012
comment
Что вы подразумеваете под можно управлять без привязки к сетке? - person Michael Schlottke-Lakemper; 26.08.2012
comment
Линейные алгебраические операции ничего не знают (математически) о физическом смысле векторов. Это хорошее свойство, которое нужно поддерживать, иначе вы получите более тесную связь между программными компонентами и вам придется выполнять гораздо больше работы для использования библиотек (например, писать все свои собственные примитивные операции) и часто жертвовать производительностью из-за более сложного обхода. - person Jed; 26.08.2012