Repository: kokkos/kokkos
Pull request #7542: call thrust::inclusive_scan when available
Author: login: science-enthusiast
Labels: name: Backend - CUDA
name: Backend - HIP
name: SNL-CI-APPROVAL
description: Required for non-SNL contributions to run on SNL CI
Created: 2024-11-22T14:07:46Z | Merged: 2025-03-04T04:16:02Z

Update 6/1/25: The PR now takes care of AMD GPUs also. Thus, in total 4 functions have been added, 2 for CUDA and 2 for HIP. For both CUDA and HIP, two overloads of Kokkos::Experimental::inclusive_scan have been implemented which call the corresponding thrust::inclusive_scan functions, under device execution space.

Also, a benchmark code has been implemented inside the `algorithms/perf_test`. Note that the directory `algorithms/perf_test` has been newly created. Going forward perf tests regarding algorithms are expected to be added here, just like `core/perf_test`.

Rough performance numbers (based on just a single run of the scan operation) can be observed by using the following two test codes:

Thrust: [thrust_single_test_cpp.txt](https://github.com/user-attachments/files/18504552/thrust_single_test_cpp.txt)

Kokkos: [kokkos_single_test_cpp.txt](https://github.com/user-attachments/files/18504562/kokkos_single_test_cpp.txt)

Total number of elements in the input = 1e8. The input contains values 0, 1, 2, ..., 1e8 - 1. Scans based on sum and max binary operations were tested.

thrust::inclusive_scan 
sum (default): 2467 us, sum (functor): 5460 us, max (functor): 6165 us

With modified Kokkos (calling thrust::inclusive_scan)
sum (default): 3829 us, sum (functor): 4667 us, max (functor): 2683 us

With original Kokkos (calling Kokkos::parallel_scan)
sum (default): 11488 us, sum (functor): 9618 us, max (functor): 9743 us

As a point of reference, Kokkos::parallel_scan with a summation based functor takes 12998 us based on the following code: 
[test-kokkos_cpp.txt](https://github.com/user-attachments/files/17870598/test-kokkos_cpp.txt)



Diff:
diff --git a/algorithms/CMakeLists.txt b/algorithms/CMakeLists.txt
index 73ce9f7ec55..e257e4ccce0 100644
--- a/algorithms/CMakeLists.txt
+++ b/algorithms/CMakeLists.txt
@@ -5,3 +5,7 @@ endif()
 if(NOT ((KOKKOS_ENABLE_OPENMPTARGET AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC) OR KOKKOS_ENABLE_OPENACC))
   kokkos_add_test_directories(unit_tests)
 endif()
+
+if(Kokkos_ENABLE_BENCHMARKS)
+  add_subdirectory(perf_test)
+endif()
diff --git a/algorithms/perf_test/CMakeLists.txt b/algorithms/perf_test/CMakeLists.txt
new file mode 100644
index 00000000000..a41d3f891b1
--- /dev/null
+++ b/algorithms/perf_test/CMakeLists.txt
@@ -0,0 +1,63 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  # FIXME: Check whether the following target_compile_options are needed.
+  # If so, clarify why.
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+# FIXME: Could NAME be a one_value_keyword specified in cmake_parse_arguments?
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  # FIXME: BenchmarkMain.cpp and Benchmark_Context.cpp should be moved to a common location from which
+  # they can be used by all performance tests.
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  # FIXME: This alone will not work. It might need an architecture and standard which need to be defined on target level.
+  # It will potentially go away with #7582.
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
+
+kokkos_add_benchmark(PerformanceTest_InclusiveScan SOURCES test_inclusive_scan.cpp)
diff --git a/algorithms/perf_test/test_inclusive_scan.cpp b/algorithms/perf_test/test_inclusive_scan.cpp
new file mode 100644
index 00000000000..a0a5de6b075
--- /dev/null
+++ b/algorithms/perf_test/test_inclusive_scan.cpp
@@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+auto inclusive_scan(const Kokkos::View<T*, ExecSpace>& in,
+                    const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out));
+  } else {
+    KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out), ScanFunctor<T>());
+  }
+
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtain_last_elem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Inclusive Scan with default binary operation (sum)
+// or user provided functor
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+void BM_inclusive_scan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepare_views<T>(kProbSize);
+
+  T res_check;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    res_check = ref_scan<T>(h_in);
+  } else {
+    res_check = ref_scan<T>(h_in, ScanFunctor<T>());
+  }
+
+  double time_scan = 0.;
+  bool passed      = false;
+
+  for (auto _ : state) {
+    if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+      std::tie(time_scan, passed) = inclusive_scan<T>(in, out, res_check);
+    } else {
+      std::tie(time_scan, passed) =
+          inclusive_scan<T, ScanFunctor>(in, out, res_check);
+    }
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+constexpr std::size_t PROB_SIZE = 100'000'000;
+
+}  // anonymous namespace
+
+// FIXME: Add logic to pass min. warm-up time. Also, the value should be set
+// by the user. Say, via the environment variable BENCHMARK_MIN_WARMUP_TIME.
+
+BENCHMARK(BM_inclusive_scan<std::uint64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::int64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<double>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::uint64_t, SumFunctor>)
+    ->Arg(PROB_SIZE)
+    ->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::int64_t, SumFunctor>)
+    ->Arg(PROB_SIZE)
+    ->UseManualTime();
+BENCHMARK(BM_inclusive_scan<double, SumFunctor>)
+    ->Arg(PROB_SIZE)
+    ->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::uint64_t, MaxFunctor>)
+    ->Arg(PROB_SIZE)
+    ->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::int64_t, MaxFunctor>)
+    ->Arg(PROB_SIZE)
+    ->UseManualTime();
+BENCHMARK(BM_inclusive_scan<double, MaxFunctor>)
+    ->Arg(PROB_SIZE)
+    ->UseManualTime();
diff --git a/algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp b/algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
index c633f629a2e..63791aafdee 100644
--- a/algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
+++ b/algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
@@ -18,12 +18,59 @@
 #define KOKKOS_STD_ALGORITHMS_INCLUSIVE_SCAN_IMPL_HPP
 
 #include <Kokkos_Core.hpp>
+#include <Kokkos_Profiling_ScopedRegion.hpp>
 #include "Kokkos_Constraints.hpp"
 #include "Kokkos_HelperPredicates.hpp"
 #include <std_algorithms/Kokkos_TransformInclusiveScan.hpp>
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
+#pragma push_macro("_CubLog")
+#ifdef _CubLog
+#undef _CubLog
+#endif
+#define _CubLog
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#pragma pop_macro("_CubLog")
+#else
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#endif
+
+#pragma GCC diagnostic pop
+
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#endif
+
 namespace Kokkos {
 namespace Experimental {
 namespace Impl {
@@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
 template <class ExecutionSpace, class InputIteratorType,
           class OutputIteratorType>
 OutputIteratorType inclusive_scan_default_op_exespace_impl(
@@ -132,11 +218,16 @@ OutputIteratorType inclusive_scan_default_op_exespace_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(label + " via Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(label,
                           RangePolicy<ExecutionSpace>(ex, 0, num_elements),
                           func_type(first_from, first_dest));
   ex.fence("Kokkos::inclusive_scan_default_op: fence after operation");
 
+  Kokkos::Profiling::popRegion();
+
   // return
   return first_dest + num_elements;
 }
@@ -144,6 +235,49 @@ OutputIteratorType inclusive_scan_default_op_exespace_impl(
 // -------------------------------------------------------------
 // inclusive_scan_custom_binary_op_impl
 // -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType, class BinaryOpType>
+OutputIteratorType inclusive_scan_custom_binary_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest,
+    BinaryOpType binary_op) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest,
+                         binary_op);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType, class BinaryOpType>
+OutputIteratorType inclusive_scan_custom_binary_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest,
+    BinaryOpType binary_op) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest,
+                         binary_op);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
 template <class ExecutionSpace, class InputIteratorType,
           class OutputIteratorType, class BinaryOpType>
 OutputIteratorType inclusive_scan_custom_binary_op_exespace_impl(
@@ -168,11 +302,16 @@ OutputIteratorType inclusive_scan_custom_binary_op_exespace_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(label + " via Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(
       label, RangePolicy<ExecutionSpace>(ex, 0, num_elements),
       func_type(first_from, first_dest, binary_op, unary_op_type()));
   ex.fence("Kokkos::inclusive_scan_custom_binary_op: fence after operation");
 
+  Kokkos::Profiling::popRegion();
+
   // return
   return first_dest + num_elements;
 }
@@ -203,12 +342,17 @@ OutputIteratorType inclusive_scan_custom_binary_op_exespace_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(label + " via Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(label,
                           RangePolicy<ExecutionSpace>(ex, 0, num_elements),
                           func_type(first_from, first_dest, binary_op,
                                     unary_op_type(), std::move(init_value)));
   ex.fence("Kokkos::inclusive_scan_custom_binary_op: fence after operation");
 
+  Kokkos::Profiling::popRegion();
+
   // return
   return first_dest + num_elements;
 }
@@ -291,7 +435,6 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_custom_binary_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
-
   ::Kokkos::parallel_scan(
       TeamThreadRange(teamHandle, 0, num_elements),
       func_type(first_from, first_dest, binary_op, unary_op_type()));
