2015-09-16 21:16:07 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
2019-04-15 23:24:21 +00:00
|
|
|
//
|
2015-09-16 21:16:07 +00:00
|
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
|
|
//============================================================================
|
2015-12-02 18:55:49 +00:00
|
|
|
|
2018-05-04 18:42:46 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <thread>
|
2015-09-16 21:16:07 +00:00
|
|
|
|
2019-04-09 13:52:53 +00:00
|
|
|
#include <vtkm/cont/Initialize.h>
|
2019-09-02 14:38:47 +00:00
|
|
|
#include <vtkm/cont/PartitionedDataSet.h>
|
2016-08-22 19:45:45 +00:00
|
|
|
|
2018-05-04 18:42:46 +00:00
|
|
|
#include "IOGenerator.h"
|
|
|
|
#include "MultiDeviceGradient.h"
|
|
|
|
#include "TaskQueue.h"
|
2015-09-16 21:16:07 +00:00
|
|
|
|
2018-05-04 18:42:46 +00:00
|
|
|
//This demo shows off using vtk-m in multiple threads in two different ways.
|
|
|
|
//
|
|
|
|
//At a high level we have 2 primary threads, an IO thread and a Worker thread
|
|
|
|
//The IO thread will generate all data using the vtk-m serial device, and
|
2019-09-02 14:38:47 +00:00
|
|
|
//will post this data to a worker queue as a vtk-m partitioned dataset.
|
|
|
|
//The Worker thread will pull down these vtk-m data and run a
|
|
|
|
//vtk-m filter on the partitions.
|
2018-05-04 18:42:46 +00:00
|
|
|
//The vtk-m filter it runs will itself have a worker pool which it will
|
|
|
|
//distribute work too. The number of workers is based on what device adapters
|
|
|
|
//are enabled but uses the following logic:
|
|
|
|
// - If TBB is enabled construct a single TBB worker
|
|
|
|
// - If CUDA is enabled construct 4 workers for each GPU on the machine
|
|
|
|
//
|
|
|
|
//Unfortunately due to some thread unsafe logic in VTK-m it is currently not
|
|
|
|
//possible to have CUDA and TBB workers at the same time. So the class will
|
|
|
|
//choose CUDA over TBB when possible.
|
|
|
|
//Once the thread unsafe logic is fixed a machine that has a single CPU
|
|
|
|
//and single GPU we should expect that we will have 2 primary 'main loop'
|
|
|
|
//threads, and 5 threads for heavy 'task' work.
|
|
|
|
|
2019-09-02 14:38:47 +00:00
|
|
|
void partition_processing(TaskQueue<vtkm::cont::PartitionedDataSet>& queue);
|
2019-04-09 13:52:53 +00:00
|
|
|
int main(int argc, char** argv)
|
2015-09-16 21:16:07 +00:00
|
|
|
{
|
2019-04-09 13:52:53 +00:00
|
|
|
auto opts =
|
|
|
|
vtkm::cont::InitializeOptions::DefaultAnyDevice | vtkm::cont::InitializeOptions::Strict;
|
|
|
|
vtkm::cont::Initialize(argc, argv, opts);
|
|
|
|
|
2018-05-04 18:42:46 +00:00
|
|
|
//Step 1. Construct the two primary 'main loops'. The threads
|
|
|
|
//share a queue object so we need to explicitly pass it
|
|
|
|
//by reference (the std::ref call)
|
2019-09-02 14:38:47 +00:00
|
|
|
TaskQueue<vtkm::cont::PartitionedDataSet> queue;
|
2018-07-31 19:02:41 +00:00
|
|
|
std::thread io(io_generator, std::ref(queue), 6);
|
2019-09-02 14:38:47 +00:00
|
|
|
std::thread worker(partition_processing, std::ref(queue));
|
2018-05-04 18:42:46 +00:00
|
|
|
|
|
|
|
//Step N. Wait for the work to finish
|
|
|
|
io.join();
|
|
|
|
worker.join();
|
|
|
|
return 0;
|
|
|
|
}
|
2015-09-16 21:16:07 +00:00
|
|
|
|
2018-05-04 18:42:46 +00:00
|
|
|
//=================================================================
|
2019-09-02 14:38:47 +00:00
|
|
|
void partition_processing(TaskQueue<vtkm::cont::PartitionedDataSet>& queue)
|
2015-09-16 21:16:07 +00:00
|
|
|
{
|
2018-05-04 18:42:46 +00:00
|
|
|
//Step 1. Construct the gradient filter outside the work loop
|
|
|
|
//so that we can reuse the thread pool it constructs
|
|
|
|
MultiDeviceGradient gradient;
|
|
|
|
gradient.SetComputePointGradient(true);
|
|
|
|
while (queue.hasTasks())
|
2015-09-16 21:16:07 +00:00
|
|
|
{
|
2019-09-02 14:38:47 +00:00
|
|
|
//Step 2. grab the next partition skipping any that are empty
|
2018-05-04 18:42:46 +00:00
|
|
|
//as empty ones can be returned when the queue is about
|
|
|
|
//to say it has no work
|
2019-09-02 14:38:47 +00:00
|
|
|
vtkm::cont::PartitionedDataSet pds = queue.pop();
|
|
|
|
if (pds.GetNumberOfPartitions() == 0)
|
2018-05-04 18:42:46 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2016-08-22 19:45:45 +00:00
|
|
|
|
2019-09-02 14:38:47 +00:00
|
|
|
//Step 3. Get the first field name from the partition
|
|
|
|
std::string fieldName = pds.GetPartition(0).GetField(0).GetName();
|
2016-08-22 19:45:45 +00:00
|
|
|
|
2018-05-04 18:42:46 +00:00
|
|
|
//Step 4. Run a multi device gradient
|
|
|
|
gradient.SetActiveField(fieldName);
|
2019-09-02 14:38:47 +00:00
|
|
|
vtkm::cont::PartitionedDataSet result = gradient.Execute(pds);
|
|
|
|
std::cout << "finished processing a partitioned dataset" << std::endl;
|
2016-08-22 19:45:45 +00:00
|
|
|
|
2019-09-02 14:38:47 +00:00
|
|
|
//Step 5. Verify each partition has a "Gradients" field
|
|
|
|
for (auto&& partition : result)
|
2015-09-16 21:16:07 +00:00
|
|
|
{
|
2018-05-04 18:42:46 +00:00
|
|
|
// std::cout << std::endl << std::endl << std::endl;
|
2019-09-02 14:38:47 +00:00
|
|
|
// std::cout << "partition: " << std::endl;
|
|
|
|
// partition.PrintSummary(std::cout);
|
2022-03-17 17:02:37 +00:00
|
|
|
if (!partition.HasField("Gradients", vtkm::cont::Field::Association::Points))
|
2018-05-04 18:42:46 +00:00
|
|
|
{
|
2019-08-07 15:24:54 +00:00
|
|
|
std::cerr << "Gradient filter failed!" << std::endl;
|
2019-09-02 14:38:47 +00:00
|
|
|
std::cerr << "Missing Gradient field on output partition." << std::endl;
|
2018-05-04 18:42:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-09-16 21:16:07 +00:00
|
|
|
}
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2016-08-22 19:45:45 +00:00
|
|
|
|
2019-09-02 14:38:47 +00:00
|
|
|
std::cout << "partition_processing finished" << std::endl;
|
2015-09-16 21:16:07 +00:00
|
|
|
}
|