From 25fb8564e53c33ddbc3392448e08afdfdb14c390 Mon Sep 17 00:00:00 2001 From: vmadanan Date: Wed, 8 Jul 2020 12:42:37 -0700 Subject: [PATCH 1/2] Adding mandelbrot sample to the repository Signed-off-by: vmadanan --- .../mandelbrot/CMakeLists.txt | 13 + .../CombinationalLogic/mandelbrot/License.txt | 8 + .../CombinationalLogic/mandelbrot/README.md | 96 ++++++ .../mandelbrot/mandelbrot.sln | 25 ++ .../mandelbrot/mandelbrot.vcxproj | 161 ++++++++++ .../mandelbrot/mandelbrot.vcxproj.filters | 36 +++ .../mandelbrot/mandelbrot.vcxproj.user | 10 + .../CombinationalLogic/mandelbrot/sample.json | 30 ++ .../mandelbrot/src/CMakeLists.txt | 11 + .../mandelbrot/src/main.cpp | 91 ++++++ .../mandelbrot/src/mandel.hpp | 286 ++++++++++++++++++ 11 files changed, 767 insertions(+) create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/CMakeLists.txt create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.sln create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.user create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/sample.json create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/main.cpp create mode 100644 DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/CMakeLists.txt b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/CMakeLists.txt new file mode 100644 index 0000000000..d92953a3a1 --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required (VERSION 3.0) + +set(CMAKE_CXX_COMPILER dpcpp) + +# Set default build type to RelWithDebInfo if not specified +if (NOT CMAKE_BUILD_TYPE) + message (STATUS "Default CMAKE_BUILD_TYPE not set using Release with Debug Info") + set (CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE + STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel" + FORCE) +endif() +project (mandelbrot) +add_subdirectory (src) diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt new file mode 100644 index 0000000000..8f608e972a --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt @@ -0,0 +1,8 @@ +Copyright 2019 Intel Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md new file mode 100644 index 0000000000..1026556c03 --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md @@ -0,0 +1,96 @@ +# `Mandelbrot` Sample + +Mandelbrot is an infinitely complex fractal patterning that is derived from a simple formula. It demonstrates using DPC++ for offloading computations to a GPU (or other devices) and shows how processing time can be optimized and improved with parallelism. + +For comprehensive instructions regarding DPC++ Programming, go to https://software.intel.com/en-us/oneapi-programming-guide and search based on relevant terms noted in the comments. + +| Optimized for | Description +|:--- |:--- +| OS | Linux* Ubuntu* 18.04; Windows 10 +| Hardware | Skylake with GEN9 or newer +| Software | Intel® oneAPI DPC++ Compiler beta; +| What you will learn | How to offload the computation to GPU using Intel DPC++ compiler +| Time to complete | 15 minutes + +## Purpose +Mandelbrot is a DPC++ application that generates a fractal image by initializing a matrix of 512 x 512, where the computation at each point (pixel) is entirely independent of the computation at other points. The sample includes both parallel and serial calculation of the set, allowing for a direct comparison of results. The parallel implementation can demonstrate the use of Unified Shared Memory (USM) or buffers. You can modify parameters such as the number of rows, columns, and iterations to evaluate the difference in performance and load between USM and buffers. This is further described at the end of this document in the "Running the Sample" section. + +The code will attempt first to execute on an available GPU and fallback to the system's CPU if a compatible GPU is not detected. The device used for compilation is displayed in the output along with elapsed time to render the mandelbrot image. This is helpful for comparing different offload implementations based on complexity of the computation. + +## Key Implementation Details +The basic DPC++ implementation explained in the code includes device selector, buffer, accessor, kernel, and command groups. + +## License +This code sample is licensed under MIT license. + +## Building the `Mandelbrot` Program for CPU and GPU + +### Running Samples In DevCloud +If running a sample in the Intel DevCloud, remember that you must specify the compute node (CPU, GPU, FPGA) as well whether to run in batch or interactive mode. For more information see the Intel® oneAPI Base Toolkit Get Started Guide (https://devcloud.intel.com/oneapi/get-started/base-toolkit/) + +### On a Linux* System +Perform the following steps: +1. Build the program using the following `cmake` commands. +``` +$ mkdir build +$ cd build +$ cmake .. +$ make +``` + +> Note: by default, exectables are created for both USM and buffers. You can build individually with the following: +> Create buffers executable: make mandelbrot +> Create USM executable: make mandelbrot_usm + +2. Run the program (default uses buffers): + ``` + make run + ``` +> Note: for USM use `make run_usm` + +3. Clean the program using: + ``` + make clean + ``` + +### On a Windows* System Using Visual Studio* Version 2017 or Newer +* Build the program using VS2017 or VS2019 + Right click on the solution file and open using either VS2017 or VS2019 IDE. + Right click on the project in Solution explorer and select Rebuild. + From top menu select Debug -> Start without Debugging. + +>If you see the following error message when compiling this sample: +> +``` +Error 'dpc_common.hpp' file not found +``` +>You need to add the following directory to the list of include folders, that are required by your project, in your project's Visual Studio project property panel. The missing include folder is located at `%ONEAPI_ROOT%\dev-utilities\latest\include` on your development system. + +* Build the program using MSBuild + Open "x64 Native Tools Command Prompt for VS2017" or "x64 Native Tools Command Prompt for VS2019" + Run - MSBuild mandelbrot.sln /t:Rebuild /p:Configuration="Release" + + +## Running the Sample +### Application Parameters +You can modify the Mandelbrot parameters from within mandel.hpp. The configurable parameters include: + row_size = + col_size = + max_iterations = + repetitions = +The default row and column size is 512. Max interatins and repetions are both 100. By adjusting the parameters, you can observe how the performance varies using the different offload techniques. Note that if the values drop below 128 for row and column, the output is limted to just text in the ouput window. + +### Example of Output +``` +Platform Name: Intel(R) OpenCL HD Graphics + Platform Version: OpenCL 2.1 + Device Name: Intel(R) Gen9 HD Graphics NEO + Max Work Group: 256 + Max Compute Units: 24 + +Parallel Mandelbrot set using buffers. +Rendered image output to file: mandelbrot.png (output too large to display in text) + Serial time: 0.0430331s + Parallel time: 0.00224131s +Successfully computed Mandelbrot set. +``` \ No newline at end of file diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.sln b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.sln new file mode 100644 index 0000000000..2b8298d2f0 --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.852 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mandelbrot", "mandelbrot.vcxproj", "{C2DF6F42-60A8-4FFD-AE40-F37E9EF9875E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C2DF6F42-60A8-4FFD-AE40-F37E9EF9875E}.Debug|x64.ActiveCfg = Debug|x64 + {C2DF6F42-60A8-4FFD-AE40-F37E9EF9875E}.Debug|x64.Build.0 = Debug|x64 + {C2DF6F42-60A8-4FFD-AE40-F37E9EF9875E}.Release|x64.ActiveCfg = Release|x64 + {C2DF6F42-60A8-4FFD-AE40-F37E9EF9875E}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {075ECF2A-BDB7-4151-826F-CAC1B35A18F2} + EndGlobalSection +EndGlobal diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj new file mode 100644 index 0000000000..50c7200cd7 --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj @@ -0,0 +1,161 @@ + + + + + Debug + x64 + + + Release + x64 + + + + + + + + + + + + + + + + + 15.0 + {c2df6f42-60a8-4ffd-ae40-f37e9ef9875e} + Win32Proj + mandelbrot + $(WindowsSDKVersion.Replace("\","")) + + + + Application + true + oneAPI Data Parallel C++ Compiler + Unicode + + + Application + false + oneAPI Data Parallel C++ Compiler + true + Unicode + + + Application + true + Intel(R) oneAPI DPC++ Compiler + Unicode + + + Application + false + Intel(R) oneAPI DPC++ Compiler + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + true + true + pch.h + + + Console + true + + + + + Use + Level3 + Disabled + true + true + pch.h + Level3 + + + Console + true + $(ONEAPI_ROOT)\compiler\latest\windows\bin\libsycl-complex.o + + + + + Use + Level3 + MaxSpeed + true + true + true + true + pch.h + + + Console + true + true + true + + + + + Use + Level3 + MaxSpeed + true + true + true + true + pch.h + Level3 + + + Console + true + true + true + $(ONEAPI_ROOT)\compiler\latest\windows\bin\libsycl-complex.o + + + + + + \ No newline at end of file diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters new file mode 100644 index 0000000000..dcc683dbce --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters @@ -0,0 +1,36 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + + + + + + + Source Files + + + \ No newline at end of file diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.user b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.user new file mode 100644 index 0000000000..2354252aa4 --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.user @@ -0,0 +1,10 @@ + + + + $(LocalDebuggerEnvironment) + WindowsLocalDebugger + + + WindowsLocalDebugger + + \ No newline at end of file diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/sample.json b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/sample.json new file mode 100644 index 0000000000..ec3467d005 --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/sample.json @@ -0,0 +1,30 @@ +{ + "guid": "8572B85D-0B32-40B1-8112-538F480C8660", + "name": "Mandelbrot", + "categories": [ "Toolkit/Intel® oneAPI HPC Toolkit" ], + "description": "The Mandelbrot set - a fractal example in mathematics", + "toolchain": [ "dpcpp" ], + "languages": [ { "cpp": {} } ], + "targetDevice": [ "CPU", "GPU" ], + "os": [ "linux", "windows" ], + "builder": [ "ide", "cmake" ], + "ciTests": { + "linux": [{ + "steps": [ + "mkdir build", + "cd build", + "cmake ..", + "make", + "make run" + ] + }], + "windows": [{ + "steps": [ + "MSBuild mandelbrot.sln /t:Rebuild /p:Configuration=\"Release\"", + "cd x64/Release", + "mandelbrot.exe" + ] + }] + + } +} diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt new file mode 100644 index 0000000000..9cd8f8f64d --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt @@ -0,0 +1,11 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++17") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + +add_executable(mandelbrot main.cpp) +target_link_libraries(mandelbrot OpenCL sycl $ENV{ONEAPI_ROOT}/compiler/latest/linux/lib/libsycl-complex.o) +add_custom_target(run ${CMAKE_COMMAND} -E env SYCL_BE=PI_OPENCL ./mandelbrot) + +add_executable(mandelbrot_usm main.cpp) +target_compile_definitions(mandelbrot_usm PRIVATE MANDELBROT_USM) +target_link_libraries(mandelbrot_usm OpenCL sycl $ENV{ONEAPI_ROOT}/compiler/latest/linux/lib/libsycl-complex.o) +add_custom_target(run_usm ${CMAKE_COMMAND} -E env SYCL_BE=PI_OPENCL ./mandelbrot_usm) diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/main.cpp b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/main.cpp new file mode 100644 index 0000000000..cc8a9514ef --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/main.cpp @@ -0,0 +1,91 @@ +//============================================================== +// Copyright © 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT +// ============================================================= + +#include +#include +#include + +// dpc_common.hpp can be found in the dev-utilities include folder. +// e.g., $ONEAPI_ROOT/dev-utilities//include/dpc_common.hpp +#include "dpc_common.hpp" +#include "mandel.hpp" + +using namespace std; +using namespace sycl; + +void ShowDevice(queue &q) { + // Output platform and device information. + auto device = q.get_device(); + auto p_name = device.get_platform().get_info(); + cout << std::setw(20) << "Platform Name: " << p_name << "\n"; + auto p_version = device.get_platform().get_info(); + cout << std::setw(20) << "Platform Version: " << p_version << "\n"; + auto d_name = device.get_info(); + cout << std::setw(20) << "Device Name: " << d_name << "\n"; + auto max_work_group = device.get_info(); + cout << std::setw(20) << "Max Work Group: " << max_work_group << "\n"; + auto max_compute_units = device.get_info(); + cout << std::setw(20) << "Max Compute Units: " << max_compute_units << "\n\n"; +} + +void Execute(queue &q) { + // Demonstrate the Mandelbrot calculation serial and parallel. +#ifdef MANDELBROT_USM + cout << "Parallel Mandelbrot set using USM.\n"; + MandelParallelUsm m_par(row_size, col_size, max_iterations, &q); +#else + cout << "Parallel Mandelbrot set using buffers.\n"; + MandelParallel m_par(row_size, col_size, max_iterations); +#endif + + MandelSerial m_ser(row_size, col_size, max_iterations); + + // Run the code once to trigger JIT. + m_par.Evaluate(q); + + // Run the parallel version and time it. + dpc_common::TimeInterval t_par; + for (int i = 0; i < repetitions; ++i) m_par.Evaluate(q); + double parallel_time = t_par.Elapsed(); + + // Print the results. + m_par.Print(); + m_par.WriteImage(); + + // Run the serial version. + dpc_common::TimeInterval t_ser; + m_ser.Evaluate(); + double serial_time = t_ser.Elapsed(); + + // Report the results. + cout << std::setw(20) << "Serial time: " << serial_time << "s\n"; + cout << std::setw(20) << "Parallel time: " << (parallel_time / repetitions) + << "s\n"; + + // Validate. + m_par.Verify(m_ser); +} + +int main(int argc, char *argv[]) { + try { + // Create a queue on the default device. Set SYCL_DEVICE_TYPE environment + // variable to (CPU|GPU|FPGA|HOST) to change the device. + queue q(default_selector{}, dpc_common::exception_handler); + + // Display the device info. + ShowDevice(q); + + // Compute Mandelbrot set. + Execute(q); + } catch (...) { + // Some other exception detected. + cout << "Failed to compute Mandelbrot set.\n"; + std::terminate(); + } + + cout << "Successfully computed Mandelbrot set.\n"; + return 0; +} diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp new file mode 100644 index 0000000000..991478032c --- /dev/null +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp @@ -0,0 +1,286 @@ +//============================================================== +// Copyright © 2020 Intel Corporation +// +// SPDX-License-Identifier: MIT +// ============================================================= + +#pragma once + +#include +#include +#include +#include + +// stb/*.h files can be found in the dev-utilities include folder. +// e.g., $ONEAPI_ROOT/dev-utilities//include/stb/*.h +#define STB_IMAGE_IMPLEMENTATION +#include "stb/stb_image.h" +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb/stb_image_write.h" + +using namespace std; +using namespace sycl; + +constexpr int row_size = 512; +constexpr int col_size = 512; +constexpr int max_iterations = 100; +constexpr int repetitions = 100; + +// Parameters used in Mandelbrot including number of row, column, and iteration. +struct MandelParameters { + int row_count_; + int col_count_; + int max_iterations_; + + typedef std::complex ComplexF; + + MandelParameters(int row_count, int col_count, int max_iterations) + : row_count_(row_count), + col_count_(col_count), + max_iterations_(max_iterations) {} + + int row_count() const { return row_count_; } + int col_count() const { return col_count_; } + int max_iterations() const { return max_iterations_; } + + // Scale from 0..row_count to -1.5..0.5 + float ScaleRow(int i) const { return -1.5f + (i * (2.0f / row_count_)); } + + // Scale from 0..col_count to -1..1 + float ScaleCol(int i) const { return -1.0f + (i * (2.0f / col_count_)); } + + // Mandelbrot set are points that do not diverge within max_iterations. + int Point(const ComplexF &c) const { + int count = 0; + ComplexF z = 0; + + for (int i = 0; i < max_iterations_; ++i) { + auto r = z.real(); + auto im = z.imag(); + + // Leave loop if diverging. + if (((r * r) + (im * im)) >= 4.0f) { + break; + } + + z = z * z + c; + count++; + } + + return count; + } +}; + +// Shared functions for computing Mandelbrot set. +class Mandel { + private: + MandelParameters p_; + + protected: + int *data_; + + public: + Mandel(int row_count, int col_count, int max_iterations) + : p_(row_count, col_count, max_iterations) { + data_ = nullptr; + } + + virtual ~Mandel() {} + virtual void Alloc() { data_ = new int[p_.row_count() * p_.col_count()]; } + virtual void Free() { delete[] data_; } + + MandelParameters GetParameters() const { return p_; } + + void WriteImage() { + constexpr int channel_num{3}; + int row_count = p_.row_count(); + int col_count = p_.col_count(); + + uint8_t *pixels = new uint8_t[col_count * row_count * channel_num]; + + int index = 0; + + for (int j = 0; j < row_count; ++j) { + for (int i = 0; i < col_count; ++i) { + float normalized = (1.0 * data_[i * col_count + j]) / max_iterations; + int color = int(normalized * 0xFFFFFF); // 16M color. + + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + + pixels[index++] = r; + pixels[index++] = g; + pixels[index++] = b; + } + } + + stbi_write_png("mandelbrot.png", row_count, col_count, channel_num, pixels, + col_count * channel_num); + + delete[] pixels; + } + + // Use only for debugging with small dimensions. + void Print() { + if (p_.row_count() > 128 || p_.col_count() > 128) { + cout << " Rendered image output to file: mandelbrot.png " + "(output too large to display in text)\n"; + + return; + } + + for (int i = 0; i < p_.row_count(); ++i) { + for (int j = 0; j < p_.col_count_; ++j) { + cout << std::setw(1) + << ((GetValue(i, j) >= p_.max_iterations()) ? "x" : " "); + } + + cout << "\n"; + } + } + + // Accessor for data and count values. + int *data() const { return data_; } + + // Accessor to read a value from the mandelbrot data matrix. + int GetValue(int i, int j) const { return data_[i * p_.col_count_ + j]; } + + // Mutator to store a value into the mandelbrot data matrix. + void SetValue(int i, int j, float v) { data_[i * p_.col_count_ + j] = v; } + + // Validate the results match. + void Verify(Mandel &m) { + if ((m.p_.row_count() != p_.row_count_) || + (m.p_.col_count() != p_.col_count_)) { + cout << "Fail verification - matrix size is different\n"; + throw std::runtime_error("Verification failure"); + } + + int diff = 0; + + for (int i = 0; i < p_.row_count(); ++i) { + for (int j = 0; j < p_.col_count(); ++j) { + if (m.GetValue(i, j) != GetValue(i, j)) diff++; + } + } + + double tolerance = 0.05; + double ratio = (double)diff / (double)(p_.row_count() * p_.col_count()); + +#if _DEBUG + cout << "diff: " << diff << "\n"; + cout << "total count: " << p_.row_count() * p_.col_count() << "\n"; +#endif + + if (ratio > tolerance) { + cout << "Fail verification - diff larger than tolerance\n"; + throw std::runtime_error("Verification failure"); + } + +#if _DEBUG + cout << "Pass verification\n"; +#endif + } +}; + +// Serial implementation for computing Mandelbrot set. +class MandelSerial : public Mandel { + public: + MandelSerial(int row_count, int col_count, int max_iterations) + : Mandel(row_count, col_count, max_iterations) { + Alloc(); + } + + ~MandelSerial() { Free(); } + + void Evaluate() { + // Iterate over image and compute mandel for each point. + MandelParameters p = GetParameters(); + + for (int i = 0; i < p.row_count(); ++i) { + for (int j = 0; j < p.col_count(); ++j) { + auto c = MandelParameters::ComplexF(p.ScaleRow(i), p.ScaleCol(j)); + SetValue(i, j, p.Point(c)); + } + } + } +}; + +// Parallel implementation for computing Mandelbrot set using buffers. +class MandelParallel : public Mandel { + public: + MandelParallel(int row_count, int col_count, int max_iterations) + : Mandel(row_count, col_count, max_iterations) { + Alloc(); + } + + ~MandelParallel() { Free(); } + + void Evaluate(queue &q) { + // Iterate over image and check if each point is in Mandelbrot set. + MandelParameters p = GetParameters(); + + const int rows = p.row_count(); + const int cols = p.col_count(); + + buffer data_buf(data(), range(rows, cols)); + + // We submit a command group to the queue. + q.submit([&](handler &h) { + // Get access to the buffer. + auto b = data_buf.get_access(h); + + // Iterate over image and compute mandel for each point. + h.parallel_for(range(rows, cols), [=](id<2> index) { + int i = int(index[0]); + int j = int(index[1]); + auto c = MandelParameters::ComplexF(p.ScaleRow(i), p.ScaleCol(j)); + b[index] = p.Point(c); + }); + }); + } +}; + +// Parallel implementation for computing Mandelbrot set using Unified Shared +// Memory (USM). +class MandelParallelUsm : public Mandel { + private: + queue *q; + + public: + MandelParallelUsm(int row_count, int col_count, int max_iterations, queue *q) + : Mandel(row_count, col_count, max_iterations) { + this->q = q; + Alloc(); + } + + ~MandelParallelUsm() { Free(); } + + virtual void Alloc() { + MandelParameters p = GetParameters(); + data_ = malloc_shared(p.row_count() * p.col_count(), *q); + } + + virtual void Free() { free(data_, *q); } + + void Evaluate(queue &q) { + // Iterate over image and check if each point is in Mandelbrot set. + MandelParameters p = GetParameters(); + + const int rows = p.row_count(); + const int cols = p.col_count(); + auto ldata = data_; + + // Iterate over image and compute mandel for each point. + auto e = q.parallel_for(range(rows * cols), [=](id<1> index) { + int i = index / cols; + int j = index % cols; + auto c = MandelParameters::ComplexF(p.ScaleRow(i), p.ScaleCol(j)); + ldata[index] = p.Point(c); + }); + + // Wait for the asynchronous computation on device to complete. + e.wait(); + } +}; From d0fe6542799c5928c3a3e4ed80cf189f5cac1c07 Mon Sep 17 00:00:00 2001 From: vmadanan Date: Mon, 17 Aug 2020 13:52:21 -0700 Subject: [PATCH 2/2] Adding changes to mandelbrot to remove libsycl-complex.so dependency --- .../DPC++/CombinationalLogic/mandelbrot/License.txt | 4 ---- .../DPC++/CombinationalLogic/mandelbrot/README.md | 12 ------------ .../CombinationalLogic/mandelbrot/mandelbrot.vcxproj | 11 +---------- .../mandelbrot/mandelbrot.vcxproj.filters | 6 ------ .../CombinationalLogic/mandelbrot/src/CMakeLists.txt | 8 ++++---- .../CombinationalLogic/mandelbrot/src/mandel.hpp | 9 +++++++-- 6 files changed, 12 insertions(+), 38 deletions(-) diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt index 9540ee9f72..8f608e972a 100644 --- a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/License.txt @@ -1,8 +1,4 @@ -<<<<<<< HEAD Copyright 2019 Intel Corporation -======= -Copyright Intel Corporation ->>>>>>> 646c0545c8df6680d8d8a84b191ce56b698e346e Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md index e4e06e143c..312bb4e783 100644 --- a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/README.md @@ -25,12 +25,9 @@ This code sample is licensed under MIT license. ## Building the `Mandelbrot` Program for CPU and GPU -<<<<<<< HEAD -======= ### Include Files The include folder is located at %ONEAPI_ROOT%\dev-utilities\latest\include on your development system. ->>>>>>> 646c0545c8df6680d8d8a84b191ce56b698e346e ### Running Samples In DevCloud If running a sample in the Intel DevCloud, remember that you must specify the compute node (CPU, GPU, FPGA) as well whether to run in batch or interactive mode. For more information see the Intel® oneAPI Base Toolkit Get Started Guide (https://devcloud.intel.com/oneapi/get-started/base-toolkit/) @@ -65,15 +62,6 @@ $ make Right click on the project in Solution explorer and select Rebuild. From top menu select Debug -> Start without Debugging. -<<<<<<< HEAD ->If you see the following error message when compiling this sample: -> -``` -Error 'dpc_common.hpp' file not found -``` ->You need to add the following directory to the list of include folders, that are required by your project, in your project's Visual Studio project property panel. The missing include folder is located at `%ONEAPI_ROOT%\dev-utilities\latest\include` on your development system. -======= ->>>>>>> 646c0545c8df6680d8d8a84b191ce56b698e346e * Build the program using MSBuild Open "x64 Native Tools Command Prompt for VS2017" or "x64 Native Tools Command Prompt for VS2019" diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj index c2f4da4f3f..8a4eaa9d40 100644 --- a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj @@ -14,10 +14,6 @@ -<<<<<<< HEAD - -======= ->>>>>>> 646c0545c8df6680d8d8a84b191ce56b698e346e @@ -113,15 +109,11 @@ true pch.h Level3 -<<<<<<< HEAD -======= $(ONEAPI_ROOT)dev-utilities\latest\include ->>>>>>> 646c0545c8df6680d8d8a84b191ce56b698e346e Console true - $(ONEAPI_ROOT)\compiler\latest\windows\bin\libsycl-complex.o @@ -159,10 +151,9 @@ true true true - $(ONEAPI_ROOT)\compiler\latest\windows\bin\libsycl-complex.o - \ No newline at end of file + diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters index d0d884d6b3..fe00fec339 100644 --- a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/mandelbrot.vcxproj.filters @@ -15,12 +15,6 @@ -<<<<<<< HEAD - - Header Files - -======= ->>>>>>> 646c0545c8df6680d8d8a84b191ce56b698e346e Header Files diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt index 9cd8f8f64d..4c3d57303d 100644 --- a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/CMakeLists.txt @@ -2,10 +2,10 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -std=c++17") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") add_executable(mandelbrot main.cpp) -target_link_libraries(mandelbrot OpenCL sycl $ENV{ONEAPI_ROOT}/compiler/latest/linux/lib/libsycl-complex.o) -add_custom_target(run ${CMAKE_COMMAND} -E env SYCL_BE=PI_OPENCL ./mandelbrot) +target_link_libraries(mandelbrot OpenCL sycl) +add_custom_target(run ./mandelbrot) add_executable(mandelbrot_usm main.cpp) target_compile_definitions(mandelbrot_usm PRIVATE MANDELBROT_USM) -target_link_libraries(mandelbrot_usm OpenCL sycl $ENV{ONEAPI_ROOT}/compiler/latest/linux/lib/libsycl-complex.o) -add_custom_target(run_usm ${CMAKE_COMMAND} -E env SYCL_BE=PI_OPENCL ./mandelbrot_usm) +target_link_libraries(mandelbrot_usm OpenCL sycl) +add_custom_target(run_usm ./mandelbrot_usm) diff --git a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp index 991478032c..7c261a5e56 100644 --- a/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp +++ b/DirectProgramming/DPC++/CombinationalLogic/mandelbrot/src/mandel.hpp @@ -33,6 +33,10 @@ struct MandelParameters { int max_iterations_; typedef std::complex ComplexF; + static std::complex complex_square( std::complex c) + { + return std::complex( c.real()*c.real() - c.imag()*c.imag(), c.real()*c.imag()*2 ); + } MandelParameters(int row_count, int col_count, int max_iterations) : row_count_(row_count), @@ -41,7 +45,7 @@ struct MandelParameters { int row_count() const { return row_count_; } int col_count() const { return col_count_; } - int max_iterations() const { return max_iterations_; } +int max_iterations() const { return max_iterations_; } // Scale from 0..row_count to -1.5..0.5 float ScaleRow(int i) const { return -1.5f + (i * (2.0f / row_count_)); } @@ -63,7 +67,8 @@ struct MandelParameters { break; } - z = z * z + c; + // z = z * z + c; + z = complex_square(z) + c; count++; }