diff --git a/core/perf_test/BenchmarkMain.cpp b/core/perf_test/BenchmarkMain.cpp
index 2232019c191..3524d58c0c9 100644
--- a/core/perf_test/BenchmarkMain.cpp
+++ b/core/perf_test/BenchmarkMain.cpp
@@ -24,6 +24,7 @@
 int main(int argc, char** argv) {
   Kokkos::initialize(argc, argv);
   benchmark::Initialize(&argc, argv);
+  // FIXME: seconds as default time unit leads to precision loss
   benchmark::SetDefaultTimeUnit(benchmark::kSecond);
   KokkosBenchmark::add_benchmark_context(true);
 


Reviews:
user: login: cedricchevalier19
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-11-22T16:51:29Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-11-22T17:01:19Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-11-22T18:57:22Z
user: login: aprokop
body: Why only CUDA? What about rocThrust? What's the difference there?
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-11-23T00:54:08Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2024-11-23T07:13:17Z
user: login: tpadioleau
body: I have a few remarks/questions

1. Can you share the latest version of your test codes ? You recently added repetition loops right ?

2. Can you benchmark again the Thrust implementation using `thrust::device_vector<size_t>` for the input array ?

3. Can you use the same functors for `SumFunctor` and `MaxFunctor` both in the Thrust and Kokkos implementations ?
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-11-26T14:00:49Z
user: login: dalg24
body: Please add an executable that benchmarks the performance, either under `benchmarks/[stl_]algorithms/inclusive_scan` or `algorithms/perf_tests`.
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-12-02T15:22:02Z
user: login: dalg24
state: COMMENTED
author_association: MEMBER
submitted_at: 2024-12-02T15:25:04Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T10:44:00Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T10:49:48Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T12:56:52Z
user: login: dalg24
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-01-06T13:03:15Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T13:48:54Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T13:50:24Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T13:51:24Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T13:54:23Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T13:56:48Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T14:05:29Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T14:16:41Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T14:39:49Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-06T14:53:49Z
user: login: tpadioleau
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-01-07T09:14:07Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-07T09:18:26Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-07T09:21:25Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-07T09:22:00Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-07T09:34:24Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-07T10:17:21Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-07T10:34:24Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-09T08:59:16Z
user: login: tpadioleau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-01-09T09:45:42Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-09T09:56:12Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-09T11:22:02Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-09T13:20:17Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-09T15:27:26Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-10T08:44:55Z
user: login: tpadioleau
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-01-10T09:44:02Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-15T09:27:50Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-15T10:15:34Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-15T10:18:19Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-15T14:12:02Z
user: login: masterleinad
body: I still don't see new performance results.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-15T14:13:37Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-16T21:47:58Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-17T16:49:18Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-17T16:56:59Z
user: login: masterleinad
body: FIne with me.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-01-17T19:48:46Z
user: login: Rombur
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-01-21T15:48:16Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-21T16:02:56Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-01-22T11:16:12Z
user: login: Rombur
state: APPROVED
author_association: MEMBER
submitted_at: 2025-01-22T13:51:35Z
user: login: tpadioleau
body: lgtm
state: APPROVED
author_association: MEMBER
submitted_at: 2025-01-22T17:25:32Z
user: login: dalg24
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-03T12:52:28Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T13:05:49Z
user: login: dalg24
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-03T15:26:06Z
user: login: dalg24
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-03T15:29:08Z
user: login: dalg24
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-02-03T15:32:54Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T23:20:21Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T23:44:34Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T23:45:41Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-03T23:46:18Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T12:51:56Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T12:53:33Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T12:57:59Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T13:04:11Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T13:27:20Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T15:16:28Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T16:54:25Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T19:24:56Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-04T19:46:14Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-05T10:39:41Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-05T10:41:55Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-05T11:24:21Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T15:38:43Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T15:40:40Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T15:50:06Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T15:52:22Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T16:09:31Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T16:12:22Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-06T18:53:32Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T08:44:29Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T08:45:22Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T08:46:12Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T08:47:08Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T10:31:08Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T10:31:29Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T14:05:19Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T16:03:22Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T16:09:16Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T16:14:48Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T16:32:26Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T16:36:41Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-10T16:53:37Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-11T13:52:22Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-11T14:42:28Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-12T15:49:55Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-12T15:52:58Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-12T15:56:55Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T10:20:54Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T12:41:26Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T13:51:43Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T14:18:21Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T14:46:38Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T14:54:14Z
user: login: masterleinad
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T14:56:05Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T15:28:13Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T16:36:54Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-02-13T16:40:32Z
user: login: JBludau
body: I think it is getting there
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T15:21:42Z
user: login: science-enthusiast
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T15:46:24Z
user: login: JBludau
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T16:04:54Z

Review comments:
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: cedricchevalier19
body: Just curious, but is this error still present with the latest versions of clang or cuda?
created_at: 2024-11-22T16:51:29Z
author_association: MEMBER
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Good point. I will check.
created_at: 2024-11-22T17:01:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
+#pragma push_macro("_CubLog")
+#ifdef _CubLog
+#undef _CubLog
+#endif
+#define _CubLog
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#pragma pop_macro("_CubLog")
+#else
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#endif
+
+#pragma GCC diagnostic pop
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: aprokop
body: Should we isolate all of these in a header? Otherwise, we'll have multiple copies for every time we include Thrust. Same code is in sort_by_key, and will proliferate further once we start incorporate some Thrust calls.
created_at: 2024-11-22T18:19:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +142,25 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: The label is unused here. Maybe, add something like
```C++
 uint64_t kpID = 0;
    if (Kokkos::Profiling::profileLibraryLoaded()) {
      Kokkos::Profiling::beginParallelScan(
          label + " via thrust::inclusive_scan",
          Kokkos::Profiling::Experimental::device_id(ex), &kpID);
    }
```
before the call to `thrust::inclusize_scan` and
```C++
  if (Kokkos::Profiling::profileLibraryLoaded()) {
      Kokkos::Profiling::endParallelScan(kpID);
    }
```
after it. Similarly below.
created_at: 2024-11-22T18:57:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
+#pragma push_macro("_CubLog")
+#ifdef _CubLog
+#undef _CubLog
+#endif
+#define _CubLog
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#pragma pop_macro("_CubLog")
+#else
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#endif
+
+#pragma GCC diagnostic pop
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Yes, it will be good to run tests on AMD GPUs. I will come back on this.

This code snippet was copied from the sort implementation. Yes, refactoring this part into a separate header is the better approach. Also, as @cedricchevalier19 pointed out, I will check whether the problem still exists with recent Clang and Cuda.
created_at: 2024-11-23T07:13:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: dalg24
body: Please open a separate issue to track this.  In particular we are interested in knowing if this will still be required in 5.0 when we bump our minimum Cuda/Thrust and minimum Clang requirements
created_at: 2024-12-02T15:25:04Z
author_association: MEMBER
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: An issue has been created (#7649) to track this.
created_at: 2025-01-06T10:43:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,47 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
+#pragma push_macro("_CubLog")
+#ifdef _CubLog
+#undef _CubLog
+#endif
+#define _CubLog
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#pragma pop_macro("_CubLog")
+#else
+#include <thrust/distance.h>
+#include <thrust/scan.h>
+#endif
+
+#pragma GCC diagnostic pop
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: An issue has been created (#7649) to keep track of this problem. It is expected to be resolved by release 5.0.
created_at: 2025-01-06T10:49:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: tpadioleau
body: ```suggestion
```

Is it actually needed ?
created_at: 2025-01-06T10:58:17Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: tpadioleau
body: ```suggestion
                   const Kokkos::View<const T*, exec_space>& in,
                   const Kokkos::View<T*, exec_space>& out) {
```
created_at: 2025-01-06T11:02:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: You are already checking for this in `algorithms/CMakeLists.txt`.
```suggestion
```
created_at: 2025-01-06T12:28:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: It looks like you just copied this block from `core/perf_test/CMakeLists.txt`. Have you actually checked if it's necessary here?
created_at: 2025-01-06T12:37:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
+
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: I'd prefer not to duplicate all of this but share it in a common location with `core/perf_test/CMakeLists.txt`
created_at: 2025-01-06T12:41:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: You don't have to copy the whole `View` if you only want the last element.
```suggestion
  T last_element;
  Kokkos::deep_copy(last_element, Kokkos::subview(out, out.extent(0)-1));
  return last_element;
```
created_at: 2025-01-06T12:45:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: Maybe fence before for good measure to make sure nothing else is included in the time recorded.
```suggestion
  exec_space().fence();
  // Default prefix sum scan
  Kokkos::Timer timer;
  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
```
created_at: 2025-01-06T12:47:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: Style: Use PascalCase case to denote types.
created_at: 2025-01-06T12:48:40Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: Without an explicit fence right before `timer.reset()`, this relies on `obtainLastElem` to fence (which it currently does).
created_at: 2025-01-06T12:49:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: Same here.
created_at: 2025-01-06T12:49:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: This feels out-of-place. I would rather error out if the results aren't correct.
created_at: 2025-01-06T12:51:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: If you only care about the last element, then why copy the entire view to the host.
Take a subview of the last element if the view before creating a mirror and deep copy.
created_at: 2025-01-06T12:53:20Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: Why are you printing the size of the type as a counter?
```suggestion
```
created_at: 2025-01-06T12:53:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
+}
+
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  Kokkos::View<T*, exec_space> in{"input", kProbSize};
+  Kokkos::View<T*, exec_space> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  exec_space().fence();
+  for (auto _ : state) {
+    InclusiveScan<T>(state, in, out);
+  }
+}
+
+static constexpr std::size_t PROB_SIZE  = 100'000'000;
+static constexpr std::uint32_t ITER_CNT = 100;
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->Iterations(ITER_CNT);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: Why are we forcing the number of iterations?
created_at: 2025-01-06T12:54:09Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: Where is this header used? Do you need all the others above?
created_at: 2025-01-06T12:54:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
+}
+
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  Kokkos::View<T*, exec_space> in{"input", kProbSize};
+  Kokkos::View<T*, exec_space> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  exec_space().fence();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: That fence is unnecessary
```suggestion
```
created_at: 2025-01-06T12:59:01Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: Why did you pick this approach instead of having individual benchmarks?
created_at: 2025-01-06T13:02:52Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: ```suggestion
  KOKKOS_FUNCTION
```
Same comment below
created_at: 2025-01-06T13:03:11Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: That is true. I could check by removing these conditions (one set at a time) and seeing whether it breaks the build.
created_at: 2025-01-06T13:48:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Yes, I was wondering about this. I could have asked people around, instead of committing it in a PR. Thank you.
created_at: 2025-01-06T13:50:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
+
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: I will look into this.
created_at: 2025-01-06T13:51:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I thought, the input and output views could be allocated only once and reused. Also, I saw a similar approach in `core/perf_test/test_atomic.cpp`.
created_at: 2025-01-06T13:54:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I was wondering about this. I searched for a `back()`-like function and didn't find it. I should have thought of using subview or asked people around.
created_at: 2025-01-06T13:56:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: While looking at the results, I thought this will give an idea about the size of the array involved. However, this information can be easily inferred.
created_at: 2025-01-06T14:05:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
+}
+
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  Kokkos::View<T*, exec_space> in{"input", kProbSize};
+  Kokkos::View<T*, exec_space> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  exec_space().fence();
+  for (auto _ : state) {
+    InclusiveScan<T>(state, in, out);
+  }
+}
+
+static constexpr std::size_t PROB_SIZE  = 100'000'000;
+static constexpr std::uint32_t ITER_CNT = 100;
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->Iterations(ITER_CNT);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I was doing this to check whether I got similar numbers to my earlier tests which manually ran the code for 100 iterations. Then I just left it like that, without removing it. It may be a better practice to let Google Benchmark implicitly select the number of iterations.
created_at: 2025-01-06T14:16:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I was thinking that the fence that just follows each of the calls to inclusive_scan was enough. I will fence before `timer.reset()` that precedes each inclusive_scan.
created_at: 2025-01-06T14:39:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: `<cstdint>` is for `std::uint64_t`.

Regarding `<random>`, I wanted to implement a logic to create an input array that will have random values picked randomly between 0 and N-1. But then I haven't implemented that logic yet. I wanted to implement something like `std::shuffle` by using functions in `<random>`.

I included `<cstring>`, `<cstdlib>` etc while debugging my code using parts of the logic in `core/perf_test/test_atomic.cpp`. I first implemented my benchmark code based on fixtures. However, I got errors, involving the construction/destruction of views present inside the fixture class. Then to just get something that compiles, I copy-pasted a working sub-part of `core/perf_test/test_atomic.cpp`. I didn't clean it up properly later.

In short, among the four listed above, I will retain `<cstdint>`. I will have a look at other header files also.
created_at: 2025-01-06T14:53:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
+}
+
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  Kokkos::View<T*, exec_space> in{"input", kProbSize};
+  Kokkos::View<T*, exec_space> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  exec_space().fence();
+  for (auto _ : state) {
+    InclusiveScan<T>(state, in, out);
+  }
+}
+
+static constexpr std::size_t PROB_SIZE  = 100'000'000;
+static constexpr std::uint32_t ITER_CNT = 100;
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->Iterations(ITER_CNT);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: tpadioleau
body: Yes I would also let google benchmark compute it for you. I think for that to work you will need
- a call to `state.SetIterationTime`
- a dedicated loop `for (auto _ : state)` per benchmark
created_at: 2025-01-07T08:49:41Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: tpadioleau
body: ```suggestion
  // Prefix sum scan using a sum functor
  timer.reset();
  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
                     KE::cend(in), KE::begin(out), SumFunctor<T>());
```

