From 987a1fd8a20f3ab8013646ae4bb213b34bb97a71 Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Fri, 19 Nov 2021 11:32:18 -0800 Subject: [PATCH 01/13] fix include path --- vtkm/cont/cuda/ChooseCudaDevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vtkm/cont/cuda/ChooseCudaDevice.h b/vtkm/cont/cuda/ChooseCudaDevice.h index ae3a215db..2928fe7a9 100644 --- a/vtkm/cont/cuda/ChooseCudaDevice.h +++ b/vtkm/cont/cuda/ChooseCudaDevice.h @@ -14,8 +14,8 @@ #include #include +#include #include -#include #include #include From 7ebdaac1fe23e7fc1265d46fc6deb9471f646618 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Mon, 22 Nov 2021 13:31:02 -0500 Subject: [PATCH 02/13] CI: Remove use_virtuals at GCC5.2 build --- .gitlab/ci/ubuntu1604.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab/ci/ubuntu1604.yml b/.gitlab/ci/ubuntu1604.yml index 5ac715e6b..ded8bfe9f 100644 --- a/.gitlab/ci/ubuntu1604.yml +++ b/.gitlab/ci/ubuntu1604.yml @@ -56,7 +56,7 @@ build:ubuntu1604_gcc5_2: CC: "gcc-5" CXX: "g++-5" CMAKE_BUILD_TYPE: Release - VTKM_SETTINGS: "openmp+cuda+pascal+examples+static+use_virtuals" + VTKM_SETTINGS: "openmp+cuda+pascal+examples+static" test:ubuntu1804_test_ubuntu1604_gcc5_2: tags: From 035a7b39bc26e5989eb4a49175d6ce13861e1de5 Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Wed, 30 Jun 2021 08:58:40 -0700 Subject: [PATCH 03/13] Add initial framework for in-situ benchmarks This adapts existing benchmarks and creates new ones that simulate in-situ simulations. --- benchmarking/BenchmarkInSitu.cxx | 1073 ++++++++++++++++++++++++++++++ benchmarking/CMakeLists.txt | 1 + 2 files changed, 1074 insertions(+) create mode 100644 benchmarking/BenchmarkInSitu.cxx diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx new file mode 100644 index 000000000..20d218f36 --- /dev/null +++ b/benchmarking/BenchmarkInSitu.cxx @@ -0,0 +1,1073 @@ +#include "Benchmarker.h" + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +const uint32_t DEFAULT_NUM_CYCLES = 20; +const vtkm::Id DEFAULT_DATASET_DIM = 128; +const vtkm::FloatDefault DEFAULT_SPACING = 0.1f; + +// Hold configuration state (e.g. active device): +vtkm::cont::InitializeResult Config; +// Input dataset dimensions: +static vtkm::Id DataSetDim; +// The input datasets we'll use on the filters: +static vtkm::cont::DataSet InputDataSet; +static vtkm::cont::PartitionedDataSet PartitionedInputDataSet; +// The point scalars to use: +static std::string PointScalarsName; +// The point vectors to use: +static std::string PointVectorsName; + +enum class RenderingMode +{ + None = 0, + Mesh = 1, + RayTrace = 2, + Volume = 3, +}; + +struct PerlinNoise3DWorklet : public vtkm::worklet::WorkletVisitPointsWithCells +{ + using ControlSignature = void(CellSetIn, FieldInPoint, WholeArrayIn, FieldOut noise); + using ExecutionSignature = void(_2, _3, _4); + + VTKM_CONT PerlinNoise3DWorklet(vtkm::Id repeat) + : Repeat(repeat) + { + } + + // Adapted from https://adrianb.io/2014/08/09/perlinnoise.html + // Archive link: https://web.archive.org/web/20210329174559/https://adrianb.io/2014/08/09/perlinnoise.html + template + VTKM_EXEC void operator()(const PointVecType& pos, const PermsPortal& perms, OutType& noise) const + { + vtkm::Id xi = static_cast(pos[0]) % this->Repeat; + vtkm::Id yi = static_cast(pos[1]) % this->Repeat; + vtkm::Id zi = static_cast(pos[2]) % this->Repeat; + vtkm::FloatDefault xf = pos[0] - xi; + vtkm::FloatDefault yf = pos[1] - yi; + vtkm::FloatDefault zf = pos[2] - zi; + vtkm::FloatDefault u = this->Fade(xf); + vtkm::FloatDefault v = this->Fade(yf); + vtkm::FloatDefault w = this->Fade(zf); + + vtkm::Id aaa, aba, aab, abb, baa, bba, bab, bbb; + aaa = perms[perms[perms[xi] + yi] + zi]; + aba = perms[perms[perms[xi] + this->Increment(yi)] + zi]; + aab = perms[perms[perms[xi] + yi] + this->Increment(zi)]; + abb = perms[perms[perms[xi] + this->Increment(yi)] + this->Increment(zi)]; + baa = perms[perms[perms[this->Increment(xi)] + yi] + zi]; + bba = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + zi]; + bab = perms[perms[perms[this->Increment(xi)] + yi] + this->Increment(zi)]; + bbb = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + this->Increment(zi)]; + + vtkm::FloatDefault x1, x2, y1, y2; + x1 = vtkm::Lerp(this->Gradient(aaa, xf, yf, zf), this->Gradient(baa, xf - 1, yf, zf), u); + x2 = + vtkm::Lerp(this->Gradient(aba, xf, yf - 1, zf), this->Gradient(bba, xf - 1, yf - 1, zf), u); + y1 = vtkm::Lerp(x1, x2, v); + + x1 = + vtkm::Lerp(this->Gradient(aab, xf, yf, zf - 1), this->Gradient(bab, xf - 1, yf, zf - 1), u); + x2 = vtkm::Lerp( + this->Gradient(abb, xf, yf - 1, zf - 1), this->Gradient(bbb, xf - 1, yf - 1, zf - 1), u); + y2 = vtkm::Lerp(x1, x2, v); + + noise = (vtkm::Lerp(y1, y2, w) + OutType(1.0f)) * OutType(0.5f); + } + + VTKM_EXEC vtkm::FloatDefault Fade(vtkm::FloatDefault t) const + { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + VTKM_EXEC vtkm::Id Increment(vtkm::Id n) const { return (n + 1) % this->Repeat; } + + VTKM_EXEC vtkm::FloatDefault Gradient(vtkm::Id hash, + vtkm::FloatDefault x, + vtkm::FloatDefault y, + vtkm::FloatDefault z) const + { + switch (hash & 0xF) + { + case 0x0: + return x + y; + case 0x1: + return -x + y; + case 0x2: + return x - y; + case 0x3: + return -x - y; + case 0x4: + return x + z; + case 0x5: + return -x + z; + case 0x6: + return x - z; + case 0x7: + return -x - z; + case 0x8: + return y + z; + case 0x9: + return -y + z; + case 0xA: + return y - z; + case 0xB: + return -y - z; + case 0xC: + return y + x; + case 0xD: + return -y + z; + case 0xE: + return y - x; + case 0xF: + return -y - z; + default: + return 0; // never happens + } + } + + vtkm::Id Repeat; +}; + +class PerlinNoise3DGenerator : public vtkm::filter::FilterField +{ +public: + VTKM_CONT PerlinNoise3DGenerator(vtkm::IdComponent tableSize, vtkm::Id seed) + : TableSize(tableSize) + , Seed(seed) + { + this->GeneratePermutations(); + this->SetUseCoordinateSystemAsField(true); + } + + template + VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input, + const FieldType&, + const vtkm::filter::FieldMetadata& fieldMetadata, + vtkm::filter::PolicyBase) + { + vtkm::cont::ArrayHandle noiseArray; + PerlinNoise3DWorklet worklet{ this->TableSize }; + this->Invoke(worklet, input.GetCellSet(), input.GetCoordinateSystem(), this->P, noiseArray); + + return vtkm::filter::CreateResult(input, noiseArray, "PerlinNoise3D", fieldMetadata); + } + +protected: + VTKM_CONT void GeneratePermutations() + { + std::mt19937_64 rng; + rng.seed(this->Seed); + std::uniform_int_distribution distribution(0, this->TableSize - 1); + + vtkm::cont::ArrayHandle perms; + perms.Allocate(this->TableSize); + auto permsPortal = perms.WritePortal(); + for (auto i = 0; i < permsPortal.GetNumberOfValues(); ++i) + { + permsPortal.Set(i, distribution(rng)); + } + this->P.Allocate(2 * this->TableSize); + auto pPortal = this->P.WritePortal(); + for (auto i = 0; i < pPortal.GetNumberOfValues(); ++i) + { + pPortal.Set(i, permsPortal.Get(i % this->TableSize)); + } + } + + +private: + vtkm::IdComponent TableSize; + vtkm::Id Seed; + vtkm::cont::ArrayHandle P; +}; + +std::vector ExtractDataSets(const vtkm::cont::PartitionedDataSet& partitions) +{ + return partitions.GetPartitions(); +} + +// Mirrors ExtractDataSet(ParitionedDataSet), to keep code simple at use sites +std::vector ExtractDataSets(vtkm::cont::DataSet& dataSet) +{ + return std::vector{ dataSet }; +} + +void BuildInputDataSet(uint32_t cycle, + bool isStructured, + bool isMultiBlock, + vtkm::Id dims, + vtkm::FloatDefault spacing = 0.1f) +{ + vtkm::cont::PartitionedDataSet partitionedInputDataSet; + vtkm::cont::DataSet inputDataSet; + + PointScalarsName = "PerlinNoise3D"; + PointVectorsName = "PerlinNoise3DGradient"; + + // Generate uniform dataset(s) + const vtkm::Id3 dataSetDims{ dims, dims, dims }; + const vtkm::Vec3f dataSetSpacing{ spacing, spacing, spacing }; + if (isMultiBlock) + { + for (auto i = 0; i < 2; ++i) + { + for (auto j = 0; j < 2; ++j) + { + for (auto k = 0; k < 2; ++k) + { + const vtkm::Vec3f dataSetOrigin{ (dims - 1) * spacing * i, + (dims - 1) * spacing * j, + (dims - 1) * spacing * k }; + vtkm::cont::DataSetBuilderUniform dataSetBuilder; + vtkm::cont::DataSet uniformDataSet = + dataSetBuilder.Create(dataSetDims, dataSetOrigin, dataSetSpacing); + partitionedInputDataSet.AppendPartition(uniformDataSet); + } + } + } + } + else + { + const vtkm::Vec3f dataSetOrigin{ 0.0f, 0.0f, 0.0f }; + vtkm::cont::DataSetBuilderUniform dataSetBuilder; + inputDataSet = dataSetBuilder.Create(dataSetDims, dataSetOrigin, dataSetSpacing); + } + + // Generate Perlin Noise point scalar field + PerlinNoise3DGenerator fieldGenerator(dims, cycle); + if (isMultiBlock) + { + partitionedInputDataSet = fieldGenerator.Execute(partitionedInputDataSet); + } + else + { + inputDataSet = fieldGenerator.Execute(inputDataSet); + } + + // Generate Perln Noise Gradient point vector field + vtkm::filter::Gradient gradientFilter; + gradientFilter.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::POINTS); + gradientFilter.SetComputePointGradient(true); + gradientFilter.SetOutputFieldName(PointVectorsName); + gradientFilter.SetFieldsToPass( + vtkm::filter::FieldSelection(vtkm::filter::FieldSelection::MODE_ALL)); + if (isMultiBlock) + { + partitionedInputDataSet = gradientFilter.Execute(partitionedInputDataSet); + } + else + { + inputDataSet = gradientFilter.Execute(inputDataSet); + } + + // Run Tetrahedralize filter to convert uniform dataset(s) into unstructured ones + if (!isStructured) + { + vtkm::filter::Tetrahedralize destructizer; + destructizer.SetFieldsToPass( + vtkm::filter::FieldSelection(vtkm::filter::FieldSelection::MODE_ALL)); + if (isMultiBlock) + { + partitionedInputDataSet = destructizer.Execute(partitionedInputDataSet); + } + else + { + inputDataSet = destructizer.Execute(inputDataSet); + } + } + + // Release execution resources to simulate in-situ workload, where the data is + // not present in the execution environment + std::vector dataSets = + isMultiBlock ? ExtractDataSets(partitionedInputDataSet) : ExtractDataSets(inputDataSet); + for (auto& dataSet : dataSets) + { + dataSet.GetCellSet().ReleaseResourcesExecution(); + dataSet.GetCoordinateSystem().ReleaseResourcesExecution(); + dataSet.GetField(PointScalarsName).ReleaseResourcesExecution(); + dataSet.GetField(PointVectorsName).ReleaseResourcesExecution(); + } + + PartitionedInputDataSet = partitionedInputDataSet; + InputDataSet = inputDataSet; +} + +void RenderDataSets(const std::vector& dataSets, + RenderingMode mode, + std::string fieldName, + std::string bench, + bool isStructured, + uint32_t cycle) +{ + vtkm::rendering::Scene scene; + vtkm::cont::ColorTable colorTable("inferno"); + if (mode == RenderingMode::Volume) + { + colorTable.AddPointAlpha(0.0f, 0.03f); + colorTable.AddPointAlpha(1.0f, 0.01f); + } + + for (auto& dataSet : dataSets) + { + scene.AddActor(vtkm::rendering::Actor(dataSet.GetCellSet(), + dataSet.GetCoordinateSystem(), + dataSet.GetField(fieldName), + colorTable)); + } + + auto bounds = std::accumulate(dataSets.begin(), + dataSets.end(), + vtkm::Bounds(), + [=](const vtkm::Bounds& val, const vtkm::cont::DataSet& partition) { + return val + vtkm::cont::BoundsCompute(partition); + }); + vtkm::Vec3f_64 totalExtent(bounds.X.Length(), bounds.Y.Length(), bounds.Z.Length()); + vtkm::Float64 mag = vtkm::Magnitude(totalExtent); + vtkm::Normalize(totalExtent); + + // setup a camera and point it to towards the center of the input data + vtkm::rendering::Camera camera; + camera.SetFieldOfView(60.f); + camera.ResetToBounds(bounds); + camera.SetLookAt(totalExtent * (mag * .5f)); + camera.SetViewUp(vtkm::make_Vec(0.f, 1.f, 0.f)); + camera.SetPosition(totalExtent * (mag * 1.5f)); + + vtkm::rendering::CanvasRayTracer canvas(1920, 1080); + + auto mapper = [=]() -> std::unique_ptr { + switch (mode) + { + case RenderingMode::Mesh: + { + return std::unique_ptr(new vtkm::rendering::MapperWireframer()); + } + case RenderingMode::RayTrace: + { + return std::unique_ptr(new vtkm::rendering::MapperRayTracer()); + } + case RenderingMode::Volume: + { + return std::unique_ptr(new vtkm::rendering::MapperVolume()); + } + case RenderingMode::None: + default: + { + return std::unique_ptr(new vtkm::rendering::MapperRayTracer()); + } + } + }(); + + vtkm::rendering::View3D view(scene, + *mapper, + canvas, + camera, + vtkm::rendering::Color(0.8f, 0.8f, 0.6f), + vtkm::rendering::Color(0.2f, 0.4f, 0.2f)); + view.Paint(); + + // TODO: Remove this later, once the various benchmark quirks are fixed + (void)cycle; + (void)isStructured; + (void)bench; + /* + std::ostringstream p; + p << "output_" + << "c" << cycle << "_" << (isStructured ? "structured" : "unstructured") << "_" + << (dataSets.size() == 1 ? "single_" : "multi_") << bench << "_" + << (mode == RenderingMode::Mesh ? "mesh" : (mode == RenderingMode::Volume ? "volume" : "ray")) + << ".png"; + view.SaveAs(p.str()); + */ +} + +template +DataSetType RunContourHelper(vtkm::filter::Contour& filter, + vtkm::Id numIsoVals, + const DataSetType& input) +{ + // Set up some equally spaced contours, with the min/max slightly inside the + // scalar range: + const vtkm::Range scalarRange = + vtkm::cont::ArrayGetValue(0, vtkm::cont::FieldRangeCompute(input, PointScalarsName)); + const auto step = scalarRange.Length() / static_cast(numIsoVals + 1); + const auto minIsoVal = scalarRange.Min + (step * 0.5f); + filter.SetNumberOfIsoValues(numIsoVals); + for (vtkm::Id i = 0; i < numIsoVals; ++i) + { + filter.SetIsoValue(i, minIsoVal + (step * static_cast(i))); + } + + return filter.Execute(input); +} + +void BenchContour(::benchmark::State& state) +{ + const vtkm::cont::DeviceAdapterId device = Config.Device; + + const uint32_t cycle = static_cast(state.range(0)); + const vtkm::Id numIsoVals = static_cast(state.range(1)); + const bool isStructured = static_cast(state.range(2)); + const bool isMultiBlock = static_cast(state.range(3)); + const RenderingMode renderAlgo = static_cast(state.range(4)); + + vtkm::cont::Timer inputGenTimer{ device }; + inputGenTimer.Start(); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + inputGenTimer.Stop(); + + vtkm::filter::Contour filter; + filter.SetActiveField(PointScalarsName, vtkm::cont::Field::Association::POINTS); + filter.SetMergeDuplicatePoints(true); + filter.SetGenerateNormals(true); + filter.SetComputeFastNormalsForStructured(true); + filter.SetComputeFastNormalsForUnstructured(true); + + vtkm::cont::Timer totalTimer{ device }; + vtkm::cont::Timer filterTimer{ device }; + vtkm::cont::Timer renderTimer{ device }; + + for (auto _ : state) + { + (void)_; + totalTimer.Start(); + filterTimer.Start(); + std::vector dataSets; + if (isMultiBlock) + { + auto input = PartitionedInputDataSet; + auto result = RunContourHelper(filter, numIsoVals, input); + dataSets = ExtractDataSets(result); + } + else + { + auto input = InputDataSet; + auto result = RunContourHelper(filter, numIsoVals, input); + dataSets = ExtractDataSets(result); + } + filterTimer.Stop(); + + renderTimer.Start(); + RenderDataSets(dataSets, renderAlgo, PointScalarsName, "contour", isStructured, cycle); + renderTimer.Stop(); + + totalTimer.Stop(); + + state.SetIterationTime(totalTimer.GetElapsedTime()); + state.counters.insert( + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "FilterTime", static_cast(filterTimer.GetElapsedTime() * 1000) }, + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) } }); + } +} + +void BenchContourGenerator(::benchmark::internal::Benchmark* bm) +{ + bm->ArgNames({ "Cycle", "NIsos", "IsStructured", "IsMultiBlock", "RenderingMode" }); + + std::vector isStructureds{ false, true }; + std::vector isMultiBlocks{ false, true }; + std::vector renderingModes{ RenderingMode::RayTrace }; + for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle) + { + for (auto& isStructured : isStructureds) + { + for (auto& isMultiBlock : isMultiBlocks) + { + for (auto& mode : renderingModes) + { + bm->Args({ cycle, 10, isStructured, isMultiBlock, static_cast(mode) }); + } + } + } + } +} + +VTKM_BENCHMARK_APPLY(BenchContour, BenchContourGenerator); + +void MakeRandomSeeds(vtkm::Id seedCount, + vtkm::Bounds& bounds, + vtkm::cont::ArrayHandle& seeds) +{ + std::default_random_engine generator(static_cast(255)); + vtkm::FloatDefault zero(0), one(1); + std::uniform_real_distribution distribution(zero, one); + std::vector points; + points.resize(0); + for (vtkm::Id i = 0; i < seedCount; i++) + { + vtkm::FloatDefault rx = distribution(generator); + vtkm::FloatDefault ry = distribution(generator); + vtkm::FloatDefault rz = distribution(generator); + vtkm::Vec3f p; + p[0] = static_cast(bounds.X.Min + rx * bounds.X.Length()); + p[1] = static_cast(bounds.Y.Min + ry * bounds.Y.Length()); + p[2] = static_cast(bounds.Z.Min + rz * bounds.Z.Length()); + points.push_back(vtkm::Particle(p, static_cast(i))); + } + vtkm::cont::ArrayHandle tmp = + vtkm::cont::make_ArrayHandle(points, vtkm::CopyFlag::Off); + vtkm::cont::ArrayCopy(tmp, seeds); +} + +vtkm::Id GetNumberOfPoints(const vtkm::cont::DataSet& input) +{ + return input.GetCoordinateSystem().GetNumberOfPoints(); +} + +vtkm::Id GetNumberOfPoints(const vtkm::cont::PartitionedDataSet& input) +{ + return input.GetPartition(0).GetCoordinateSystem().GetNumberOfPoints(); +} + +void AddField(vtkm::cont::DataSet& input, + std::string fieldName, + std::vector& field) +{ + input.AddPointField(fieldName, field); +} + +void AddField(vtkm::cont::PartitionedDataSet& input, + std::string fieldName, + std::vector& field) +{ + for (auto i = 0; i < input.GetNumberOfPartitions(); ++i) + { + auto partition = input.GetPartition(i); + AddField(partition, fieldName, field); + input.ReplacePartition(i, partition); + } +} + +template +DataSetType RunStreamlinesHelper(vtkm::filter::Streamline& filter, const DataSetType& input) +{ + auto dataSetBounds = vtkm::cont::BoundsCompute(input); + vtkm::cont::ArrayHandle seedArray; + MakeRandomSeeds(100, dataSetBounds, seedArray); + filter.SetSeeds(seedArray); + + auto result = filter.Execute(input); + auto numPoints = GetNumberOfPoints(result); + std::vector colorMap( + static_cast::size_type>(numPoints)); + for (std::vector::size_type i = 0; i < colorMap.size(); i++) + { + colorMap[i] = static_cast(i); + } + + AddField(result, "pointvar", colorMap); + return result; +} + +void BenchStreamlines(::benchmark::State& state) +{ + const vtkm::cont::DeviceAdapterId device = Config.Device; + + const uint32_t cycle = static_cast(state.range(0)); + const bool isStructured = static_cast(state.range(1)); + const bool isMultiBlock = static_cast(state.range(2)); + const RenderingMode renderAlgo = static_cast(state.range(3)); + + vtkm::cont::Timer inputGenTimer{ device }; + inputGenTimer.Start(); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + inputGenTimer.Stop(); + + vtkm::filter::Streamline streamline; + streamline.SetStepSize(0.1f); + streamline.SetNumberOfSteps(1000); + streamline.SetActiveField(PointVectorsName); + + vtkm::cont::Timer totalTimer{ device }; + vtkm::cont::Timer filterTimer{ device }; + vtkm::cont::Timer renderTimer{ device }; + + for (auto _ : state) + { + (void)_; + totalTimer.Start(); + filterTimer.Start(); + + std::vector dataSets; + if (isMultiBlock) + { + auto input = PartitionedInputDataSet; + auto result = RunStreamlinesHelper(streamline, input); + dataSets = ExtractDataSets(result); + } + else + { + auto input = InputDataSet; + auto result = RunStreamlinesHelper(streamline, input); + dataSets = ExtractDataSets(result); + } + filterTimer.Stop(); + + renderTimer.Start(); + RenderDataSets(dataSets, renderAlgo, "pointvar", "streamlines", isStructured, cycle); + renderTimer.Stop(); + + totalTimer.Stop(); + + state.SetIterationTime(totalTimer.GetElapsedTime()); + state.counters.insert( + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "FilterTime", static_cast(filterTimer.GetElapsedTime() * 1000) }, + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) } }); + } +} + +void BenchStreamlinesGenerator(::benchmark::internal::Benchmark* bm) +{ + bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock", "RenderingMode" }); + + std::vector isStructureds{ false, true }; + std::vector isMultiBlocks{ false, true }; + std::vector renderingModes{ RenderingMode::Mesh }; + for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle) + { + for (auto& isStructured : isStructureds) + { + for (auto& isMultiBlock : isMultiBlocks) + { + for (auto& mode : renderingModes) + { + bm->Args({ cycle, isStructured, isMultiBlock, static_cast(mode) }); + } + } + } + } +} + +VTKM_BENCHMARK_APPLY(BenchStreamlines, BenchStreamlinesGenerator); + +vtkm::Vec3f GetSlicePlaneOrigin(const bool isMultiBlock) +{ + if (isMultiBlock) + { + auto data = PartitionedInputDataSet; + vtkm::Bounds global; + global = data.GetPartition(0).GetCoordinateSystem().GetBounds(); + for (auto i = 1; i < data.GetNumberOfPartitions(); ++i) + { + auto dataset = data.GetPartition(i); + vtkm::Bounds bounds = dataset.GetCoordinateSystem().GetBounds(); + global.X.Min = vtkm::Min(global.X.Min, bounds.X.Min); + global.Y.Min = vtkm::Min(global.Y.Min, bounds.Y.Min); + global.Z.Min = vtkm::Min(global.Z.Min, bounds.Z.Min); + global.X.Max = vtkm::Min(global.X.Max, bounds.X.Max); + global.Y.Max = vtkm::Min(global.Y.Max, bounds.Y.Max); + global.Z.Max = vtkm::Min(global.Z.Max, bounds.Z.Max); + } + return vtkm::Vec3f{ static_cast((global.X.Max - global.X.Min) / 2.), + static_cast((global.Y.Max - global.Y.Min) / 2.), + static_cast((global.Z.Max - global.Z.Min) / 2.) }; + } + else + { + auto data = InputDataSet; + vtkm::Bounds bounds = data.GetCoordinateSystem().GetBounds(); + return vtkm::Vec3f{ static_cast((bounds.X.Max - bounds.X.Min) / 2.), + static_cast((bounds.Y.Max - bounds.Y.Min) / 2.), + static_cast((bounds.Z.Max - bounds.Z.Min) / 2.) }; + } +} + +void BenchSlice(::benchmark::State& state) +{ + const vtkm::cont::DeviceAdapterId device = Config.Device; + + const uint32_t cycle = static_cast(state.range(0)); + const bool isStructured = static_cast(state.range(1)); + const bool isMultiBlock = static_cast(state.range(2)); + const RenderingMode renderAlgo = static_cast(state.range(3)); + + vtkm::cont::Timer inputGenTimer{ device }; + inputGenTimer.Start(); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + inputGenTimer.Stop(); + + vtkm::filter::Slice filter; + + vtkm::cont::Timer totalTimer{ device }; + vtkm::cont::Timer filterTimer{ device }; + vtkm::cont::Timer renderTimer{ device }; + + for (auto _ : state) + { + (void)_; + totalTimer.Start(); + filterTimer.Start(); + std::vector dataSets; + if (isMultiBlock) + { + auto input = PartitionedInputDataSet; + vtkm::Vec3f origin = GetSlicePlaneOrigin(isMultiBlock); + // Set-up implicit function + vtkm::Plane plane(origin, vtkm::Plane::Vector{ 1, 1, 1 }); + filter.SetImplicitFunction(plane); + auto result = filter.Execute(input); + dataSets = ExtractDataSets(result); + } + else + { + auto input = InputDataSet; + vtkm::Vec3f origin = GetSlicePlaneOrigin(isMultiBlock); + // Set-up implicit function + vtkm::Plane plane(origin, vtkm::Plane::Vector{ 1, 1, 1 }); + filter.SetImplicitFunction(plane); + auto result = filter.Execute(input); + dataSets = ExtractDataSets(result); + } + filterTimer.Stop(); + + renderTimer.Start(); + RenderDataSets(dataSets, renderAlgo, PointScalarsName, "slice", isStructured, cycle); + renderTimer.Stop(); + + totalTimer.Stop(); + + state.SetIterationTime(totalTimer.GetElapsedTime()); + state.counters.insert( + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "FilterTime", static_cast(filterTimer.GetElapsedTime() * 1000) }, + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) } }); + } +} + +void BenchSliceGenerator(::benchmark::internal::Benchmark* bm) +{ + bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock", "RenderingMode" }); + + std::vector isStructureds{ false, true }; + std::vector isMultiBlocks{ false, true }; + std::vector renderingModes{ RenderingMode::RayTrace }; + for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle) + { + for (auto& isStructured : isStructureds) + { + for (auto& isMultiBlock : isMultiBlocks) + { + for (auto& mode : renderingModes) + { + bm->Args({ cycle, isStructured, isMultiBlock, static_cast(mode) }); + } + } + } + } +} + +VTKM_BENCHMARK_APPLY(BenchSlice, BenchSliceGenerator); + +void BenchMeshRendering(::benchmark::State& state) +{ + const vtkm::cont::DeviceAdapterId device = Config.Device; + + const uint32_t cycle = static_cast(state.range(0)); + const bool isStructured = static_cast(state.range(1)); + const bool isMultiBlock = static_cast(state.range(2)); + + vtkm::cont::Timer inputGenTimer{ device }; + inputGenTimer.Start(); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + inputGenTimer.Stop(); + + vtkm::cont::Timer totalTimer{ device }; + + for (auto _ : state) + { + (void)_; + + totalTimer.Start(); + std::vector dataSets = + isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet); + RenderDataSets(dataSets, RenderingMode::Mesh, PointScalarsName, "mesh", isStructured, cycle); + totalTimer.Stop(); + + state.SetIterationTime(totalTimer.GetElapsedTime()); + state.counters.insert( + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) } }); + } +} + +void BenchMeshRenderingGenerator(::benchmark::internal::Benchmark* bm) +{ + bm->ArgNames({ "Cycle", "IsStructured", "IsMultiBlock" }); + + std::vector isStructureds{ false, true }; + std::vector isMultiBlocks{ false, true }; + for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle) + { + for (auto& isStructured : isStructureds) + { + for (auto& isMultiBlock : isMultiBlocks) + { + bm->Args({ cycle, isStructured, isMultiBlock }); + } + } + } +} + +VTKM_BENCHMARK_APPLY(BenchMeshRendering, BenchMeshRenderingGenerator); + +void BenchVolumeRendering(::benchmark::State& state) +{ + const vtkm::cont::DeviceAdapterId device = Config.Device; + + const uint32_t cycle = static_cast(state.range(0)); + const bool isStructured = true; + const bool isMultiBlock = static_cast(state.range(1)); + + vtkm::cont::Timer inputGenTimer{ device }; + inputGenTimer.Start(); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + inputGenTimer.Stop(); + + vtkm::cont::Timer totalTimer{ device }; + + for (auto _ : state) + { + (void)_; + vtkm::rendering::Scene scene; + + totalTimer.Start(); + std::vector dataSets = + isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet); + RenderDataSets( + dataSets, RenderingMode::Volume, PointScalarsName, "volume", isStructured, cycle); + totalTimer.Stop(); + + state.SetIterationTime(totalTimer.GetElapsedTime()); + state.counters.insert( + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) } }); + } +} + +void BenchVolumeRenderingGenerator(::benchmark::internal::Benchmark* bm) +{ + bm->ArgNames({ "Cycle", "IsMultiBlock" }); + + std::vector isMultiBlocks{ false, /*true*/ }; + for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle) + { + for (auto& isMultiBlock : isMultiBlocks) + { + bm->Args({ cycle, isMultiBlock }); + } + } +} + +VTKM_BENCHMARK_APPLY(BenchVolumeRendering, BenchVolumeRenderingGenerator); + +struct Arg : vtkm::cont::internal::option::Arg +{ + static vtkm::cont::internal::option::ArgStatus Number( + const vtkm::cont::internal::option::Option& option, + bool msg) + { + bool argIsNum = ((option.arg != nullptr) && (option.arg[0] != '\0')); + const char* c = option.arg; + while (argIsNum && (*c != '\0')) + { + argIsNum &= static_cast(std::isdigit(*c)); + ++c; + } + + if (argIsNum) + { + return vtkm::cont::internal::option::ARG_OK; + } + else + { + if (msg) + { + std::cerr << "Option " << option.name << " requires a numeric argument." << std::endl; + } + + return vtkm::cont::internal::option::ARG_ILLEGAL; + } + } + + static vtkm::cont::internal::option::ArgStatus Required( + const vtkm::cont::internal::option::Option& option, + bool msg) + { + if ((option.arg != nullptr) && (option.arg[0] != '\0')) + { + return vtkm::cont::internal::option::ARG_OK; + } + else + { + if (msg) + { + std::cerr << "Option " << option.name << " requires an argument." << std::endl; + } + return vtkm::cont::internal::option::ARG_ILLEGAL; + } + } +}; + +enum OptionIndex +{ + UNKNOWN, + HELP, + DATASET_DIM, +}; + +void ParseBenchmarkOptions(int& argc, char** argv) +{ + namespace option = vtkm::cont::internal::option; + + std::vector usage; + std::string usageHeader{ "Usage: " }; + usageHeader.append(argv[0]); + usageHeader.append("[input data options] [benchmark options]"); + usage.push_back({ UNKNOWN, 0, "", "", Arg::None, usageHeader.c_str() }); + usage.push_back({ UNKNOWN, 0, "", "", Arg::None, "Input data options are:" }); + usage.push_back({ HELP, 0, "h", "help", Arg::None, " -h, --help\tDisplay this help." }); + usage.push_back({ UNKNOWN, 0, "", "", Arg::None, Config.Usage.c_str() }); + usage.push_back({ DATASET_DIM, + 0, + "s", + "size", + Arg::Number, + " -s, --size \tSpecify dataset dimension and " + "dataset with NxNxN dimensions and 0.1 spacing is created. " + "If not specified, N=128" }); + usage.push_back({ 0, 0, nullptr, nullptr, nullptr, nullptr }); + + option::Stats stats(usage.data(), argc - 1, argv + 1); + std::unique_ptr options{ new option::Option[stats.options_max] }; + std::unique_ptr buffer{ new option::Option[stats.buffer_max] }; + option::Parser commandLineParse(usage.data(), argc - 1, argv + 1, options.get(), buffer.get()); + + if (options[HELP]) + { + option::printUsage(std::cout, usage.data()); + // Print google benchmark usage too + const char* helpstr = "--help"; + char* tmpargv[] = { argv[0], const_cast(helpstr), nullptr }; + int tmpargc = 2; + VTKM_EXECUTE_BENCHMARKS(tmpargc, tmpargv); + exit(0); + } + if (options[DATASET_DIM]) + { + std::istringstream parse(options[DATASET_DIM].arg); + parse >> DataSetDim; + } + else + { + DataSetDim = 128; + } + + std::cerr << "Using data set dimensions(N) = " << DataSetDim << std::endl; + + // Now go back through the arg list and remove anything that is not in the list of + // unknown options or non-option arguments. + int destArg = 1; + // This is copy/pasted from vtkm::cont::Initialize(), should probably be abstracted eventually: + for (int srcArg = 1; srcArg < argc; ++srcArg) + { + std::string thisArg{ argv[srcArg] }; + bool copyArg = false; + + // Special case: "--" gets removed by optionparser but should be passed. + if (thisArg == "--") + { + copyArg = true; + } + for (const option::Option* opt = options[UNKNOWN]; !copyArg && opt != nullptr; + opt = opt->next()) + { + if (thisArg == opt->name) + { + copyArg = true; + } + if ((opt->arg != nullptr) && (thisArg == opt->arg)) + { + copyArg = true; + } + // Special case: optionparser sometimes removes a single "-" from an option + if (thisArg.substr(1) == opt->name) + { + copyArg = true; + } + } + for (int nonOpt = 0; !copyArg && nonOpt < commandLineParse.nonOptionsCount(); ++nonOpt) + { + if (thisArg == commandLineParse.nonOption(nonOpt)) + { + copyArg = true; + } + } + if (copyArg) + { + if (destArg != srcArg) + { + argv[destArg] = argv[srcArg]; + } + ++destArg; + } + } + argc = destArg; +} + +} // end anon namespace + +int main(int argc, char* argv[]) +{ + auto opts = vtkm::cont::InitializeOptions::RequireDevice; + + std::vector args(argv, argv + argc); + vtkm::bench::detail::InitializeArgs(&argc, args, opts); + + // Parse VTK-m options + Config = vtkm::cont::Initialize(argc, args.data(), opts); + ParseBenchmarkOptions(argc, args.data()); + + // This opts chances when it is help + if (opts != vtkm::cont::InitializeOptions::None) + { + vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device); + } + + VTKM_EXECUTE_BENCHMARKS(argc, args.data()); +} diff --git a/benchmarking/CMakeLists.txt b/benchmarking/CMakeLists.txt index 3b59cad74..2cf18da0c 100644 --- a/benchmarking/CMakeLists.txt +++ b/benchmarking/CMakeLists.txt @@ -71,4 +71,5 @@ endif() if(TARGET vtkm_rendering) add_benchmark(NAME BenchmarkRayTracing FILE BenchmarkRayTracing.cxx LIBS vtkm_rendering vtkm_source) + add_benchmark(NAME BenchmarkInSitu FILE BenchmarkInSitu.cxx LIBS vtkm_rendering vtkm_source vtkm_filter vtkm_io) endif() From d9487e01d44bd0dbde092fe5774719d51589c49f Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Wed, 30 Jun 2021 11:04:55 -0700 Subject: [PATCH 04/13] Add copyright notice --- benchmarking/BenchmarkInSitu.cxx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index 20d218f36..32f2766ca 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -1,3 +1,13 @@ +//========================================================================== +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// 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. +//========================================================================== + #include "Benchmarker.h" #include From 2c5180fee947b3eca6cb95fab6be08f5b21f2bf7 Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Fri, 6 Aug 2021 02:41:22 -0700 Subject: [PATCH 05/13] Write benchmark rendered images to disk --- benchmarking/BenchmarkInSitu.cxx | 108 ++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index 32f2766ca..ddef020d9 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -338,12 +338,9 @@ void BuildInputDataSet(uint32_t cycle, InputDataSet = inputDataSet; } -void RenderDataSets(const std::vector& dataSets, - RenderingMode mode, - std::string fieldName, - std::string bench, - bool isStructured, - uint32_t cycle) +vtkm::rendering::Canvas* RenderDataSets(const std::vector& dataSets, + RenderingMode mode, + std::string fieldName) { vtkm::rendering::Scene scene; vtkm::cont::ColorTable colorTable("inferno"); @@ -412,21 +409,27 @@ void RenderDataSets(const std::vector& dataSets, vtkm::rendering::Color(0.2f, 0.4f, 0.2f)); view.Paint(); - // TODO: Remove this later, once the various benchmark quirks are fixed - (void)cycle; - (void)isStructured; - (void)bench; - /* - std::ostringstream p; - p << "output_" - << "c" << cycle << "_" << (isStructured ? "structured" : "unstructured") << "_" - << (dataSets.size() == 1 ? "single_" : "multi_") << bench << "_" - << (mode == RenderingMode::Mesh ? "mesh" : (mode == RenderingMode::Volume ? "volume" : "ray")) - << ".png"; - view.SaveAs(p.str()); - */ + return view.GetCanvas().NewCopy(); } +void WriteToDisk(const vtkm::rendering::Canvas& canvas, + RenderingMode mode, + std::string bench, + bool isStructured, + bool isMultiBlock, + uint32_t cycle) +{ + std::ostringstream nameBuilder; + nameBuilder << "insitu_" << bench << "_" + << "cycle_" << cycle << "_" << (isStructured ? "structured_" : "unstructured_") + << (isMultiBlock ? "multi_" : "single_") + << (mode == RenderingMode::Mesh ? "mesh" + : (mode == RenderingMode::Volume ? "volume" : "ray")) + << ".png"; + canvas.SaveAs(nameBuilder.str()); +} + + template DataSetType RunContourHelper(vtkm::filter::Contour& filter, vtkm::Id numIsoVals, @@ -472,6 +475,7 @@ void BenchContour(::benchmark::State& state) vtkm::cont::Timer totalTimer{ device }; vtkm::cont::Timer filterTimer{ device }; vtkm::cont::Timer renderTimer{ device }; + vtkm::cont::Timer writeTimer{ device }; for (auto _ : state) { @@ -494,16 +498,21 @@ void BenchContour(::benchmark::State& state) filterTimer.Stop(); renderTimer.Start(); - RenderDataSets(dataSets, renderAlgo, PointScalarsName, "contour", isStructured, cycle); + auto canvas = RenderDataSets(dataSets, renderAlgo, PointScalarsName); renderTimer.Stop(); + writeTimer.Start(); + WriteToDisk(*canvas, renderAlgo, "contour", isStructured, isMultiBlock, cycle); + writeTimer.Stop(); + totalTimer.Stop(); state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, { "FilterTime", static_cast(filterTimer.GetElapsedTime() * 1000) }, - { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) } }); + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, + { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } } @@ -628,6 +637,7 @@ void BenchStreamlines(::benchmark::State& state) vtkm::cont::Timer totalTimer{ device }; vtkm::cont::Timer filterTimer{ device }; vtkm::cont::Timer renderTimer{ device }; + vtkm::cont::Timer writeTimer{ device }; for (auto _ : state) { @@ -651,16 +661,21 @@ void BenchStreamlines(::benchmark::State& state) filterTimer.Stop(); renderTimer.Start(); - RenderDataSets(dataSets, renderAlgo, "pointvar", "streamlines", isStructured, cycle); + auto canvas = RenderDataSets(dataSets, renderAlgo, "pointvar"); renderTimer.Stop(); + writeTimer.Start(); + WriteToDisk(*canvas, renderAlgo, "streamlines", isStructured, isMultiBlock, cycle); + writeTimer.Stop(); + totalTimer.Stop(); state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, { "FilterTime", static_cast(filterTimer.GetElapsedTime() * 1000) }, - { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) } }); + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, + { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } } @@ -739,6 +754,7 @@ void BenchSlice(::benchmark::State& state) vtkm::cont::Timer totalTimer{ device }; vtkm::cont::Timer filterTimer{ device }; vtkm::cont::Timer renderTimer{ device }; + vtkm::cont::Timer writeTimer{ device }; for (auto _ : state) { @@ -769,16 +785,21 @@ void BenchSlice(::benchmark::State& state) filterTimer.Stop(); renderTimer.Start(); - RenderDataSets(dataSets, renderAlgo, PointScalarsName, "slice", isStructured, cycle); + auto canvas = RenderDataSets(dataSets, renderAlgo, PointScalarsName); renderTimer.Stop(); + writeTimer.Start(); + WriteToDisk(*canvas, renderAlgo, "slice", isStructured, isMultiBlock, cycle); + writeTimer.Stop(); + totalTimer.Stop(); state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, { "FilterTime", static_cast(filterTimer.GetElapsedTime() * 1000) }, - { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) } }); + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, + { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } } @@ -815,6 +836,9 @@ void BenchMeshRendering(::benchmark::State& state) const bool isMultiBlock = static_cast(state.range(2)); vtkm::cont::Timer inputGenTimer{ device }; + vtkm::cont::Timer renderTimer{ device }; + vtkm::cont::Timer writeTimer{ device }; + inputGenTimer.Start(); BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); inputGenTimer.Stop(); @@ -826,14 +850,25 @@ void BenchMeshRendering(::benchmark::State& state) (void)_; totalTimer.Start(); + std::vector dataSets = isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet); - RenderDataSets(dataSets, RenderingMode::Mesh, PointScalarsName, "mesh", isStructured, cycle); + + renderTimer.Start(); + auto canvas = RenderDataSets(dataSets, RenderingMode::Mesh, PointScalarsName); + renderTimer.Stop(); + + writeTimer.Start(); + WriteToDisk(*canvas, RenderingMode::Mesh, "mesh", isStructured, isMultiBlock, cycle); + writeTimer.Stop(); + totalTimer.Stop(); state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( - { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) } }); + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, + { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } } @@ -871,22 +906,31 @@ void BenchVolumeRendering(::benchmark::State& state) inputGenTimer.Stop(); vtkm::cont::Timer totalTimer{ device }; + vtkm::cont::Timer renderTimer{ device }; + vtkm::cont::Timer writeTimer{ device }; for (auto _ : state) { (void)_; - vtkm::rendering::Scene scene; - totalTimer.Start(); + + renderTimer.Start(); std::vector dataSets = isMultiBlock ? ExtractDataSets(PartitionedInputDataSet) : ExtractDataSets(InputDataSet); - RenderDataSets( - dataSets, RenderingMode::Volume, PointScalarsName, "volume", isStructured, cycle); + auto canvas = RenderDataSets(dataSets, RenderingMode::Volume, PointScalarsName); + renderTimer.Stop(); + + writeTimer.Start(); + WriteToDisk(*canvas, RenderingMode::Volume, "volume", isStructured, isMultiBlock, cycle); + writeTimer.Stop(); + totalTimer.Stop(); state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( - { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) } }); + { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, + { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } } From 1ceb137751df3b5bb066f01487f5eac0c645896c Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Fri, 6 Aug 2021 02:56:38 -0700 Subject: [PATCH 06/13] Add commandline arg for rendered image size The image size defaults to `1024` if not specified. --- benchmarking/BenchmarkInSitu.cxx | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index ddef020d9..a5da90362 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -49,11 +49,14 @@ namespace const uint32_t DEFAULT_NUM_CYCLES = 20; const vtkm::Id DEFAULT_DATASET_DIM = 128; const vtkm::FloatDefault DEFAULT_SPACING = 0.1f; +const vtkm::Id DEFAULT_IMAGE_SIZE = 1024; // Hold configuration state (e.g. active device): vtkm::cont::InitializeResult Config; // Input dataset dimensions: -static vtkm::Id DataSetDim; +vtkm::Id DataSetDim; +// Image size: +vtkm::Id ImageSize; // The input datasets we'll use on the filters: static vtkm::cont::DataSet InputDataSet; static vtkm::cont::PartitionedDataSet PartitionedInputDataSet; @@ -376,7 +379,7 @@ vtkm::rendering::Canvas* RenderDataSets(const std::vector& camera.SetViewUp(vtkm::make_Vec(0.f, 1.f, 0.f)); camera.SetPosition(totalExtent * (mag * 1.5f)); - vtkm::rendering::CanvasRayTracer canvas(1920, 1080); + vtkm::rendering::CanvasRayTracer canvas(ImageSize, ImageSize); auto mapper = [=]() -> std::unique_ptr { switch (mode) @@ -1003,6 +1006,7 @@ enum OptionIndex UNKNOWN, HELP, DATASET_DIM, + IMAGE_SIZE, }; void ParseBenchmarkOptions(int& argc, char** argv) @@ -1025,6 +1029,14 @@ void ParseBenchmarkOptions(int& argc, char** argv) " -s, --size \tSpecify dataset dimension and " "dataset with NxNxN dimensions and 0.1 spacing is created. " "If not specified, N=128" }); + usage.push_back({ IMAGE_SIZE, + 0, + "i", + "image-size", + Arg::Number, + " -i, --image-size \tSpecify size of the rendered image." + " The image is rendered as a square of size NxN. " + "If not specified, N=1024" }); usage.push_back({ 0, 0, nullptr, nullptr, nullptr, nullptr }); option::Stats stats(usage.data(), argc - 1, argv + 1); @@ -1049,10 +1061,20 @@ void ParseBenchmarkOptions(int& argc, char** argv) } else { - DataSetDim = 128; + DataSetDim = DEFAULT_DATASET_DIM; + } + if (options[IMAGE_SIZE]) + { + std::istringstream parse(options[IMAGE_SIZE].arg); + parse >> ImageSize; + } + else + { + ImageSize = DEFAULT_IMAGE_SIZE; } - std::cerr << "Using data set dimensions(N) = " << DataSetDim << std::endl; + std::cerr << "Using data set dimensions = " << DataSetDim << std::endl; + std::cerr << "Using image size = " << ImageSize << "x" << ImageSize << std::endl; // Now go back through the arg list and remove anything that is not in the list of // unknown options or non-option arguments. From 2130ed59156315da1079c9e8c289873d1a77330e Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Fri, 6 Aug 2021 03:01:41 -0700 Subject: [PATCH 07/13] Refactor some static globals --- benchmarking/BenchmarkInSitu.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index a5da90362..5287a6c7b 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -58,12 +58,12 @@ vtkm::Id DataSetDim; // Image size: vtkm::Id ImageSize; // The input datasets we'll use on the filters: -static vtkm::cont::DataSet InputDataSet; -static vtkm::cont::PartitionedDataSet PartitionedInputDataSet; +vtkm::cont::DataSet InputDataSet; +vtkm::cont::PartitionedDataSet PartitionedInputDataSet; // The point scalars to use: -static std::string PointScalarsName; +std::string PointScalarsName; // The point vectors to use: -static std::string PointVectorsName; +std::string PointVectorsName; enum class RenderingMode { From a2c3c80ce0e8d763cdcd5132e5a3009d615d6292 Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Fri, 6 Aug 2021 11:59:59 -0700 Subject: [PATCH 08/13] Make perlin generation as a `vtkm::source::Source` source Making it a `vtkm::source::Source` makes it easier to use in other benchmarks or tests. --- benchmarking/BenchmarkInSitu.cxx | 220 ++++--------------------------- vtkm/source/CMakeLists.txt | 2 + vtkm/source/PerlinNoise.cxx | 209 +++++++++++++++++++++++++++++ vtkm/source/PerlinNoise.h | 61 +++++++++ 4 files changed, 295 insertions(+), 197 deletions(-) create mode 100644 vtkm/source/PerlinNoise.cxx create mode 100644 vtkm/source/PerlinNoise.h diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index 5287a6c7b..a35ed1e14 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -28,7 +27,6 @@ #include #include -#include #include #include #include @@ -43,6 +41,7 @@ #include #include +#include namespace { @@ -73,163 +72,6 @@ enum class RenderingMode Volume = 3, }; -struct PerlinNoise3DWorklet : public vtkm::worklet::WorkletVisitPointsWithCells -{ - using ControlSignature = void(CellSetIn, FieldInPoint, WholeArrayIn, FieldOut noise); - using ExecutionSignature = void(_2, _3, _4); - - VTKM_CONT PerlinNoise3DWorklet(vtkm::Id repeat) - : Repeat(repeat) - { - } - - // Adapted from https://adrianb.io/2014/08/09/perlinnoise.html - // Archive link: https://web.archive.org/web/20210329174559/https://adrianb.io/2014/08/09/perlinnoise.html - template - VTKM_EXEC void operator()(const PointVecType& pos, const PermsPortal& perms, OutType& noise) const - { - vtkm::Id xi = static_cast(pos[0]) % this->Repeat; - vtkm::Id yi = static_cast(pos[1]) % this->Repeat; - vtkm::Id zi = static_cast(pos[2]) % this->Repeat; - vtkm::FloatDefault xf = pos[0] - xi; - vtkm::FloatDefault yf = pos[1] - yi; - vtkm::FloatDefault zf = pos[2] - zi; - vtkm::FloatDefault u = this->Fade(xf); - vtkm::FloatDefault v = this->Fade(yf); - vtkm::FloatDefault w = this->Fade(zf); - - vtkm::Id aaa, aba, aab, abb, baa, bba, bab, bbb; - aaa = perms[perms[perms[xi] + yi] + zi]; - aba = perms[perms[perms[xi] + this->Increment(yi)] + zi]; - aab = perms[perms[perms[xi] + yi] + this->Increment(zi)]; - abb = perms[perms[perms[xi] + this->Increment(yi)] + this->Increment(zi)]; - baa = perms[perms[perms[this->Increment(xi)] + yi] + zi]; - bba = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + zi]; - bab = perms[perms[perms[this->Increment(xi)] + yi] + this->Increment(zi)]; - bbb = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + this->Increment(zi)]; - - vtkm::FloatDefault x1, x2, y1, y2; - x1 = vtkm::Lerp(this->Gradient(aaa, xf, yf, zf), this->Gradient(baa, xf - 1, yf, zf), u); - x2 = - vtkm::Lerp(this->Gradient(aba, xf, yf - 1, zf), this->Gradient(bba, xf - 1, yf - 1, zf), u); - y1 = vtkm::Lerp(x1, x2, v); - - x1 = - vtkm::Lerp(this->Gradient(aab, xf, yf, zf - 1), this->Gradient(bab, xf - 1, yf, zf - 1), u); - x2 = vtkm::Lerp( - this->Gradient(abb, xf, yf - 1, zf - 1), this->Gradient(bbb, xf - 1, yf - 1, zf - 1), u); - y2 = vtkm::Lerp(x1, x2, v); - - noise = (vtkm::Lerp(y1, y2, w) + OutType(1.0f)) * OutType(0.5f); - } - - VTKM_EXEC vtkm::FloatDefault Fade(vtkm::FloatDefault t) const - { - return t * t * t * (t * (t * 6 - 15) + 10); - } - - VTKM_EXEC vtkm::Id Increment(vtkm::Id n) const { return (n + 1) % this->Repeat; } - - VTKM_EXEC vtkm::FloatDefault Gradient(vtkm::Id hash, - vtkm::FloatDefault x, - vtkm::FloatDefault y, - vtkm::FloatDefault z) const - { - switch (hash & 0xF) - { - case 0x0: - return x + y; - case 0x1: - return -x + y; - case 0x2: - return x - y; - case 0x3: - return -x - y; - case 0x4: - return x + z; - case 0x5: - return -x + z; - case 0x6: - return x - z; - case 0x7: - return -x - z; - case 0x8: - return y + z; - case 0x9: - return -y + z; - case 0xA: - return y - z; - case 0xB: - return -y - z; - case 0xC: - return y + x; - case 0xD: - return -y + z; - case 0xE: - return y - x; - case 0xF: - return -y - z; - default: - return 0; // never happens - } - } - - vtkm::Id Repeat; -}; - -class PerlinNoise3DGenerator : public vtkm::filter::FilterField -{ -public: - VTKM_CONT PerlinNoise3DGenerator(vtkm::IdComponent tableSize, vtkm::Id seed) - : TableSize(tableSize) - , Seed(seed) - { - this->GeneratePermutations(); - this->SetUseCoordinateSystemAsField(true); - } - - template - VTKM_CONT vtkm::cont::DataSet DoExecute(const vtkm::cont::DataSet& input, - const FieldType&, - const vtkm::filter::FieldMetadata& fieldMetadata, - vtkm::filter::PolicyBase) - { - vtkm::cont::ArrayHandle noiseArray; - PerlinNoise3DWorklet worklet{ this->TableSize }; - this->Invoke(worklet, input.GetCellSet(), input.GetCoordinateSystem(), this->P, noiseArray); - - return vtkm::filter::CreateResult(input, noiseArray, "PerlinNoise3D", fieldMetadata); - } - -protected: - VTKM_CONT void GeneratePermutations() - { - std::mt19937_64 rng; - rng.seed(this->Seed); - std::uniform_int_distribution distribution(0, this->TableSize - 1); - - vtkm::cont::ArrayHandle perms; - perms.Allocate(this->TableSize); - auto permsPortal = perms.WritePortal(); - for (auto i = 0; i < permsPortal.GetNumberOfValues(); ++i) - { - permsPortal.Set(i, distribution(rng)); - } - this->P.Allocate(2 * this->TableSize); - auto pPortal = this->P.WritePortal(); - for (auto i = 0; i < pPortal.GetNumberOfValues(); ++i) - { - pPortal.Set(i, permsPortal.Get(i % this->TableSize)); - } - } - - -private: - vtkm::IdComponent TableSize; - vtkm::Id Seed; - vtkm::cont::ArrayHandle P; -}; - std::vector ExtractDataSets(const vtkm::cont::PartitionedDataSet& partitions) { return partitions.GetPartitions(); @@ -241,21 +83,16 @@ std::vector ExtractDataSets(vtkm::cont::DataSet& dataSet) return std::vector{ dataSet }; } -void BuildInputDataSet(uint32_t cycle, - bool isStructured, - bool isMultiBlock, - vtkm::Id dims, - vtkm::FloatDefault spacing = 0.1f) +void BuildInputDataSet(uint32_t cycle, bool isStructured, bool isMultiBlock, vtkm::Id dim) { vtkm::cont::PartitionedDataSet partitionedInputDataSet; vtkm::cont::DataSet inputDataSet; - PointScalarsName = "PerlinNoise3D"; - PointVectorsName = "PerlinNoise3DGradient"; + PointScalarsName = "perlinnoise"; + PointVectorsName = "perlinnoisegrad"; // Generate uniform dataset(s) - const vtkm::Id3 dataSetDims{ dims, dims, dims }; - const vtkm::Vec3f dataSetSpacing{ spacing, spacing, spacing }; + const vtkm::Id3 dims{ dim, dim, dim }; if (isMultiBlock) { for (auto i = 0; i < 2; ++i) @@ -264,33 +101,22 @@ void BuildInputDataSet(uint32_t cycle, { for (auto k = 0; k < 2; ++k) { - const vtkm::Vec3f dataSetOrigin{ (dims - 1) * spacing * i, - (dims - 1) * spacing * j, - (dims - 1) * spacing * k }; - vtkm::cont::DataSetBuilderUniform dataSetBuilder; - vtkm::cont::DataSet uniformDataSet = - dataSetBuilder.Create(dataSetDims, dataSetOrigin, dataSetSpacing); - partitionedInputDataSet.AppendPartition(uniformDataSet); + const vtkm::Vec3f origin{ static_cast(i), + static_cast(j), + static_cast(k) }; + const vtkm::source::PerlinNoise noise{ dims, + origin, + static_cast(cycle) }; + const auto dataset = noise.Execute(); + partitionedInputDataSet.AppendPartition(dataset); } } } } else { - const vtkm::Vec3f dataSetOrigin{ 0.0f, 0.0f, 0.0f }; - vtkm::cont::DataSetBuilderUniform dataSetBuilder; - inputDataSet = dataSetBuilder.Create(dataSetDims, dataSetOrigin, dataSetSpacing); - } - - // Generate Perlin Noise point scalar field - PerlinNoise3DGenerator fieldGenerator(dims, cycle); - if (isMultiBlock) - { - partitionedInputDataSet = fieldGenerator.Execute(partitionedInputDataSet); - } - else - { - inputDataSet = fieldGenerator.Execute(inputDataSet); + const vtkm::source::PerlinNoise noise{ dims, static_cast(cycle) }; + inputDataSet = noise.Execute(); } // Generate Perln Noise Gradient point vector field @@ -465,7 +291,7 @@ void BenchContour(::benchmark::State& state) vtkm::cont::Timer inputGenTimer{ device }; inputGenTimer.Start(); - BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim); inputGenTimer.Stop(); vtkm::filter::Contour filter; @@ -629,7 +455,7 @@ void BenchStreamlines(::benchmark::State& state) vtkm::cont::Timer inputGenTimer{ device }; inputGenTimer.Start(); - BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim); inputGenTimer.Stop(); vtkm::filter::Streamline streamline; @@ -749,7 +575,7 @@ void BenchSlice(::benchmark::State& state) vtkm::cont::Timer inputGenTimer{ device }; inputGenTimer.Start(); - BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim); inputGenTimer.Stop(); vtkm::filter::Slice filter; @@ -843,7 +669,7 @@ void BenchMeshRendering(::benchmark::State& state) vtkm::cont::Timer writeTimer{ device }; inputGenTimer.Start(); - BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim); inputGenTimer.Stop(); vtkm::cont::Timer totalTimer{ device }; @@ -905,7 +731,7 @@ void BenchVolumeRendering(::benchmark::State& state) vtkm::cont::Timer inputGenTimer{ device }; inputGenTimer.Start(); - BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim, DEFAULT_SPACING); + BuildInputDataSet(cycle, isStructured, isMultiBlock, DataSetDim); inputGenTimer.Stop(); vtkm::cont::Timer totalTimer{ device }; @@ -941,7 +767,7 @@ void BenchVolumeRenderingGenerator(::benchmark::internal::Benchmark* bm) { bm->ArgNames({ "Cycle", "IsMultiBlock" }); - std::vector isMultiBlocks{ false, /*true*/ }; + std::vector isMultiBlocks{ false }; for (uint32_t cycle = 1; cycle <= DEFAULT_NUM_CYCLES; ++cycle) { for (auto& isMultiBlock : isMultiBlocks) @@ -1027,7 +853,7 @@ void ParseBenchmarkOptions(int& argc, char** argv) "size", Arg::Number, " -s, --size \tSpecify dataset dimension and " - "dataset with NxNxN dimensions and 0.1 spacing is created. " + "dataset with NxNxN dimensions is created. " "If not specified, N=128" }); usage.push_back({ IMAGE_SIZE, 0, @@ -1146,4 +972,4 @@ int main(int argc, char* argv[]) } VTKM_EXECUTE_BENCHMARKS(argc, args.data()); -} +} \ No newline at end of file diff --git a/vtkm/source/CMakeLists.txt b/vtkm/source/CMakeLists.txt index 88c576b2c..03de54190 100644 --- a/vtkm/source/CMakeLists.txt +++ b/vtkm/source/CMakeLists.txt @@ -13,6 +13,7 @@ set(headers Source.h Tangle.h Wavelet.h + PerlinNoise.h ) set(device_sources @@ -20,6 +21,7 @@ set(device_sources Source.cxx Tangle.cxx Wavelet.cxx + PerlinNoise.cxx ) vtkm_library(NAME vtkm_source diff --git a/vtkm/source/PerlinNoise.cxx b/vtkm/source/PerlinNoise.cxx new file mode 100644 index 000000000..03847536b --- /dev/null +++ b/vtkm/source/PerlinNoise.cxx @@ -0,0 +1,209 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// 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. +//============================================================================ + +#include + +#include +#include +#include +#include + +namespace vtkm +{ +namespace source +{ +namespace perlin +{ +struct PerlinNoiseWorklet : public vtkm::worklet::WorkletVisitPointsWithCells +{ + using ControlSignature = void(CellSetIn, FieldInPoint, WholeArrayIn, FieldOut noise); + using ExecutionSignature = void(_2, _3, _4); + + VTKM_CONT PerlinNoiseWorklet(vtkm::Id repeat) + : Repeat(repeat) + { + } + + // Adapted from https://adrianb.io/2014/08/09/perlinnoise.html + // Archive link: https://web.archive.org/web/20210329174559/https://adrianb.io/2014/08/09/perlinnoise.html + template + VTKM_EXEC void operator()(const PointVecType& pos, const PermsPortal& perms, OutType& noise) const + { + vtkm::Id xi = static_cast(pos[0]) % this->Repeat; + vtkm::Id yi = static_cast(pos[1]) % this->Repeat; + vtkm::Id zi = static_cast(pos[2]) % this->Repeat; + vtkm::FloatDefault xf = pos[0] - xi; + vtkm::FloatDefault yf = pos[1] - yi; + vtkm::FloatDefault zf = pos[2] - zi; + vtkm::FloatDefault u = this->Fade(xf); + vtkm::FloatDefault v = this->Fade(yf); + vtkm::FloatDefault w = this->Fade(zf); + + vtkm::Id aaa, aba, aab, abb, baa, bba, bab, bbb; + aaa = perms[perms[perms[xi] + yi] + zi]; + aba = perms[perms[perms[xi] + this->Increment(yi)] + zi]; + aab = perms[perms[perms[xi] + yi] + this->Increment(zi)]; + abb = perms[perms[perms[xi] + this->Increment(yi)] + this->Increment(zi)]; + baa = perms[perms[perms[this->Increment(xi)] + yi] + zi]; + bba = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + zi]; + bab = perms[perms[perms[this->Increment(xi)] + yi] + this->Increment(zi)]; + bbb = perms[perms[perms[this->Increment(xi)] + this->Increment(yi)] + this->Increment(zi)]; + + vtkm::FloatDefault x1, x2, y1, y2; + x1 = vtkm::Lerp(this->Gradient(aaa, xf, yf, zf), this->Gradient(baa, xf - 1, yf, zf), u); + x2 = + vtkm::Lerp(this->Gradient(aba, xf, yf - 1, zf), this->Gradient(bba, xf - 1, yf - 1, zf), u); + y1 = vtkm::Lerp(x1, x2, v); + + x1 = + vtkm::Lerp(this->Gradient(aab, xf, yf, zf - 1), this->Gradient(bab, xf - 1, yf, zf - 1), u); + x2 = vtkm::Lerp( + this->Gradient(abb, xf, yf - 1, zf - 1), this->Gradient(bbb, xf - 1, yf - 1, zf - 1), u); + y2 = vtkm::Lerp(x1, x2, v); + + noise = (vtkm::Lerp(y1, y2, w) + OutType(1.0f)) * OutType(0.5f); + } + + VTKM_EXEC vtkm::FloatDefault Fade(vtkm::FloatDefault t) const + { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + VTKM_EXEC vtkm::Id Increment(vtkm::Id n) const { return (n + 1) % this->Repeat; } + + VTKM_EXEC vtkm::FloatDefault Gradient(vtkm::Id hash, + vtkm::FloatDefault x, + vtkm::FloatDefault y, + vtkm::FloatDefault z) const + { + switch (hash & 0xF) + { + case 0x0: + return x + y; + case 0x1: + return -x + y; + case 0x2: + return x - y; + case 0x3: + return -x - y; + case 0x4: + return x + z; + case 0x5: + return -x + z; + case 0x6: + return x - z; + case 0x7: + return -x - z; + case 0x8: + return y + z; + case 0x9: + return -y + z; + case 0xA: + return y - z; + case 0xB: + return -y - z; + case 0xC: + return y + x; + case 0xD: + return -y + z; + case 0xE: + return y - x; + case 0xF: + return -y - z; + default: + return 0; // never happens + } + } + + vtkm::Id Repeat; +}; + +class PerlinNoiseField : public vtkm::filter::FilterField +{ +public: + VTKM_CONT PerlinNoiseField(vtkm::IdComponent tableSize, vtkm::Id seed) + : TableSize(tableSize) + , Seed(seed) + { + this->GeneratePermutations(); + this->SetUseCoordinateSystemAsField(true); + } + + template + VTKM_CONT vtkm::cont::DataSet DoExecute( + const vtkm::cont::DataSet& input, + const FieldType& vtkmNotUsed(field), + const vtkm::filter::FieldMetadata& fieldMetadata, + vtkm::filter::PolicyBase vtkmNotUsed(policy)) + { + vtkm::cont::ArrayHandle noise; + PerlinNoiseWorklet worklet{ this->TableSize }; + this->Invoke( + worklet, input.GetCellSet(), input.GetCoordinateSystem(), this->Permutations, noise); + + return vtkm::filter::CreateResult(input, noise, this->GetOutputFieldName(), fieldMetadata); + } + +private: + VTKM_CONT void GeneratePermutations() + { + std::mt19937_64 rng; + rng.seed(this->Seed); + std::uniform_int_distribution distribution(0, this->TableSize - 1); + + vtkm::cont::ArrayHandle perms; + perms.Allocate(this->TableSize); + auto permsPortal = perms.WritePortal(); + for (auto i = 0; i < permsPortal.GetNumberOfValues(); ++i) + { + permsPortal.Set(i, distribution(rng)); + } + this->Permutations.Allocate(2 * this->TableSize); + auto permutations = this->Permutations.WritePortal(); + for (auto i = 0; i < permutations.GetNumberOfValues(); ++i) + { + permutations.Set(i, permsPortal.Get(i % this->TableSize)); + } + } + + vtkm::IdComponent TableSize; + vtkm::Id Seed; + vtkm::cont::ArrayHandle Permutations; +}; +} // namespace perlin + +vtkm::cont::DataSet PerlinNoise::Execute() const +{ + VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf); + + vtkm::cont::DataSet dataSet; + const vtkm::Id3 pdims{ this->Dims + vtkm::Id3{ 1, 1, 1 } }; + const vtkm::Vec3f spacing(1.0f / static_cast(this->Dims[0]), + 1.0f / static_cast(this->Dims[1]), + 1.0f / static_cast(this->Dims[2])); + + + vtkm::cont::CellSetStructured<3> cellSet; + cellSet.SetPointDimensions(pdims); + dataSet.SetCellSet(cellSet); + vtkm::cont::ArrayHandleUniformPointCoordinates coordinates(pdims, this->Origin, spacing); + dataSet.AddCoordinateSystem(vtkm::cont::CoordinateSystem("coordinates", coordinates)); + + auto tableSize = static_cast( + vtkm::Max(this->Dims[0], vtkm::Max(this->Dims[1], this->Dims[2]))); + perlin::PerlinNoiseField noiseGenerator(tableSize, this->Seed); + noiseGenerator.SetOutputFieldName("perlinnoise"); + dataSet = noiseGenerator.Execute(dataSet); + + return dataSet; +} + +} // namespace source +} // namespace vtkm diff --git a/vtkm/source/PerlinNoise.h b/vtkm/source/PerlinNoise.h new file mode 100644 index 000000000..5a53dd046 --- /dev/null +++ b/vtkm/source/PerlinNoise.h @@ -0,0 +1,61 @@ +//============================================================================ +// Copyright (c) Kitware, Inc. +// All rights reserved. +// See LICENSE.txt for details. +// +// 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. +//============================================================================ + +#ifndef vtk_m_source_PerlinNoise_h +#define vtk_m_source_PerlinNoise_h + +#include + +namespace vtkm +{ +namespace source +{ +/** + * @brief The PerlinNoise source creates a uniform dataset. + * + * This class generates a uniform grid dataset with a tileable perlin + * noise scalar point field. + * + * The Execute method creates a complete structured dataset that have a + * scalar point field named 'perlinnoise'. +**/ +class VTKM_SOURCE_EXPORT PerlinNoise final : public vtkm::source::Source +{ +public: + ///Construct a PerlinNoise with Cell Dimensions + VTKM_CONT + PerlinNoise(vtkm::Id3 dims, vtkm::IdComponent seed) + : PerlinNoise(dims, vtkm::Vec3f(0), seed) + { + } + + VTKM_CONT + PerlinNoise(vtkm::Id3 dims, vtkm::Vec3f origin, vtkm::IdComponent seed) + : Dims(dims) + , Origin(origin) + , Seed(seed) + { + } + + vtkm::IdComponent GetSeed() const { return this->Seed; } + + void SetSeed(vtkm::IdComponent seed) { this->Seed = seed; } + + vtkm::cont::DataSet Execute() const override; + +private: + vtkm::Id3 Dims; + vtkm::Vec3f Origin; + vtkm::IdComponent Seed; +}; +} //namespace source +} //namespace vtkm + +#endif //vtk_m_source_Tangle_h From 48a820df07b9b665065e30af1abb01cf0145518e Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Fri, 6 Aug 2021 12:24:12 -0700 Subject: [PATCH 09/13] Align mesh and volume rendering benchmarks timings --- benchmarking/BenchmarkInSitu.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index a35ed1e14..de64300cb 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -696,6 +696,7 @@ void BenchMeshRendering(::benchmark::State& state) state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "FilterTime", 0 }, { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } @@ -758,6 +759,7 @@ void BenchVolumeRendering(::benchmark::State& state) state.SetIterationTime(totalTimer.GetElapsedTime()); state.counters.insert( { { "InputGenTime", static_cast(inputGenTimer.GetElapsedTime() * 1000) }, + { "FilterTime", 0 }, { "RenderTime", static_cast(renderTimer.GetElapsedTime() * 1000) }, { "WriteTime", static_cast(writeTimer.GetElapsedTime() * 1000) } }); } From a571f50dfcb29c911b21a81d4f09860b090a60f5 Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Fri, 6 Aug 2021 23:22:28 -0700 Subject: [PATCH 10/13] Cleanup unused code --- benchmarking/BenchmarkInSitu.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index de64300cb..4f0d70629 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -42,12 +42,12 @@ #include #include + namespace { const uint32_t DEFAULT_NUM_CYCLES = 20; const vtkm::Id DEFAULT_DATASET_DIM = 128; -const vtkm::FloatDefault DEFAULT_SPACING = 0.1f; const vtkm::Id DEFAULT_IMAGE_SIZE = 1024; // Hold configuration state (e.g. active device): From 5482bc55180638d5dd5f62079d6bf604f76c3ce1 Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Sat, 7 Aug 2021 05:04:50 -0700 Subject: [PATCH 11/13] Fix formatting --- benchmarking/BenchmarkInSitu.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index 4f0d70629..cd7d1fa30 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -974,4 +974,4 @@ int main(int argc, char* argv[]) } VTKM_EXECUTE_BENCHMARKS(argc, args.data()); -} \ No newline at end of file +} From 2ab1594ad1cf1b271cca15162e3c6826e0bcf84b Mon Sep 17 00:00:00 2001 From: Manish Mathai Date: Sun, 15 Aug 2021 01:37:04 -0400 Subject: [PATCH 12/13] Fix typo --- benchmarking/BenchmarkInSitu.cxx | 21 +-------------------- vtkm/source/PerlinNoise.h | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/benchmarking/BenchmarkInSitu.cxx b/benchmarking/BenchmarkInSitu.cxx index cd7d1fa30..b198de949 100644 --- a/benchmarking/BenchmarkInSitu.cxx +++ b/benchmarking/BenchmarkInSitu.cxx @@ -15,7 +15,6 @@ #include -#include #include #include #include @@ -267,7 +266,7 @@ DataSetType RunContourHelper(vtkm::filter::Contour& filter, // Set up some equally spaced contours, with the min/max slightly inside the // scalar range: const vtkm::Range scalarRange = - vtkm::cont::ArrayGetValue(0, vtkm::cont::FieldRangeCompute(input, PointScalarsName)); + vtkm::cont::FieldRangeCompute(input, PointScalarsName).ReadPortal().Get(0); const auto step = scalarRange.Length() / static_cast(numIsoVals + 1); const auto minIsoVal = scalarRange.Min + (step * 0.5f); filter.SetNumberOfIsoValues(numIsoVals); @@ -809,24 +808,6 @@ struct Arg : vtkm::cont::internal::option::Arg return vtkm::cont::internal::option::ARG_ILLEGAL; } } - - static vtkm::cont::internal::option::ArgStatus Required( - const vtkm::cont::internal::option::Option& option, - bool msg) - { - if ((option.arg != nullptr) && (option.arg[0] != '\0')) - { - return vtkm::cont::internal::option::ARG_OK; - } - else - { - if (msg) - { - std::cerr << "Option " << option.name << " requires an argument." << std::endl; - } - return vtkm::cont::internal::option::ARG_ILLEGAL; - } - } }; enum OptionIndex diff --git a/vtkm/source/PerlinNoise.h b/vtkm/source/PerlinNoise.h index 5a53dd046..3f54503a9 100644 --- a/vtkm/source/PerlinNoise.h +++ b/vtkm/source/PerlinNoise.h @@ -58,4 +58,4 @@ private: } //namespace source } //namespace vtkm -#endif //vtk_m_source_Tangle_h +#endif //vtk_m_source_PerlinNoise_h From d5143ad7ed2e55025cec2f49fb3f0ab46045a8e2 Mon Sep 17 00:00:00 2001 From: Vicente Adolfo Bolea Sanchez Date: Tue, 7 Dec 2021 18:47:49 -0500 Subject: [PATCH 13/13] 1.7.0 is our 10th official release of VTK-m. The major changes to VTK-m from (previous release) can be found in: docs/changelog/1.7/release-notes.md --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 57dfe270d..bd8bf882d 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.7.0-rc1 +1.7.0