[pstl] Add a serial backend for the PSTL
authorLouis Dionne <ldionne@apple.com>
Thu, 18 Apr 2019 18:20:19 +0000 (18:20 +0000)
committerLouis Dionne <ldionne@apple.com>
Thu, 18 Apr 2019 18:20:19 +0000 (18:20 +0000)
Summary:
The serial backend performs all tasks serially and does not require
threads. It does not have any dependencies beyond normal C++, but
it is not very efficient either.

Reviewers: rodgert, MikeDvorskiy

Subscribers: mgorny, jkorous, dexonsmith, jdoerfert, libcxx-commits

Differential Revision: https://reviews.llvm.org/D59791

llvm-svn: 358700

pstl/CMakeLists.txt
pstl/include/pstl/internal/parallel_backend.h
pstl/include/pstl/internal/parallel_backend_serial.h [new file with mode: 0644]
pstl/include/pstl/internal/pstl_config.h

index d8614a0..a11487f 100644 (file)
@@ -35,19 +35,16 @@ add_library(pstl::ParallelSTL ALIAS ParallelSTL)
 target_compile_features(ParallelSTL INTERFACE cxx_std_17)
 
 if (PARALLELSTL_USE_PARALLEL_POLICIES)
-    message(STATUS "Using Parallel Policies")
-    if (PARALLELSTL_BACKEND STREQUAL "tbb")
+    if (PARALLELSTL_BACKEND STREQUAL "serial")
+        message(STATUS "Parallel STL uses the serial backend")
+        target_compile_definitions(ParallelSTL INTERFACE -D_PSTL_PAR_BACKEND_SERIAL)
+    elseif (PARALLELSTL_BACKEND STREQUAL "tbb")
         find_package(TBB 2018 REQUIRED tbb OPTIONAL_COMPONENTS tbbmalloc)
         message(STATUS "Parallel STL uses TBB ${TBB_VERSION} (interface version: ${TBB_INTERFACE_VERSION})")
         target_link_libraries(ParallelSTL INTERFACE TBB::tbb)
-      else()
-        message(STATUS "Using Parallel Policies, but not tbb")
-        if (TARGET ${PARALLELSTL_BACKEND})
-            target_link_libraries(ParallelSTL INTERFACE ${PARALLELSTL_BACKEND})
-        else()
-            find_package(${PARALLELSTL_BACKEND} REQUIRED)
-            target_link_libraries(ParallelSTL INTERFACE ${${PARALLELSTL_BACKEND}_IMPORTED_TARGETS})
-        endif()
+        target_compile_definitions(ParallelSTL INTERFACE -D_PSTL_PAR_BACKEND_TBB)
+    else()
+        message(FATAL_ERROR "Requested unknown Parallel STL backend '${PARALLELSTL_BACKEND}'.")
     endif()
 else()
     target_compile_definitions(ParallelSTL INTERFACE PSTL_USE_PARALLEL_POLICIES=0)
index 438f87e..85d2d4b 100644 (file)
@@ -10,7 +10,9 @@
 #ifndef _PSTL_PARALLEL_BACKEND_H
 #define _PSTL_PARALLEL_BACKEND_H
 
-#if _PSTL_PAR_BACKEND_TBB
+#if defined(_PSTL_PAR_BACKEND_SERIAL)
+#    include "parallel_backend_serial.h"
+#elif defined(_PSTL_PAR_BACKEND_TBB)
 #    include "parallel_backend_tbb.h"
 #else
 _PSTL_PRAGMA_MESSAGE("Parallel backend was not specified");