I don't think we need to store the functor, same for `MaxFunctor`.
created_at: 2025-01-07T08:57:38Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
+
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
path: algorithms/perf_test/CMakeLists.txt
user: login: tpadioleau
body: In the `cmake` directory ?
created_at: 2025-01-07T09:03:08Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Yes, this will also work.
created_at: 2025-01-07T09:18:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I am already reviewing the headers included in the code. Let me see which all need to be retained.
created_at: 2025-01-07T09:21:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Good point about constness propagation and Views.
created_at: 2025-01-07T09:22:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
+
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: Which is the directory that you are referring to?
created_at: 2025-01-07T09:34:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
+
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: Yes, it is a good idea to move these common functions to the root directory and make `core/perf_test`, `algorithms/perf_test` and the perf tests in the future, to refer to these common functions. This is better than making `core/perf_test` as the source of reference.
created_at: 2025-01-07T10:17:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
+  exec_space().fence();
+  double time_sum_func = timer.seconds();
+
+  T res_sum_func = obtainLastElem(out);
+
+  // Scan using a max functor
+  MaxFunctor<T> max_functor;
+
+  timer.reset();
+  KE::inclusive_scan("max functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), max_functor);
+  exec_space().fence();
+  double time_max_func = timer.seconds();
+
+  // Checking expected results
+  std::size_t res_max_func = static_cast<std::size_t>(obtainLastElem(out));
+  std::size_t exp_max_val  = in.size() - 1;
+  bool passed = (res_def == res_sum_func) && (res_max_func == exp_max_val);
+
+  state.counters["Passed"]             = benchmark::Counter(passed);
+  state.counters["Value default scan"] = benchmark::Counter(res_def);
+  state.counters["Value sum functor"]  = benchmark::Counter(res_sum_func);
+  state.counters["Value max functor"]  = benchmark::Counter(res_max_func);
+  state.counters["Time default scan"]  = benchmark::Counter(time_def);
+  state.counters["Time sum functor"]   = benchmark::Counter(time_sum_func);
+  state.counters["Time max functor"]   = benchmark::Counter(time_max_func);
+  state.counters["Size of type"]       = benchmark::Counter(sizeof(T));
+}
+
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  Kokkos::View<T*, exec_space> in{"input", kProbSize};
+  Kokkos::View<T*, exec_space> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  exec_space().fence();
+  for (auto _ : state) {
+    InclusiveScan<T>(state, in, out);
+  }
+}
+
+static constexpr std::size_t PROB_SIZE  = 100'000'000;
+static constexpr std::uint32_t ITER_CNT = 100;
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->Iterations(ITER_CNT);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Good point about manual timing and passing the measured time to `SetIterationTime` etc. I noticed this being done in some of the codes in `core/perf_test` and then I forgot about it. Since we are using `Kokkos::Timer`, properly implementing manual timing is the better approach.
created_at: 2025-01-07T10:34:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: @tpadioleau In practice, there is a correction regarding this. @dalg24 was also mentioning it. When a function template parameter has a View with const element type (i.e, Kokkos::View<const T*, ...>), it is not possible to pass a View with a non-const element type (e.g., Kokkos::View<double *, ...>). The compiler is not able to find a match. I tried this with the function `obtainLastElem` (since, the function doesn't modify the elements of the View) and faced this error.
created_at: 2025-01-09T08:59:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: tpadioleau
body: ```suggestion
                   const Kokkos::View<T*, exec_space>& in,
                   const Kokkos::View<T*, exec_space>& out) {
```

You are right the compiler cannot both make a conversion and a deduction of the template parameter. I suggest we only make the object `const`.
created_at: 2025-01-09T09:45:42Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Good point that the compiler doesn't perform both a conversion and template argument deduction at the same time. At the same time, it is not clear to me whether that alone is the reason for what is going on here.
created_at: 2025-01-09T09:56:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I will clarify my thoughts further. I have heard about not performing conversion and deduction at the same time, in the context of multiple function parameters with the same template parameter type. e.g., if one argument is `double` and the other is `int` (or one is `const int` and the other is `int`), while both function parameters are of type `T`, then a matching function will not be found. I couldn't understand well enough, how not performing conversion and deduction at the same time causes the problem in our case. For example, on compiler explorer, I tried a simple function template with a `const T` parameter. It could find a match when a non-const `double` was passed. Why is it not working out with a Kokkos View?
created_at: 2025-01-09T11:22:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: masterleinad
body: https://godbolt.org/z/eorvfcrbn would be a simple example.
created_at: 2025-01-09T13:20:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Thank you for the illustrative example.
created_at: 2025-01-09T15:27:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: There is this article: [Coercing deep const-ness](https://brevzin.github.io/c++/2021/09/10/deep-const/)

He mentions how exceptions have been made to the rule of no conversion during deduction when it comes to pointer/reference to const. For class templates like `std::span`, the rule still applies. We are facing the same issue with `Kokkos::View`. He describes how one could possibly overcome this problem. Most likely, Kokkos is already making efforts in this direction.
created_at: 2025-01-10T08:44:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: tpadioleau
body: While I understand the problem in the language I am fine with the "completely useless" `takes_generic_const_span`. The user is responsible to pass a `span<const int>`, using `views::as_const` if necessary.
created_at: 2025-01-10T09:44:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,143 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdio>
+#include <cstdint>
+#include <cstring>
+#include <cstdlib>
+#include <random>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using exec_space = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_INLINE_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, exec_space>& out) {
+  auto h_out = Kokkos::create_mirror_view(out);
+  Kokkos::deep_copy(h_out, out);
+  auto view_size = h_out.extent(0);
+  return h_out(view_size - 1);
+}
+
+template <class T>
+void InclusiveScan(benchmark::State& state,
+                   const Kokkos::View<T*, exec_space>& in,
+                   Kokkos::View<T*, exec_space>& out) {
+  // Default prefix sum scan
+  Kokkos::Timer timer;
+  KE::inclusive_scan("default scan", exec_space(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  exec_space().fence();
+  double time_def = timer.seconds();
+
+  T res_def = obtainLastElem(out);
+
+  // Prefix sum scan using a sum functor
+  SumFunctor<T> sum_functor;
+
+  timer.reset();
+  KE::inclusive_scan("sum functor scan", exec_space(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), sum_functor);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I would like to correct what I said in the earlier version of the comment. In the recent version of the code in [e7ca1e4](https://github.com/kokkos/kokkos/commit/e7ca1e490c8ce319f75e3e7d26c3fa05d4862cd7), the scan functor needs to be passed in two places (once to obtain a reference result and once to Kokkos::InclusiveScan. Thus an object of the functor has been created.
created_at: 2025-01-15T09:27:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: A FIX_ME has been added to keep track of this issue.
created_at: 2025-01-15T10:15:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
+
+if(NOT Kokkos_ENABLE_BENCHMARKS)
+  return()
+endif()
+
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
+
+  string(TIMESTAMP BENCHMARK_TIME "%Y-%m-%d_T%H-%M-%S" UTC)
+  set(BENCHMARK_ARGS --benchmark_counters_tabular=true --benchmark_out=${BENCHMARK_NAME}_${BENCHMARK_TIME}.json)
+
+  add_test(NAME ${BENCHMARK_NAME} COMMAND ${BENCHMARK_NAME} ${BENCHMARK_ARGS})
+endfunction()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: As suggested by @dalg24, refactoring such common logic should be handled in a separate PR. An issue has been created: [7670](https://github.com/kokkos/kokkos/issues/7670). Also, FIXMEs have been added in the relevant places.
created_at: 2025-01-15T10:18:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: Just try to remove these guards and see if it fails in the CI.
created_at: 2025-01-15T14:12:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,65 @@
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+  return()
+endif()
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: ping
created_at: 2025-01-16T21:47:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,69 @@
+# FIXME: These checks are from `core/perf_test/CMakeLists.txt`. Will the following backends successfully run
+# inclusive_scan and other future tests?
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+# if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+#   return()
+# endif()
+
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: ```suggestion
```
created_at: 2025-01-17T16:49:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,69 @@
+# FIXME: These checks are from `core/perf_test/CMakeLists.txt`. Will the following backends successfully run
+# inclusive_scan and other future tests?
+# FIXME_OPENMPTARGET - the NVIDIA HPC compiler nvc++ in the OpenMPTarget backend does not pass the perf_tests.
+# FIXME_OPENACC - temporarily disabled due to unimplemented features
+if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
+  return()
+endif()
+# if(KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)
+#   return()
+# endif()
+
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: I will remove these checks in the PR.
created_at: 2025-01-17T16:56:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,211 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: Rombur
body: Why are you returning `h_in`? You are not using it later on. 
created_at: 2025-01-21T15:34:03Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,211 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Thanks for your review. I did that with the intention to pass it on to the serialScan function. Then I have forgotten about it and I wrote serialScan which accepts a view in the default execution space. It will be more efficient if serialScan accepts h_in. I will rewrite serialScan.
created_at: 2025-01-21T16:02:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,211 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace = Kokkos::DefaultExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: The function serialScan has been updated. This change is outside the time measured during the perf tests. Just to be sure the perf tests were re-run for both CUDA and HIP. The numbers remain the same as expected.
created_at: 2025-01-22T11:16:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +147,62 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  std::uint64_t kpID = 0;
+  if (Kokkos::Profiling::profileLibraryLoaded()) {
+    Kokkos::Profiling::beginParallelScan(
+        label + " via thrust::inclusive_scan",
+        Kokkos::Profiling::Experimental::device_id(ex), &kpID);
+  }
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: dalg24
body: Why did you opt for this versus `{push,pop}Region()`?
created_at: 2025-02-03T12:38:29Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
path: algorithms/perf_test/CMakeLists.txt
user: login: dalg24
body: OK
If we haven't already done so please open an issue to keep track of this reorg.
created_at: 2025-02-03T12:40:58Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: Why not initialize these directly on the device?
created_at: 2025-02-03T12:44:09Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: Why static?
created_at: 2025-02-03T12:45:41Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+// Benchmark: Scan based on a functor
+template <class T, template <class> class ScanFunctor>
+void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  auto scan_functor = ScanFunctor<T>();
+
+  T res_check = serialScan<T>(h_in, scan_functor);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] =
+        InclusiveScan<T, ScanFunctor<T>>(in, out, res_check, scan_functor);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+static constexpr std::size_t PROB_SIZE = 100'000'000;
+static constexpr double WARMUP_TIME    = 0.1;  // warm up of 100 milli-seconds
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: If we want to avoid symbol collisions, the right thing to do is probably just define everything here within the anonymous namespace like we do for tests.
created_at: 2025-02-03T12:47:20Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+// Benchmark: Scan based on a functor
+template <class T, template <class> class ScanFunctor>
+void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  auto scan_functor = ScanFunctor<T>();
+
+  T res_check = serialScan<T>(h_in, scan_functor);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] =
+        InclusiveScan<T, ScanFunctor<T>>(in, out, res_check, scan_functor);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+static constexpr std::size_t PROB_SIZE = 100'000'000;
+static constexpr double WARMUP_TIME    = 0.1;  // warm up of 100 milli-seconds
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->MinWarmUpTime(WARMUP_TIME)
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: Is that something specific to that benchmark or something we would like to set globally?
created_at: 2025-02-03T12:50:53Z
author_association: MEMBER
diff_hunk: @@ -101,9 +147,62 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  std::uint64_t kpID = 0;
+  if (Kokkos::Profiling::profileLibraryLoaded()) {
+    Kokkos::Profiling::beginParallelScan(
+        label + " via thrust::inclusive_scan",
+        Kokkos::Profiling::Experimental::device_id(ex), &kpID);
+  }
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I will discuss with @masterleinad about this.
created_at: 2025-02-03T13:05:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: You could have use `std::inclusive_scan` (not blocking)
created_at: 2025-02-03T15:26:06Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+// Benchmark: Scan based on a functor
+template <class T, template <class> class ScanFunctor>
+void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  auto scan_functor = ScanFunctor<T>();
+
+  T res_check = serialScan<T>(h_in, scan_functor);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] =
+        InclusiveScan<T, ScanFunctor<T>>(in, out, res_check, scan_functor);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+static constexpr std::size_t PROB_SIZE = 100'000'000;
+static constexpr double WARMUP_TIME    = 0.1;  // warm up of 100 milli-seconds
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->MinWarmUpTime(WARMUP_TIME)
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: If not this is taking away control from the person who runs the exe and could have otherwise passed an `--benchmark_min_warmup_time`` argument
https://github.com/google/benchmark/blob/main/docs/user_guide.md#runtime-and-reporting-considerations

I assume there is even an environment variable to control this.
IMO it would be better to set it globally rather than forcing it here.
created_at: 2025-02-03T15:29:07Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+// Benchmark: Scan based on a functor
+template <class T, template <class> class ScanFunctor>
+void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  auto scan_functor = ScanFunctor<T>();
+
+  T res_check = serialScan<T>(h_in, scan_functor);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] =
+        InclusiveScan<T, ScanFunctor<T>>(in, out, res_check, scan_functor);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+static constexpr std::size_t PROB_SIZE = 100'000'000;
+static constexpr double WARMUP_TIME    = 0.1;  // warm up of 100 milli-seconds
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->MinWarmUpTime(WARMUP_TIME)
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: dalg24
body: If you add a FIXME comment saying that need to be revisited and should be apply wholesale to the full exe I am ok with merging and fixing as a follow up
created_at: 2025-02-03T15:32:54Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  # FIXME: BenchmarkMain.cpp and Benchmark_Context.cpp should be moved to a common location from which
+  # they can be used by all performance tests.
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: This alone will not work ... as it might need an architecture and standard which need to be defined on target level. But this could be marked with a FIXME as it will potentially go away with https://github.com/kokkos/kokkos/pull/7582
created_at: 2025-02-03T23:03:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: can it be called without any args?
created_at: 2025-02-03T23:03:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: why do we need this?
created_at: 2025-02-03T23:03:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: why is the name an extra arg and not in the `cmake_parse_arguments`
created_at: 2025-02-03T23:04:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: this naming does not follow your convention ... I would prefer following the convention we use in the rest of Kokkos
created_at: 2025-02-03T23:09:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: could you unify this with the non-default below? At the moment this is repeating a lot of code
created_at: 2025-02-03T23:11:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: can you unify the two tests vs repeating most of the code?
created_at: 2025-02-03T23:13:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,52 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: JBludau
body: I have a hard time understanding this comment
created_at: 2025-02-03T23:16:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,7 @@
 int main(int argc, char** argv) {
   Kokkos::initialize(argc, argv);
   benchmark::Initialize(&argc, argv);
+  // FIXME: seconds as default time unit leads to precision loss
path: core/perf_test/BenchmarkMain.cpp
user: login: JBludau
body: could you explain why you do it?
created_at: 2025-02-03T23:19:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: This file is copied from https://github.com/kokkos/kokkos/blob/develop/core/perf_test/CMakeLists.txt.
created_at: 2025-02-03T23:44:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,52 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: That's pre-existing in the sortimpl and sortbykeyimpl files.
created_at: 2025-02-03T23:45:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,7 @@
 int main(int argc, char** argv) {
   Kokkos::initialize(argc, argv);
   benchmark::Initialize(&argc, argv);
+  // FIXME: seconds as default time unit leads to precision loss
path: core/perf_test/BenchmarkMain.cpp
user: login: masterleinad
body: This is pre-existing in `core`.
created_at: 2025-02-03T23:46:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Thank you for your review comments. I also thought about the repeating codes.

One solution that I tried was a variadic template based benchmark function. In the [User Guide](https://github.com/google/benchmark/blob/main/docs/user_guide.md), there are two different ways in which benchmark function templates can be defined.
1. [variadic templates](https://github.com/google/benchmark/blob/main/docs/user_guide.md#passing-arbitrary-arguments-to-a-benchmark) that are used to pass arbitrary arguments to the benchmark function.
2. [function templates](https://github.com/google/benchmark/blob/main/docs/user_guide.md#templated-benchmarks) that are not variadic in nature, through which benchmarks for different types could be defined etc.

In my case, I need a variadic function template with a fixed first argument that is the type of the elements in the view. Google Benchmark is not allowing me to register such a function.

Update: As I revisit my attempt with variadic templates, I see that there was repeating code then also.

One other solution that I could think of was to pass a flag that indicates whether it is the default case or the case that accepts a functor. However, in this case there will always be a functor that also needs to be passed around. This functor will not be used in the default sum case. This didn't look like a nice solution.
created_at: 2025-02-04T12:51:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,52 @@
 #include <std_algorithms/Kokkos_Distance.hpp>
 #include <string>
 
+#if defined(KOKKOS_ENABLE_CUDA)
+
+// Workaround for `Instruction 'shfl' without '.sync' is not supported on
+// .target sm_70 and higher from PTX ISA version 6.4`.
+// Also see https://github.com/NVIDIA/cub/pull/170.
+#if !defined(CUB_USE_COOPERATIVE_GROUPS)
+#define CUB_USE_COOPERATIVE_GROUPS
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
+#pragma GCC diagnostic ignored "-Wsuggest-override"
+
+#if defined(KOKKOS_COMPILER_CLANG)
+// Some versions of Clang fail to compile Thrust, failing with errors like
+// this:
+//    <snip>/thrust/system/cuda/detail/core/agent_launcher.h:557:11:
+//    error: use of undeclared identifier 'va_printf'
+// The exact combination of versions for Clang and Thrust (or CUDA) for this
+// failure was not investigated, however even very recent version combination
+// (Clang 10.0.0 and Cuda 10.0) demonstrated failure.
+//
+// Defining _CubLog here locally allows us to avoid that code path, however
+// disabling some debugging diagnostics
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: An issue has been created to track this problem: https://github.com/kokkos/kokkos/issues/7649
created_at: 2025-02-04T12:53:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -24,6 +24,7 @@
 int main(int argc, char** argv) {
   Kokkos::initialize(argc, argv);
   benchmark::Initialize(&argc, argv);
+  // FIXME: seconds as default time unit leads to precision loss
path: core/perf_test/BenchmarkMain.cpp
user: login: science-enthusiast
body: Thank you for clarifying, @masterleinad.

I noticed that the output times have just one or two significant digits due to representing them in seconds. The FIXME has been added to address this problem in the future. When addressing issue [7670](https://github.com/kokkos/kokkos/issues/7670), this file (core/perf_test/BenchmarkMain.cpp) needs to be moved to a common place. At that time, this precision issue could also be addressed.
created_at: 2025-02-04T12:57:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: I will document possible questions/issues with the logic in this CMakeLists.txt in [7670](https://github.com/kokkos/kokkos/issues/7670).
created_at: 2025-02-04T13:04:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I will change the name to ref_scan and call `std::inclusive_scan` inside.
created_at: 2025-02-04T13:27:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: So you can not use ?
```
template<typename T, typename Functor = void>
Test_InclusiveScan(...)
{
if constexpr (std::is_same_v<Functor,void>)
  //default case
else
 //special case
}
```
created_at: 2025-02-04T15:16:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I will get back to you about this. This `void` based approach looks good. Thank you.
created_at: 2025-02-04T16:54:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: I just used `void` for the example. You can also create something like a tag with a more expressive name
created_at: 2025-02-04T19:24:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I see your point that a more expressive type will work as well. The approach is about having a default type (void or empty class as a tag) that will indicate that no functor was passed.
created_at: 2025-02-04T19:46:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: It is being tracked in issue [7670](https://github.com/kokkos/kokkos/issues/7670).
created_at: 2025-02-05T10:39:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: The input array is needed both on the device (where it is passed to Kokkos::inclusive_scan) and on the host (where it is passed to a reference implementation of inclusive_scan). Thus there is both a `h_in` and `h_out`.
created_at: 2025-02-05T10:41:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: It can be called with just one argument that corresponds to NAME.
created_at: 2025-02-05T11:24:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: but this would not really create anything helpful would it?
created_at: 2025-02-06T15:38:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  # FIXME: BenchmarkMain.cpp and Benchmark_Context.cpp should be moved to a common location from which
+  # they can be used by all performance tests.
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: Did you copy this from somewhere?
How it is now it does nothing for `CXX` and not enough for any other language.
created_at: 2025-02-06T15:40:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  # FIXME: BenchmarkMain.cpp and Benchmark_Context.cpp should be moved to a common location from which
+  # they can be used by all performance tests.
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
path: algorithms/perf_test/CMakeLists.txt
user: login: masterleinad
body: The whole file is copied from https://github.com/kokkos/kokkos/blob/develop/core/perf_test/CMakeLists.txt
created_at: 2025-02-06T15:50:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  # FIXME: BenchmarkMain.cpp and Benchmark_Context.cpp should be moved to a common location from which
+  # they can be used by all performance tests.
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
path: algorithms/perf_test/CMakeLists.txt
user: login: JBludau
body: ok, in this case I am fine with the FIXME
created_at: 2025-02-06T15:52:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: I have added a FIXME to consider making NAME a one_value_argument for cmake_parse_arguments.
created_at: 2025-02-06T16:09:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
+  cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN})
+  if(DEFINED BENCHMARK_UNPARSED_ARGUMENTS)
+    message(WARNING "Unexpected arguments when adding a benchmark: " ${BENCHMARK_UNPARSED_ARGUMENTS})
+  endif()
+
+  set(BENCHMARK_NAME Kokkos_${NAME})
+  # FIXME: BenchmarkMain.cpp and Benchmark_Context.cpp should be moved to a common location from which
+  # they can be used by all performance tests.
+  list(APPEND BENCHMARK_SOURCES ../../core/perf_test/BenchmarkMain.cpp ../../core/perf_test/Benchmark_Context.cpp)
+
+  add_executable(${BENCHMARK_NAME} ${BENCHMARK_SOURCES})
+  target_link_libraries(${BENCHMARK_NAME} PRIVATE benchmark::benchmark Kokkos::kokkos impl_git_version)
+  target_include_directories(${BENCHMARK_NAME} SYSTEM PRIVATE ${benchmark_SOURCE_DIR}/include)
+
+  foreach(SOURCE_FILE ${BENCHMARK_SOURCES})
+    set_source_files_properties(${SOURCE_FILE} PROPERTIES LANGUAGE ${KOKKOS_COMPILE_LANGUAGE})
+  endforeach()
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: :)
created_at: 2025-02-06T16:12:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,58 @@
+# FIXME: The following logic should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt` in the form of a macro
+# Find or download google/benchmark library
+find_package(benchmark QUIET 1.5.6)
+if(benchmark_FOUND)
+  message(STATUS "Using google benchmark found in ${benchmark_DIR}")
+else()
+  message(STATUS "No installed google benchmark found, fetching from GitHub")
+  include(FetchContent)
+  set(BENCHMARK_ENABLE_TESTING OFF)
+
+  list(APPEND CMAKE_MESSAGE_INDENT "[benchmark] ")
+  FetchContent_Declare(
+    googlebenchmark
+    DOWNLOAD_EXTRACT_TIMESTAMP FALSE
+    URL https://github.com/google/benchmark/archive/refs/tags/v1.7.1.tar.gz
+    URL_HASH MD5=0459a6c530df9851bee6504c3e37c2e7
+  )
+  FetchContent_MakeAvailable(googlebenchmark)
+  list(POP_BACK CMAKE_MESSAGE_INDENT)
+
+  # Suppress clang-tidy diagnostics on code that we do not have control over
+  if(CMAKE_CXX_CLANG_TIDY)
+    set_target_properties(benchmark PROPERTIES CXX_CLANG_TIDY "")
+  endif()
+
+  target_compile_options(benchmark PRIVATE -w)
+  target_compile_options(benchmark_main PRIVATE -w)
+endif()
+
+# FIXME: This function should be moved from here and also from `core/perf_test/CMakeLists.txt` to
+# the root `CMakeLists.txt`
+function(KOKKOS_ADD_BENCHMARK NAME)
path: algorithms/perf_test/CMakeLists.txt
user: login: science-enthusiast
body: A FIXME has been added to consider this.
created_at: 2025-02-06T18:53:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+// Benchmark: Scan based on a functor
+template <class T, template <class> class ScanFunctor>
+void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  auto scan_functor = ScanFunctor<T>();
+
+  T res_check = serialScan<T>(h_in, scan_functor);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] =
+        InclusiveScan<T, ScanFunctor<T>>(in, out, res_check, scan_functor);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+static constexpr std::size_t PROB_SIZE = 100'000'000;
+static constexpr double WARMUP_TIME    = 0.1;  // warm up of 100 milli-seconds
+
+BENCHMARK(Test_InclusiveScan<std::uint64_t>)
+    ->Arg(PROB_SIZE)
+    ->MinWarmUpTime(WARMUP_TIME)
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: A FIXME comment has been added.
created_at: 2025-02-10T08:44:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+// Benchmark: Scan based on a functor
+template <class T, template <class> class ScanFunctor>
+void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  auto scan_functor = ScanFunctor<T>();
+
+  T res_check = serialScan<T>(h_in, scan_functor);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] =
+        InclusiveScan<T, ScanFunctor<T>>(in, out, res_check, scan_functor);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+static constexpr std::size_t PROB_SIZE = 100'000'000;
+static constexpr double WARMUP_TIME    = 0.1;  // warm up of 100 milli-seconds
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: The anonymous namespace based approach has been implemented.
created_at: 2025-02-10T08:45:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: As noted below, the anonymous namespace based approach has been implemented now.

created_at: 2025-02-10T08:46:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +147,62 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  std::uint64_t kpID = 0;
+  if (Kokkos::Profiling::profileLibraryLoaded()) {
+    Kokkos::Profiling::beginParallelScan(
+        label + " via thrust::inclusive_scan",
+        Kokkos::Profiling::Experimental::device_id(ex), &kpID);
+  }
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: The call to `inclusive_scan` is now enclosed by a `pushRegion()` and a `popRegion()`.
created_at: 2025-02-10T08:47:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: `std::inclusive_scan` is not available in GCC 8.4.0. The Jenkins CI has a GCC 8.4.0 based check. A detailed FIXME has been added.
created_at: 2025-02-10T10:31:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtainLastElem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepareViews(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan in a serial manner. Used as reference.
+template <class T, class ScanFunctor = SumFunctor<T>>
+T serialScan(const Kokkos::View<T*, HostExecSpace>& h_in,
+             ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Default prefix sum scan
+template <class T>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in), KE::cend(in),
+                     KE::begin(out));
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_scan == res_check);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Scan with the provided functor
+// Note: The nature of the functor must be compatible with the
+// input and output views
+template <class T, class ScanFunctor>
+auto InclusiveScan(const Kokkos::View<T*, ExecSpace>& in,
+                   const Kokkos::View<T*, ExecSpace>& out, T res_check,
+                   ScanFunctor scan_functor) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+  KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                     KE::cend(in), KE::begin(out), scan_functor);
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtainLastElem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Default (prefix sum) scan
+template <class T>
+static void Test_InclusiveScan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepareViews<T>(kProbSize);
+
+  T res_check = serialScan<T>(h_in);
+
+  for (auto _ : state) {
+    const auto [time_scan, passed] = InclusiveScan<T>(in, out, res_check);
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: Please take a look at the updated code.
created_at: 2025-02-10T10:31:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: If you use this approach, please add the regions to all the other paths `inclusive_scan` could take.
created_at: 2025-02-10T14:05:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I see your point. However, the path is a call to a function in the Thrust library. I am not sure what can be done in this case.

Or is there some other approach for profiling that is more suitable here?
created_at: 2025-02-10T16:03:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: If we don't have a special path, you would just do
```
Kokkos::Profiling::pushRegion(label + " via Kokkos::parallel_scan");
```
making sure that `label` contains `Kokkos::inclusive_scan`.
created_at: 2025-02-10T16:09:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Thank you for your quick reply. Do you mean:

`Kokkos::Profiling::pushRegion(label + " via Kokkos::inclusive_scan");`

Since this `inclusive_scan` function doesn't call `Kokkos::parallel_scan`.
created_at: 2025-02-10T16:14:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: No, I meant to add a corresponding call to the other code paths that are using `Kokkos::parallel_scan`.
created_at: 2025-02-10T16:32:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Thanks. I see your point better. I will make the change and let you know.
created_at: 2025-02-10T16:36:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+auto inclusive_scan(const Kokkos::View<T*, ExecSpace>& in,
+                    const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out));
+  } else {
+    KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out), ScanFunctor<T>());
+  }
+
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtain_last_elem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Inclusive Scan with default binary operation (sum)
+// or user provided functor
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+void BM_inclusive_scan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepare_views<T>(kProbSize);
+
+  T res_check;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    res_check = ref_scan<T>(h_in);
+  } else {
+    res_check = ref_scan<T>(h_in, ScanFunctor<T>());
+  }
+
+  double time_scan = 0.;
+  bool passed      = false;
+
+  for (auto _ : state) {
+    if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+      std::tie(time_scan, passed) = inclusive_scan<T>(in, out, res_check);
+    } else {
+      std::tie(time_scan, passed) =
+          inclusive_scan<T, ScanFunctor>(in, out, res_check);
+    }
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+constexpr std::size_t PROB_SIZE = 100'000'000;
+
+}  // anonymous namespace
+
+// FIXME: Add logic to pass min. warm-up time. Also, the value should be set
+// by the user. Say, via the environment variable BENCHMARK_MIN_WARMUP_TIME.
+
+BENCHMARK(BM_inclusive_scan<std::uint64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::int64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<double>)->Arg(PROB_SIZE)->UseManualTime();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: Do we also want to benchmark this for `float`, `half` or `complex`?
created_at: 2025-02-10T16:53:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+auto inclusive_scan(const Kokkos::View<T*, ExecSpace>& in,
+                    const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out));
+  } else {
+    KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out), ScanFunctor<T>());
+  }
+
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtain_last_elem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Inclusive Scan with default binary operation (sum)
+// or user provided functor
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+void BM_inclusive_scan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepare_views<T>(kProbSize);
+
+  T res_check;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    res_check = ref_scan<T>(h_in);
+  } else {
+    res_check = ref_scan<T>(h_in, ScanFunctor<T>());
+  }
+
+  double time_scan = 0.;
+  bool passed      = false;
+
+  for (auto _ : state) {
+    if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+      std::tie(time_scan, passed) = inclusive_scan<T>(in, out, res_check);
+    } else {
+      std::tie(time_scan, passed) =
+          inclusive_scan<T, ScanFunctor>(in, out, res_check);
+    }
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+constexpr std::size_t PROB_SIZE = 100'000'000;
+
+}  // anonymous namespace
+
+// FIXME: Add logic to pass min. warm-up time. Also, the value should be set
+// by the user. Say, via the environment variable BENCHMARK_MIN_WARMUP_TIME.
+
+BENCHMARK(BM_inclusive_scan<std::uint64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::int64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<double>)->Arg(PROB_SIZE)->UseManualTime();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: I thought about `float`. The output type, in the case of operations like sum, may have to be of higher precision. I could add a FIXME about revisiting later about types like `float`, `half` and `complex`. There is a lot of work that could be done with regards to benchmark testing of Kokkos algorithms. We could start in a small way and build on it.
created_at: 2025-02-11T13:52:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+auto inclusive_scan(const Kokkos::View<T*, ExecSpace>& in,
+                    const Kokkos::View<T*, ExecSpace>& out, T res_check) {
+  ExecSpace().fence();
+  Kokkos::Timer timer;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    KE::inclusive_scan("Default scan", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out));
+  } else {
+    KE::inclusive_scan("Scan using a functor", ExecSpace(), KE::cbegin(in),
+                       KE::cend(in), KE::begin(out), ScanFunctor<T>());
+  }
+
+  ExecSpace().fence();
+  double time_scan = timer.seconds();
+
+  T res_scan  = obtain_last_elem(out);
+  bool passed = (res_check == res_scan);
+
+  return std::make_tuple(time_scan, passed);
+}
+
+// Benchmark: Inclusive Scan with default binary operation (sum)
+// or user provided functor
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
+void BM_inclusive_scan(benchmark::State& state) {
+  const std::size_t kProbSize = state.range(0);
+
+  auto [in, out, h_in] = prepare_views<T>(kProbSize);
+
+  T res_check;
+
+  if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+    res_check = ref_scan<T>(h_in);
+  } else {
+    res_check = ref_scan<T>(h_in, ScanFunctor<T>());
+  }
+
+  double time_scan = 0.;
+  bool passed      = false;
+
+  for (auto _ : state) {
+    if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>) {
+      std::tie(time_scan, passed) = inclusive_scan<T>(in, out, res_check);
+    } else {
+      std::tie(time_scan, passed) =
+          inclusive_scan<T, ScanFunctor>(in, out, res_check);
+    }
+
+    KokkosBenchmark::report_results(state, in, 2, time_scan);
+    state.counters["Passed"] = passed;
+  }
+}
+
+constexpr std::size_t PROB_SIZE = 100'000'000;
+
+}  // anonymous namespace
+
+// FIXME: Add logic to pass min. warm-up time. Also, the value should be set
+// by the user. Say, via the environment variable BENCHMARK_MIN_WARMUP_TIME.
+
+BENCHMARK(BM_inclusive_scan<std::uint64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<std::int64_t>)->Arg(PROB_SIZE)->UseManualTime();
+BENCHMARK(BM_inclusive_scan<double>)->Arg(PROB_SIZE)->UseManualTime();
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: Sounds good to me. I would prefer an issue rather than a fixme as it might require some discussion
created_at: 2025-02-11T14:42:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Could you have a look at the updated code?
created_at: 2025-02-12T15:49:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: It would if you wouldn't squash all the commits so it's easier to review changes to the pull request. 🙂 
created_at: 2025-02-12T15:52:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Sorry about that. I will try to do it differently going forward. The changes are regarding the addition of push and pop regions to all the inclusive_scan functions.
created_at: 2025-02-12T15:56:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -101,9 +148,48 @@ struct InclusiveScanDefaultFunctor {
   }
 };
 
