Я пытаюсь скопировать данные в tile_static для длительного запуска процесса. Во всех примерах, которые я видел, массив объявляется, и данные заполняются по частям для каждого потока в плитке. Затем эти потоки делятся этими данными. То, что я хочу сделать, это просто скопировать некоторые данные с помощью tile_static для использования одним потоком. Мне не нужно делиться этим, но так как он очень долгий, я понимаю, что это повысит производительность. Хотя я не уверен, что это правильный путь. Вызов tile_static, который я пытаюсь сделать, находится у дна в цикле parallel_for_each и выглядит следующим образом:
tile_static vector<int_2> route = av_RouteSet[t_idx.global[0]];
Я включил дополнительный код для ясности.
vector<float> tiledTSPCompute(accelerator_view accl, city_set CityLocations, int NumberOfTiles,
float StartTemp, float EndTemp, float CoolingCoefficient, unsigned int MovesPerTemp){
// Setting tile size
static const int TS = 16;
// Setting number of runs in terms of number of tiles
int NumberOfRuns = NumberOfTiles * TS * TS;
// Get results vector ready
vector<float> Results(NumberOfRuns);
array_view<float> av_Results(Results);
// Get routes ready
vector<int_2> RouteSet(sizeof(CityLocations.Cities) * NumberOfRuns);
array_view<int_2, 2> av_RouteSet(NumberOfRuns, sizeof(CityLocations.Cities), RouteSet);
// Prepare extent
concurrency::extent<1> e(NumberOfRuns);
// Create RNG
tinymt_collection<1> mtSet(e, 500);
concurrency::parallel_for_each(accl, av_Results.extent.tile<TS, TS>(), [=](tiled_index<TS, TS> t_idx)restrict(amp){
auto& mt = mtSet[t_idx.global];
//What I would like to do
tile_static vector<int_2> route = av_RouteSet[t_idx.global[0]];
Tiled_InitializeRoute(route);
Tiled_RandomizeRoute(route, mt);
Tiled_HeuristicRun(StartTemp, EndTemp, CoolingCoefficient, CityLocations, route, MovesPerTemp, mt);
av_Results[t_idx.global] = Tiled_TotalRouteDistance(route, CityLocations);
});
};
Как следует из названия, мозаичная память — это память, доступная для каждой плитки. Его основное использование — разделение памяти между потоками в плитке. Вот почему вы видите общий шаблон. Группа потоков загружает статическую память тайла (параллельно), выполняет чтение и запись в эту память, часто с барьерами для предотвращения состязаний, и, наконец, сохраняет результат в глобальной памяти. Плитка локальной памяти более эффективна, чем чтение из глобальной памяти.
Однако в вашем примере вы не используете эти свойства памяти тайлов. Было бы лучше использовать локальную память для хранения этих данных, поскольку вы не делите их между потоками. То же самое касается mtSet
массив. Вы должны объявить эти массивы локально для ядра и инициализировать их там. Если какой-либо из них является постоянным, вы должны объявить его как таковой, чтобы позволить им использовать постоянную память, а не локальную память.
В зависимости от размера этих данных вы можете столкнуться с проблемами занятости. Объем локальной памяти очень ограничен, обычно 10 с КБ. Если вы используете «много на поток», тогда графический процессор не сможет планировать больше деформаций, что ограничивает его способность скрывать задержки, планируя дополнительные деформации, когда существующие блокируются. Вы можете подумать о перераспределении вашей работы в каждом потоке, если это кажется проблемой.
Большая часть этого освещена в главах по оптимизации и производительности в моем C ++ AMP book. Следующее также содержит хороший обзор различные типы памяти GPU, хотя написано с точки зрения CUDA, а не AMP.
Других решений пока нет …