diff --git a/pstl/include/pstl/internal/parallel_backend_serial.h b/pstl/include/pstl/internal/parallel_backend_serial.h
new file mode 100644 (file)
index 0000000..e4b3a70
--- /dev/null
@@ -0,0 +1,138 @@
+// -*- C++ -*-
+//===-- parallel_backend_serial.h -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _PSTL_PARALLEL_BACKEND_SERIAL_H
+#define _PSTL_PARALLEL_BACKEND_SERIAL_H
+
+#include <algorithm>
+#include <cstddef>
+#include <memory>
+#include <numeric>
+#include <utility>
+
+namespace __pstl
+{
+namespace __serial
+{
+
+template <typename _Tp>
+class __buffer
+{
+    std::allocator<_Tp> __allocator_;
+    _Tp* __ptr_;
+    const std::size_t __buf_size_;
+    __buffer(const __buffer&) = delete;
+    void
+    operator=(const __buffer&) = delete;
+
+  public:
+    __buffer(std::size_t __n) : __allocator_(), __ptr_(__allocator_.allocate(__n)), __buf_size_(__n) {}
+
+    operator bool() const { return __ptr_ != nullptr; }
+    _Tp*
+    get() const
+    {
+        return __ptr_;
+    }
+    ~__buffer() { __allocator_.deallocate(__ptr_, __buf_size_); }
+};
+
+inline void
+__cancel_execution()
+{
+}
+
+template <class _ExecutionPolicy, class _Index, class _Fp>
+void
+__parallel_for(_ExecutionPolicy&&, _Index __first, _Index __last, _Fp __f)
+{
+    __f(__first, __last);
+}
+
+template <class _ExecutionPolicy, class _Value, class _Index, typename _RealBody, typename _Reduction>
+_Value
+__parallel_reduce(_ExecutionPolicy&&, _Index __first, _Index __last, const _Value& __identity,
+                  const _RealBody& __real_body, const _Reduction&)
+{
+    if (__first == __last)
+    {
+        return __identity;
+    }
+    else
+    {
+        return __real_body(__first, __last, __identity);
+    }
+}
+
+template <class _ExecutionPolicy, class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce>
+_Tp
+__parallel_transform_reduce(_ExecutionPolicy&&, _Index __first, _Index __last, _UnaryOp, _Tp __init, _BinaryOp,
+                            _Reduce __reduce)
+{
+    return __reduce(__first, __last, __init);
+}
+
+template <class _ExecutionPolicy, typename _Index, typename _Tp, typename _Rp, typename _Cp, typename _Sp, typename _Ap>
+void
+__parallel_strict_scan(_ExecutionPolicy&&, _Index __n, _Tp __initial, _Rp __reduce, _Cp __combine, _Sp __scan,
+                       _Ap __apex)
+{
+    _Tp __sum = __initial;
+    if (__n)
+        __sum = __combine(__sum, __reduce(_Index(0), __n));
+    __apex(__sum);
+    if (__n)
+        __scan(_Index(0), __n, __initial);
+}
+
+template <class _ExecutionPolicy, class _Index, class _UnaryOp, class _Tp, class _BinaryOp, class _Reduce, class _Scan>
+_Tp
+__parallel_transform_scan(_ExecutionPolicy&&, _Index __n, _UnaryOp, _Tp __init, _BinaryOp, _Reduce, _Scan __scan)
+{
+    return __scan(_Index(0), __n, __init);
+}
+
+template <class _ExecutionPolicy, typename _RandomAccessIterator, typename _Compare, typename _LeafSort>
+void
+__parallel_stable_sort(_ExecutionPolicy&&, _RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
+                       _LeafSort __leaf_sort, std::size_t = 0)
+{
+    __leaf_sort(__first, __last, __comp);
+}
+
+template <class _ExecutionPolicy, typename _RandomAccessIterator1, typename _RandomAccessIterator2,
+          typename _RandomAccessIterator3, typename _Compare, typename _LeafMerge>
+void
+__parallel_merge(_ExecutionPolicy&&, _RandomAccessIterator1 __first1, _RandomAccessIterator1 __last1,
+                 _RandomAccessIterator2 __first2, _RandomAccessIterator2 __last2, _RandomAccessIterator3 __out,
+                 _Compare __comp, _LeafMerge __leaf_merge)
+{
+    __leaf_merge(__first1, __last1, __first2, __last2, __out, __comp);
+}
+
+template <class _ExecutionPolicy, typename _F1, typename _F2>
+void
+__parallel_invoke(_ExecutionPolicy&&, _F1&& __f1, _F2&& __f2)
+{
+    std::forward<_F1>(__f1)();
+    std::forward<_F2>(__f2)();
+}
+
+} // namespace __serial
+} // namespace __pstl
+
+namespace __pstl
+{
+namespace __par_backend
+{
+using namespace __pstl::__serial;
+}
+} // namespace __pstl
+
+#endif /* _PSTL_PARALLEL_BACKEND_SERIAL_H */
index e6728d3..7f32725 100644 (file)
 #    define _PSTL_USE_PAR_POLICIES 1
 #endif
 
-#if _PSTL_USE_PAR_POLICIES
-#    if !defined(_PSTL_PAR_BACKEND_TBB)
-#        define _PSTL_PAR_BACKEND_TBB 1
-#    endif
-#else
-#    undef _PSTL_PAR_BACKEND_TBB
+#if !defined(_PSTL_PAR_BACKEND_SERIAL) && !defined(_PSTL_PAR_BACKEND_TBB)
+#   error "The parallel backend is neither serial nor TBB"
 #endif
 
 // Check the user-defined macro for warnings