-//
-// exespace impl
-//
+// -------------------------------------------------------------
+// inclusive_scan_default_op_exespace_impl
+// -------------------------------------------------------------
+
+#if defined(KOKKOS_ENABLE_CUDA)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
+
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
+
+  Kokkos::Profiling::popRegion();
+
+  const auto num_elements = thrust::distance(first_from, last_from);
+
+  return first_dest + num_elements;
+}
+#endif
+
+#if defined(KOKKOS_ENABLE_ROCTHRUST)
+template <class InputIteratorType, class OutputIteratorType>
+OutputIteratorType inclusive_scan_default_op_exespace_impl(
+    const std::string& label, const HIP& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
+  const auto thrust_ex = thrust::hip::par.on(ex.hip_stream());
+
+  Kokkos::Profiling::pushRegion(label + " via thrust::inclusive_scan");
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I also thought that since the changes are small, it will not be difficult for the reviewer.
created_at: 2025-02-13T10:20:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: Revert the changes to the team implementation.
created_at: 2025-02-13T12:41:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: Sorry, I should have caught this.
created_at: 2025-02-13T13:51:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I would like to know how you got the output of the compilation error that you pasted above. I am able to get that error output by building the code locally. I don't see it in the logs of the failed CIs.
created_at: 2025-02-13T14:18:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: You squashed again which makes it much harder to find the results from the previous run. In any case, I saw this in the GitLab CI. For the last commit, the CI results can be found at https://gitlab.spack.io/kokkos/kokkos/-/pipelines/980661.
created_at: 2025-02-13T14:46:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I am sorry if squashing is an inconvenience now also. I keep thinking that this PR is nearing its completion with small changes being made each time and it is a good idea to rebase and be ready to merge.

Thanks for telling me how to dig into the error. I did look into all the three gitlab CI failures. In all cases , the logs showed that there was one failed test. I couldn't dig deeper. I will see how to do it, the next time, I face errors.
created_at: 2025-02-13T14:54:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: masterleinad
body: > I am sorry if squashing is an inconvenience now also. I keep thinking that this PR is nearing its completion with small changes and it is a good idea to rebase and be ready to merge.

We normally squash commits while merging anyway.
created_at: 2025-02-13T14:56:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I found this article: https://jacobtomlinson.dev/posts/2022/dont-prematurely-squash/rebase-and-force-push-your-prs/

I suppose Kokkos is taking the same approach.
created_at: 2025-02-13T15:28:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: JBludau
body: I am with @masterleinad here. Recently had a similar discussion with @romintomasetti. IMHO it makes sense to just add commits and think about rewriting history before merging if it gets too messy
created_at: 2025-02-13T16:36:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -247,10 +391,16 @@ KOKKOS_FUNCTION OutputIteratorType inclusive_scan_default_op_team_impl(
   // run
   const auto num_elements =
       Kokkos::Experimental::distance(first_from, last_from);
+
+  Kokkos::Profiling::pushRegion(
+      "Kokkos::inclusive_scan via TeamPolicy and Kokkos::parallel_scan");
+
   ::Kokkos::parallel_scan(TeamThreadRange(teamHandle, 0, num_elements),
                           func_type(first_from, first_dest));
   teamHandle.team_barrier();
 
+  Kokkos::Profiling::popRegion();
+
path: algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp
user: login: science-enthusiast
body: I also see the merit in making the process easier for the reviewers.
created_at: 2025-02-13T16:40:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: Since you never use the default for `ScanFunctor` I would remove it to make it more expressive. (Non-blocking)
created_at: 2025-03-03T15:19:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: science-enthusiast
body: The default type `ImpSumBinOp` for `ScanFunctor` is used in this check `if constexpr (std::is_same_v<ScanFunctor<T>, ImpSumBinOp<T>>)` when only the parameter `T` is specified when calling `inclusive_scan`.
created_at: 2025-03-03T15:46:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,191 @@
+//@HEADER
+// ************************************************************************
+//
+//                        Kokkos v. 4.0
+//       Copyright (2022) National Technology & Engineering
+//               Solutions of Sandia, LLC (NTESS).
+//
+// Under the terms of Contract DE-NA0003525 with NTESS,
+// the U.S. Government retains certain rights in this software.
+//
+// Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions.
+// See https://kokkos.org/LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//@HEADER
+
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <type_traits>
+
+#include <benchmark/benchmark.h>
+
+#include <Kokkos_Core.hpp>
+#include <Kokkos_Timer.hpp>
+#include <Kokkos_StdAlgorithms.hpp>
+// FIXME: Benchmark_Context.hpp should be moved to a common location
+#include "../../core/perf_test/Benchmark_Context.hpp"
+
+namespace {
+
+namespace KE = Kokkos::Experimental;
+
+using ExecSpace     = Kokkos::DefaultExecutionSpace;
+using HostExecSpace = Kokkos::DefaultHostExecutionSpace;
+
+// A tag struct to identify when inclusive scan with the implicit sum
+// based binary operation needs to be called.
+template <class ValueType>
+struct ImpSumBinOp;
+
+template <class ValueType>
+struct SumFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    return (a + b);
+  }
+};
+
+template <class ValueType>
+struct MaxFunctor {
+  KOKKOS_FUNCTION
+  ValueType operator()(const ValueType& a, const ValueType& b) const {
+    if (a > b)
+      return a;
+    else
+      return b;
+  }
+};
+
+// Helper to obtain last element of a view
+template <class T>
+T obtain_last_elem(const Kokkos::View<T*, ExecSpace>& v) {
+  T last_element;
+  Kokkos::deep_copy(last_element, Kokkos::subview(v, v.extent(0) - 1));
+  return last_element;
+}
+
+// Helper to allocate input and output views
+template <class T>
+auto prepare_views(const std::size_t kProbSize) {
+  Kokkos::View<T*, ExecSpace> in{"input", kProbSize};
+  Kokkos::View<T*, ExecSpace> out{"output", kProbSize};
+
+  auto h_in = Kokkos::create_mirror_view(in);
+
+  for (std::size_t i = 0; i < kProbSize; ++i) {
+    h_in(i) = i;
+  }
+
+  Kokkos::deep_copy(in, h_in);
+
+  return std::make_tuple(in, out, h_in);
+}
+
+// Perform scan with a reference implementation
+template <class T, class ViewType, class ScanFunctor = SumFunctor<T>>
+T ref_scan(const ViewType& h_in, ScanFunctor scan_functor = ScanFunctor()) {
+  std::size_t view_size = h_in.extent(0);
+
+  Kokkos::View<T*, HostExecSpace> h_out("output", view_size);
+
+  // FIXME: We have GCC 8.4.0 based check in our ORNL Jenkins CI.
+  // std::inclusive_scan is available only from GCC 9.3. Since, GCC 9.1
+  // std::inclusive_scan that takes execution policy is available. However,
+  // there is error with <execution> header before GCC 10.1.
+  h_out(0) = h_in(0);
+
+  for (std::size_t i = 1; i < view_size; ++i) {
+    h_out(i) = scan_functor(h_in(i), h_out(i - 1));
+  }
+
+  return h_out(view_size - 1);
+}
+
+// Inclusive Scan with default binary operation (sum) or user provided functor
+// Note: The nature of the functor must be compatible with the
+// elements in the input and output views
+template <class T, template <class> class ScanFunctor = ImpSumBinOp>
path: algorithms/perf_test/test_inclusive_scan.cpp
user: login: JBludau
body: Oh, my bad. You actually use this in line 171-173. I just looked at the later invocations
created_at: 2025-03-03T16:04:54Z
author_association: CONTRIBUTOR

PR comments:
user: login: science-enthusiast
created_at: 2024-11-22T14:10:09Z
body: Fixes #6838.

In that issue, only performance difference with respect to inclusive_scan was reported. Hence, this PR addresses only inclusive_scan. However, as highlighted [here](https://github.com/kokkos/kokkos/pull/7542#issuecomment-2511843719), future investigation on exclusive_scan also will be good to do.
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2024-11-22T14:16:54Z
body: You'll have to fix the formatting:
```diff
--- ./algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp	(original)
+++ ./algorithms/src/std_algorithms/impl/Kokkos_InclusiveScan.hpp	(reformatted)
@@ -149,9 +149,8 @@
 #if defined(KOKKOS_ENABLE_CUDA)
 template <class InputIteratorType, class OutputIteratorType>
 OutputIteratorType inclusive_scan_default_op_exespace_impl(
-    const std::string& label, const Cuda& ex,
-    InputIteratorType first_from, InputIteratorType last_from,
-    OutputIteratorType first_dest) {
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest) {
   const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
 
   thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest);
@@ -204,17 +203,16 @@
 // -------------------------------------------------------------
 
 #if defined(KOKKOS_ENABLE_CUDA)
-template <class InputIteratorType, class OutputIteratorType,
-	  class BinaryOpType>
+template <class InputIteratorType, class OutputIteratorType, class BinaryOpType>
 OutputIteratorType inclusive_scan_custom_binary_op_exespace_impl(
-    const std::string& label, const Cuda& ex,
-    InputIteratorType first_from, InputIteratorType last_from,
-    OutputIteratorType first_dest, BinaryOpType binary_op) {
+    const std::string& label, const Cuda& ex, InputIteratorType first_from,
+    InputIteratorType last_from, OutputIteratorType first_dest,
+    BinaryOpType binary_op) {
   const auto thrust_ex = thrust::cuda::par.on(ex.cuda_stream());
 
-  thrust::inclusive_scan(thrust_ex, first_from, last_from,
-		         first_dest, binary_op);
- 
+  thrust::inclusive_scan(thrust_ex, first_from, last_from, first_dest,
+                         binary_op);
+
   const auto num_elements = thrust::distance(first_from, last_from);
 
   return first_dest + num_elements;
```

> thrust::inclusive_scan - sum (functor) Time taken: 5460 us
> thrust::inclusive_scan - max (functor) Time taken: 6165 us
>
> With modified Kokkos (calling thrust::inclusive_scan):
>
> KE::inclusive_scan - sum (functor) - time taken: 4667 us
> KE::inclusive_scan - max (functor) - time taken: 2683 us

How do you explain that you are observing `Kokkos` to be faster if it's calling `thrust::inclusive_scan`?
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2024-11-22T14:24:22Z
body: @masterleinad Yes, I am working on the formatting errors.

Regarding the performance numbers. The only reason that I can think of is that these numbers are based on a single run of the scan in each of the cases. I could use Google Benchmark and report those numbers.


author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2024-11-22T14:31:55Z
body: > I could use Google Benchmark and report those numbers.

Or just run the benchmark 100 times or so manually.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2024-11-22T18:45:34Z
body: Average time taken over 100 runs.

Kokkos::Experimental::inclusive_scan calling Kokkos::parallel_scan in the backend
KE::inclusive_scan - sum (default) - avg. time: 4945 us
KE::inclusive_scan - sum (functor) - avg. time: 9394 us
KE::inclusive_scan - max (functor) - avg. time: 9415 us

Kokkos::Experimental::inclusive_scan calling thrust::inclusive_scan in the backend
KE::inclusive_scan - sum (default) - avg. time: 2399 us
KE::inclusive_scan - sum (functor) - avg. time: 2514 us
KE::inclusive_scan - max (functor) - avg. time: 2321 us

thrust::inclusive_scan
thrust::inclusive_scan - sum (default) - avg. time: 2102 us
thrust::inclusive_scan - sum (functor) - avg. time: 1735 us
thrust::inclusive_scan - max (functor) - avg. time: 1810 us

Calling Kokkos::parallel_scan directly with a summation based functor
Kokkos::parallel_scan - sum functor - avg. time: 3405 us
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2024-11-26T14:22:59Z
body: @tpadioleau 

Here are the codes as .txt files. Don't mind the WET-ness in the code.
[test_in_scan_avg_cpp.txt](https://github.com/user-attachments/files/17920904/test_in_scan_avg_cpp.txt)
[test_thrust_avg_cu.txt](https://github.com/user-attachments/files/17920905/test_thrust_avg_cu.txt)

Sure, I will get back to you with the benchmarks for the case that directly calls thrust::inclusive_scan:
- by creating an input device_vector (and not using the counting iterators).
- with functors having const refer parameters. Const ref parameters are needed by Kokkos. Otherwise, matching instances of functions via template argument deduction are not being found.
author_association: CONTRIBUTOR
user: login: dalg24
created_at: 2024-12-02T15:26:32Z
body: Please briefly discuss in the description the status of exclusive_scan
author_association: MEMBER
user: login: science-enthusiast
created_at: 2024-12-05T14:03:55Z
body: Results generated after ensuring that in all cases:
- the input is a device_vector of ints.
- the binary operator functor takes its parameters by const reference.

These results have to be compared with those given [here](https://github.com/kokkos/kokkos/pull/7542#issuecomment-2494521173). As pointed out by @tpadioleau [here](https://github.com/kokkos/kokkos/pull/7542#pullrequestreview-2461629886), in that case, the code directly calling thrust::inclusive_scan took the inputs based on counting_iterators (and not device vectors) and the parameters in the binary operator functor were passed by value and not const reference.

Average time taken over 100 runs

Kokkos::Experimental::inclusive_scan calling Kokkos::parallel_scan in the backend
KE::inclusive_scan - sum (default) - avg. time: 4993 us
KE::inclusive_scan - sum (functor) - avg. time: 9392 us
KE::inclusive_scan - max (functor) - avg. time: 9390 us

Kokkos::Experimental::inclusive_scan calling thrust::inclusive_scan in the backend
KE::inclusive_scan - sum (default) - avg. time: 3359 us
KE::inclusive_scan - sum (functor) - avg. time: 4518 us
KE::inclusive_scan - max (functor) - avg. time: 3395 us

thrust::inclusive_scan
thrust::inclusive_scan - sum (default) - avg. time: 3240 us
thrust::inclusive_scan - sum (functor) - avg. time: 2327 us
thrust::inclusive_scan - max (functor) - avg. time: 2789 us

Kokkos::parallel_scan - sum functor - avg. time: 3396 us

Observation:
- Calling thrust::inclusive_scan directy is generally more efficient.
- thrust::inclusive_scan taking the input as a device_vector is slower compared to counting_iterators.

The codes used:
[test-thrust-avg_cu.txt](https://github.com/user-attachments/files/18024266/test-thrust-avg_cu.txt)
[test-in-scan-avg_cpp.txt](https://github.com/user-attachments/files/18024267/test-in-scan-avg_cpp.txt)
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2024-12-05T14:12:11Z
body: Hi @dalg24
A separate PR would be needed to implement a set of perf tests (similar to the tests in `core/perf_tests`) based on Google Benchmark.
Would it be ok, to first work on merging the current PR and then work on the PR for the perf test or should the perf test be ready first?
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2024-12-05T14:32:45Z
body: ```
Kokkos::Experimental::inclusive_scan calling thrust::inclusive_scan in the backend
KE::inclusive_scan - sum (default) - avg. time: 3359 us
KE::inclusive_scan - sum (functor) - avg. time: 4518 us
KE::inclusive_scan - max (functor) - avg. time: 3395 us

thrust::inclusive_scan
thrust::inclusive_scan - sum (default) - avg. time: 3240 us
thrust::inclusive_scan - sum (functor) - avg. time: 2327 us
thrust::inclusive_scan - max (functor) - avg. time: 2789 us
```
Can you explain these discrepancies, particularly in the second case? What do you see running NSight?
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2024-12-05T14:37:03Z
body: > Can you explain these discrepancies, particularly in the second case? What do you see running NSight?

@masterleinad, I am also surprised by the second case (sum scan using a functor).

"I have rerun the test and get similar numbers." I will take this back. After running a few more times, the numbers are not stable. There are times when calling thrust::inclusive_scan directly can do slightly worse and calling thrust::inclusive_scan indirectly can be slightly better.

I will generate numbers using Google Benchmark. That will be anyway useful in a future PR involving a perf_test directory for algorithms that will have performance tests for inclusive_scan to start with.

I haven't analysed with NSight. I will come back on this.
author_association: CONTRIBUTOR
user: login: cedricchevalier19
created_at: 2024-12-05T14:43:02Z
body: Can you have more data than just the average (like min, max, std)? Experiments are long enough to be meaningful even if run one by one.
author_association: MEMBER
user: login: science-enthusiast
created_at: 2025-01-06T10:47:10Z
body: > Why only CUDA? What about rocThrust? What's the difference there?

2 functions have been added to called thrust::inclusive_scan when using HIP backend.
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-01-06T13:11:02Z
body: Do you have some more performance results for `NVIDIA` and `AMD` GPUs?
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-06T14:07:37Z
body: > Do you have some more performance results for `NVIDIA` and `AMD` GPUs?

I am in the process of obtaining results on an AMD GPU. I will share both Nvidia and AMD results soon.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-15T14:34:20Z
body: > I still don't see new performance results.

Yes, I am on it. I have numbers for CUDA. I need to access a super computer (Adastra) to run on an AMD GPU. I have been facing some issues (mainly administrative) as a first time user of Adastra. But as of now, I have managed to build Kokkos for HIP backend (but some warnings have come. Hopefully, it should not be a problem). I will be submitting a SLURM script soon.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-16T10:58:12Z
body: Common settings:
Input size: 100000000
min_warmup_time: 0.1 seconds
time measured using manual_time (i.e., Kokkos::Timer)

The time resolution is set as seconds in the custom benchmark main function in `core/perf_test/BenchmarkMain.cpp`. Thus there is a loss in significant digits in the time. A FIXME has been added to see whether this can be removed in a future PR.

With Nvidia V100:
Benchmark$`~~~~~~~~~~~~~~~~~~~~~~~~~`$Time$`~~~~~~~~`$CPU$`~~~`$Iterations$`~~~~~~`$UserCounters...
std::uint64_t$`~~~~~~~~~~~~~~~~~~~~`$0.003 s$`~~~~~~`$0.002 s$`~~~`$234$`~`$FOM: GB/s=636.203/s MB=1.6k Passed=1
std::int64_t$`~~~~~~~~~~~~~~~~~~~~`$0.002 s$`~~~~~~~`$0.002 s$`~~~`$247$`~`$FOM: GB/s=654.122/s MB=1.6k Passed=1
double$`~~~~~~~~~~~~~~~~~~~~~~~~~`$0.003 s$`~~~~~~`$0.002 s$`~~~`$264$`~`$FOM: GB/s=514.215/s MB=1.6k Passed=1
std::uint64_t, SumFunctor$`~~`$0.003 s$`~~`$0.002 s$`~~~`$286$`~`$FOM: GB/s=613.193/s MB=1.6k Passed=1
std::int64_t, SumFunctor$`~~`$0.003 s$`~~`$0.002 s$`~~~`$260$`~`$FOM: GB/s=596.954/s MB=1.6k Passed=1
double, SumFunctor$`~~~~~~~~~`$0.003 s$`~~`$0.002 s$`~~~`$232$`~`$FOM: GB/s=618.953/s MB=1.6k Passed=1
std::uint64_t, MaxFunctor$`~~`$0.003 s$`~~`$0.002 s$`~~~`$279$`~`$FOM: GB/s=607.155/s MB=1.6k Passed=1
std::int64_t, MaxFunctor$`~~~~`$0.002 s$`~~`$0.002 s$`~~~`$213$`~`$FOM: GB/s=645.614/s MB=1.6k Passed=1
double, MaxFunctor$`~~~~~~~~~~~`$0.003 s$`~~`$0.002 s$`~~~`$209$`~`$FOM: GB/s=500.297/s MB=1.6k Passed=1

With AMD MI300A:
Benchmark$`~~~~~~~~~~~~~~~~~~~~~~~~~`$Time$`~~~~~~~~`$CPU$`~~~`$Iterations$`~~~~~~`$UserCounters...
std::uint64_t$`~~~~~~~~~~~~~~~~~~~~`$0.001 s$`~~~~~~`$0.001 s$`~~~`$692$`~`$FOM: GB/s=1.58853k/s MB=1.6k Passed=1
std::int64_t$`~~~~~~~~~~~~~~~~~~~~`$0.001 s$`~~~~~~`$0.001 s$`~~~`$691$`~`$FOM: GB/s=1.58809k/s MB=1.6k Passed=1
double$`~~~~~~~~~~~~~~~~~~~~~~~~~`$0.001 s$`~~~~~~`$0.001 s$`~~~`$692$`~`$FOM: GB/s=1.59124k/s MB=1.6k Passed=1
std::uint64_t, SumFunctor$`~~`$0.001 s$`~`$0.001 s$`~~~`$692$`~`$FOM: GB/s=1.58757k/s MB=1.6k Passed=1
std::int64_t, SumFunctor$`~~`$0.001 s$`~`$0.001 s$`~~~`$691$`~`$FOM: GB/s=1.58822k/s MB=1.6k Passed=1
double, SumFunctor$`~~~~~~~~~`$0.001 s$`~`$0.001 s$`~~~`$688$`~`$FOM: GB/s=1.59125k/s MB=1.6k Passed=1
std::uint64_t, MaxFunctor$`~~`$0.001 s$`~`$0.001 s$`~~~`$692$`~`$FOM: GB/s=1.59091k/s MB=1.6k Passed=1
std::int64_t, MaxFunctor$`~~~~`$0.001 s$`~`$0.001 s$`~~~`$693$`~`$FOM: GB/s=1.59023k/s MB=1.6k Passed=1
double, MaxFunctor$`~~~~~~~~~~~`$0.001 s$`~`$0.001 s$`~~~`$691$`~`$FOM: GB/s=1.5864k/s MB=1.6k Passed=1
CC: @masterleinad 
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-16T13:01:33Z
body: Common settings:
Input size: 1e8
min_warmup_time: 0.1 seconds
time measured using manual_time (i.e., Kokkos::Timer)

The time resolution is set as seconds in the custom benchmark main function in `core/perf_test/BenchmarkMain.cpp`. Thus there is a loss in significant digits in the time. A FIXME has been added to see whether this can be removed in a future PR.

With Nvidia V100:
|Benchmark | Time | CPU | Iterations | UserCounters...|
| --- | --- | --- | --- | --- |
| std::uint64_t | 0.003 s | 0.002 s | 234 | FOM: GB/s=636.203/s MB=1.6k Passed=1 |
| std::int64_t | 0.002 s | 0.002 s | 247 | FOM: GB/s=654.122/s MB=1.6k Passed=1 |
| double | 0.003 s | 0.002 s | 264 | FOM: GB/s=514.215/s MB=1.6k Passed=1 |
| std::uint64_t, SumFunctor | 0.003 s | 0.002 s | 286 | FOM: GB/s=613.193/s MB=1.6k Passed=1 |
| std::int64_t, SumFunctor | 0.003 s | 0.002 s | 260 | FOM: GB/s=596.954/s MB=1.6k Passed=1 |
| double, SumFunctor | 0.003 s | 0.002 s | 232 | FOM: GB/s=618.953/s MB=1.6k Passed=1 |
std::uint64_t, MaxFunctor | 0.003 s | 0.002 s | 279 | FOM: GB/s=607.155/s MB=1.6k Passed=1
std::int64_t, MaxFunctor | 0.002 s | 0.002 s | 213 | FOM: GB/s=645.614/s MB=1.6k Passed=1 |
double, MaxFunctor | 0.003 s | 0.002 s | 209 | FOM: GB/s=500.297/s MB=1.6k Passed=1 |

With AMD MI300A:
|Benchmark | Time | CPU | Iterations | UserCounters...|
| --- | --- | --- | --- | --- |
| std::uint64_t | 0.001 s | 0.001 s | 692 | FOM: GB/s=1.58853k/s MB=1.6k Passed=1
| std::int64_t | 0.001 s | 0.001 s | 691 | FOM: GB/s=1.58809k/s MB=1.6k Passed=1
| double | 0.001 s | 0.001 s | 692 | FOM: GB/s=1.59124k/s MB=1.6k Passed=1
| std::uint64_t, SumFunctor | 0.001 s | 0.001 s | 692 | FOM: GB/s=1.58757k/s MB=1.6k Passed=1
| std::int64_t, SumFunctor | 0.001 s | 0.001 s | 691 | FOM: GB/s=1.58822k/s MB=1.6k Passed=1
| double, SumFunctor | 0.001 s | 0.001 s | 688 | FOM: GB/s=1.59125k/s MB=1.6k Passed=1
| std::uint64_t, MaxFunctor | 0.001 s | 0.001 s | 692 | FOM: GB/s=1.59091k/s MB=1.6k Passed=1
| std::int64_t, MaxFunctor | 0.001 s | 0.001 s | 693 | FOM: GB/s=1.59023k/s MB=1.6k Passed=1
| double, MaxFunctor | 0.001 s | 0.001 s | 691 | FOM: GB/s=1.5864k/s MB=1.6k Passed=1

CC: @masterleinad 
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-01-16T13:06:41Z
body: What do the results look like before this pull request?
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-16T15:17:25Z
body: > What do the results look like before this pull request?

Calling current Kokkos::InclusiveScan

V100:

|Benchmark | Time | CPU | Iterations | UserCounters...
| --- | --- | --- | --- | --- |
| std::uint64_t | 0.005 s | 0 .005 s | 133 | FOM: GB/s=327.386/s MB=1.6k Passed=1
| std::int64_t | 0.005 s | 0 .005 s | 144 | FOM: GB/s=329.289/s MB=1.6k Passed=1
| double |       0.005 s | 0 .005 s | 146 | FOM: GB/s=334.165/s MB=1.6k Passed=1
| std::uint64_t, SumFunctor | 0.009 s | 0 .009 s | 75 | FOM: GB/s=170.522/s MB=1.6k Passed=1
| std::int64_t, SumFunctor | 0.009 s | 0 .009 s | 75 | FOM: GB/s=170.474/s MB=1.6k Passed=1
| double, SumFunctor | 0.009 s | 0 .009 s | 70 | FOM: GB/s=175.033/s MB=1.6k Passed=1
| std::uint64_t, MaxFunctor | 0.009 s | 0 .009 s | 75 | FOM: GB/s=170.425/s MB=1.6k Passed=1
| std::int64_t, MaxFunctor | 0.009 s | 0 .009 s | 75 | FOM: GB/s=170.57/s MB=1.6k Passed=1
| double, MaxFunctor | 0.009 s | 0 .009 s | 78 | FOM: GB/s=177.591/s MB=1.6k Passed=1

MI300A:

|Benchmark | Time | CPU | Iterations | UserCounters... |
| --- | --- | --- | --- | --- |
| std::uint64_t | 0.002 s | 0.002 s |  336 | FOM: GB/s=771.493/s MB=1.6k Passed=1
std::int64_t | 0.002 s | 0.002 s |  336 | FOM: GB/s=774.932/s MB=1.6k Passed=1
double | 0.002 s | 0.002 s |  331 | FOM: GB/s=766.541/s MB=1.6k Passed=1
std::uint64_t, SumFunctor | 0.003 s | 0.003 s |  259 | FOM: GB/s=597.217/s MB=1.6k Passed=1
std::int64_t, SumFunctor | 0.003 s | 0.003 s |  259  | FOM: GB/s=596.056/s MB=1.6k Passed=1
double, SumFunctor | 0.003 s | 0.003 s |  259 | FOM: GB/s=596.435/s MB=1.6k Passed=1
std::uint64_t, MaxFunctor | 0.003 s | 0.003 s |  261 | FOM: GB/s=601.272/s MB=1.6k Passed=1
std::int64_t, MaxFunctor | 0.003 s | 0.003 s |  261 | FOM: GB/s=602.092/s MB=1.6k Passed=1
double, MaxFunctor | 0.003 s | 0.003 s |  261 | FOM: GB/s=599.855/s MB=1.6k Passed=1

cc: @masterleinad 
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-17T12:34:12Z
body: If the following check is removed inside `CMakeLists.txt` within `algorithms/perf_test`, then there are failures in CI.
```
if((KOKKOS_ENABLE_OPENMPTARGET OR KOKKOS_ENABLE_OPENACC) AND KOKKOS_CXX_COMPILER_ID STREQUAL NVHPC)
   return()
endif()
```
The failure cases are:
linux-x64 / CI (fedora:latest, clang++, Debug, OPENMP, -DCMAKE_CXX_CLANG_TIDY="clang-tidy;-warnings-as-errors...
linux-x64 / CI (fedora:latest, clang++, Release, OPENMP, -DCMAKE_CXX_CLANG_TIDY="clang-tidy;-warnings-as-erro...
linux-x64 / CI (fedora:latest, g++, Debug, OPENMP, -DCMAKE_CXX_CLANG_TIDY="clang-tidy;-warnings-as-errors=\*",...
linux-x64 / CI (fedora:latest, g++, Release, OPENMP, -DCMAKE_CXX_CLANG_TIDY="clang-tidy;-warnings-as-errors=\*...

The four failures happen even after re-running them. All the four failures are of the same nature and concern Google Benchmark. The text from all the four cases are as follows: [clang++_debug_openmp.txt](https://github.com/user-attachments/files/18454352/clang%2B%2B_debug_openmp.txt), [clang++_release_openmp.txt](https://github.com/user-attachments/files/18454354/clang%2B%2B_release_openmp.txt), [g++_debug_openmp.txt](https://github.com/user-attachments/files/18454355/g%2B%2B_debug_openmp.txt), [g++_release_openmp.txt](https://github.com/user-attachments/files/18454356/g%2B%2B_release_openmp.txt)
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-01-17T12:42:21Z
body: > If the following check is removed inside `CMakeLists.txt` within `algorithms/perf_test`, then there are failures in CI.

That doesn't make sense. None of these builds use `nvhpc` as the compiler.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-17T12:53:15Z
body: > > If the following check is removed inside `CMakeLists.txt` within `algorithms/perf_test`, then there are failures in CI.
> 
> That doesn't make sense. None of these builds use `nvhpc` as the compiler.

Yes, I also noticed that. The CI is running now with the check (KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang) removed. Let us see what happens. Then I will also run CI with both the checks in place, as before and see whether CI passes as it used to.
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-01-17T13:07:31Z
body: Note that the jenkins build was fine and that's the only one using `nvhpc` (as host compiler). `KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)` isn't tested in the CI. I would just remove all the checks and get a verbpse log if the problem in the `GitHub` CI persists.
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-01-17T13:12:11Z
body: The fedora containers has a recent update, see https://github.com/kokkos/ci-containers/pkgs/container/ci-containers%2Ffedora. I woulnd't be surprised if that's the problem.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-17T13:14:48Z
body: > Note that the jenkins build was fine and that's the only one using `nvhpc` (as host compiler). `KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang)` isn't tested in the CI. I would just remove all the checks and get a verbpse log if the problem in the `GitHub` CI persists.

Thanks for your message. I noticed `nvhpc` in ~~one~~ two of the cases within the Jenkins build but I didn't know that the Jenkins build was the only place. Noted your point about "OpenACC + Clang" being not tested. I will see how to get a verbose log. I think I saw that option when I re-ran the tests (it is called [debug logging](https://docs.github.com/fr/actions/monitoring-and-troubleshooting-workflows/troubleshooting-workflows/enabling-debug-logging)). I didn't enable it. Let me check.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-17T13:16:53Z
body: > The fedora containers has a recent update, see https://github.com/kokkos/ci-containers/pkgs/container/ci-containers%2Ffedora. I woulnd't be surprised if that's the problem.

Wow, good catch.
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-01-17T16:00:16Z
body: The same errors associated with the Fedora containers are happening when the check for (KOKKOS_ENABLE_OPENACC AND KOKKOS_CXX_COMPILER_ID STREQUAL Clang) is removed. I re-ran the tests after enabling `debug logging`. I don't see any extra information. I dowloaded the logs and checked also. I cannot find any extra information.

As such the error is clang-tidy related, which results in an error when warnings-as-errors is enabled. When checking online for "use c++14 style type templates", other people are also facing this issue. Not clear why it is a problem for us with these Fedora containers. I see the same error happening in other PRs also. I will follow how it is getting resolved.

Update: It is being resolved with a NOLINT annotation around that block of code in PR [7688](https://github.com/kokkos/kokkos/pull/7688).
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-02-10T10:34:26Z
body: Retest this please!
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-02-13T12:40:20Z
body: ```
/builds/kokkos/kokkos/algorithms/unit_tests/../src/std_algorithms/impl/Kokkos_InclusiveScan.hpp:395:22: error: reference to __host__ function 'pushRegion' in __host__ __device__ function
  395 |   Kokkos::Profiling::pushRegion(
      |                      ^
/builds/kokkos/kokkos/algorithms/unit_tests/../src/std_algorithms/Kokkos_InclusiveScan.hpp:252:16: note: called by 'inclusive_scan<Kokkos::Impl::HIPTeamMember, Kokkos::Experimental::Impl::RandomAccessIterator<Kokkos::View<const double *, Kokkos::LayoutStride, Kokkos::Device<Kokkos::HIP, Kokkos::HIPSpace>, Kokkos::Experimental::EmptyViewHooks, Kokkos::MemoryTraits<0>>>, Kokkos::Experimental::Impl::RandomAccessIterator<Kokkos::View<double *, Kokkos::LayoutStride, Kokkos::Device<Kokkos::HIP, Kokkos::HIPSpace>, Kokkos::MemoryTraits<0>>>, 0>'
  252 |   return Impl::inclusive_scan_default_op_team_impl(teamHandle, first, last,
      |                ^
/builds/kokkos/kokkos/algorithms/unit_tests/TestStdAlgorithmsTeamInclusiveScan.cpp:74:26: note: called by 'operator()<Kokkos::Impl::HIPTeamMember>'
   74 |         auto it    = KE::inclusive_scan(member, first, last, firstDest);
      |                          ^
/builds/kokkos/kokkos/core/src/HIP/Kokkos_HIP_ParallelFor_Team.hpp:64:5: note: called by 'exec_team<void>'
   64 |     m_functor(member);
      |     ^
/builds/kokkos/kokkos/core/src/HIP/Kokkos_HIP_ParallelFor_Team.hpp:89:22: note: called by 'operator()'
   89 |       this->template exec_team<work_tag>(typename Policy::member_type(
      |                      ^
/builds/kokkos/kokkos/core/src/HIP/Kokkos_HIP_KernelLaunch.hpp:76:3: note: called by 'hip_parallel_launch_local_memory<Kokkos::Impl::ParallelFor<Test::stdalgos::TeamInclusiveScan::TestFunctorA<Kokkos::View<double **, Kokkos::HIPSpace>, Kokkos::View<double **>, Kokkos::View<unsigned long *>, Kokkos::View<bool *>, Kokkos::View<double *, Kokkos::LayoutRight, Kokkos::HIP>, Test::stdalgos::TeamInclusiveScan::PlusFunctor<double>>, Kokkos::TeamPolicy<Kokkos::HIP>>>'
   76 |   driver();
      |   ^
/builds/kokkos/kokkos/core/src/impl/Kokkos_Profiling.hpp:95:6: note: 'pushRegion' declared here
   95 | void pushRegion(const std::string& kName);
      |      ^
```
author_association: CONTRIBUTOR
user: login: science-enthusiast
created_at: 2025-02-28T02:49:12Z
body: @dalg24 
Please take a look at the changes made. I had already commented in the individual conversations about the changes. They are summarized below:

* Profiling is supported now via push and pop Regions. All the code paths have been handled. 
* Anonymous namespace has been used to enforce internal linkage.
* A FIXME has been added to accept warm-up time as a user defined parameter (say, as an environment variable).
* `std::span` is not supporteed by GCC 8.4.0 (Jenkins CI). Thus the reference scan implementation is still implemented using a for loop. A FIXME has been added.
author_association: CONTRIBUTOR
user: login: dalg24
created_at: 2025-03-03T16:05:13Z
body: Retest this please
author_association: MEMBER
user: login: dalg24
created_at: 2025-03-03T21:16:13Z
body: Retest this please
author_association: MEMBER
user: login: JBludau
created_at: 2025-03-13T15:48:36Z
body: @science-enthusiast can you open a pr adding documentation for this, please?
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-03-13T16:18:00Z
body: > @science-enthusiast can you open a pr adding documentation for this, please?

I'm not sure if we really want to document implementation details.
author_association: CONTRIBUTOR
user: login: JBludau
created_at: 2025-03-13T17:40:18Z
body: > > @science-enthusiast can you open a pr adding documentation for this, please?
> 
> I'm not sure if we really want to document implementation details.

Do we have a general policy of spelling out when we forward to vendor implementations? That is basically where I was coming from
author_association: CONTRIBUTOR
user: login: masterleinad
created_at: 2025-03-13T17:48:39Z
body: > Do we have a general policy of spelling out when we forward to vendor implementations? That is basically where I was coming from

We only list TPLs as options in the documentation but don't document in which cases interfaces might use them (which are implementation details IMHO).
author_association: CONTRIBUTOR
user: login: JBludau
created_at: 2025-03-13T17:57:36Z
body: Ok, then this does not need to be documented
author_association: CONTRIBUTOR