Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-07-26 08:22:22

0001 /**
0002  * TRACCC library, part of the ACTS project (R&D line)
0003  *
0004  * (c) 2022-2025 CERN for the benefit of the ACTS project
0005  *
0006  * Mozilla Public License Version 2.0
0007  */
0008 
0009 // Project include(s).
0010 #include "traccc/alpaka/utils/vecmem_objects.hpp"
0011 
0012 // VecMem include(s).
0013 #include <vecmem/containers/data/vector_buffer.hpp>
0014 #include <vecmem/containers/device_vector.hpp>
0015 #include <vecmem/containers/vector.hpp>
0016 
0017 // Alpaka include(s).
0018 #include <alpaka/alpaka.hpp>
0019 #include <alpaka/example/ExampleDefaultAcc.hpp>
0020 
0021 // GoogleTest include(s).
0022 #include <gtest/gtest.h>
0023 
0024 // Standard include(s).
0025 #include <cstdint>
0026 #include <iostream>
0027 
0028 template <typename Acc>
0029 ALPAKA_FN_ACC float process(Acc const& acc, uint32_t idx) {
0030   return static_cast<float>(alpaka::math::sin(acc, idx));
0031 }
0032 
0033 struct VectorOpKernel {
0034   template <typename Acc>
0035   ALPAKA_FN_ACC void operator()(Acc const& acc, float* result,
0036                                 uint32_t n) const {
0037     using namespace alpaka;
0038     auto const globalThreadIdx = getIdx<alpaka::Grid, alpaka::Threads>(acc)[0u];
0039 
0040     // It is possible to get index type from the accelerator,
0041     // but for simplicity we just repeat the type here
0042     if (globalThreadIdx < n) {
0043       result[globalThreadIdx] = process(acc, globalThreadIdx);
0044     }
0045   }
0046 };
0047 
0048 /// Copy vector to device, set element[i] = sin(i) on device, then compare with
0049 /// same calculation on host
0050 GTEST_TEST(AlpakaBasic, VectorOp) {
0051   using namespace alpaka;
0052   using Dim = DimInt<1>;
0053   using Idx = uint32_t;
0054 
0055   using Acc = ExampleDefaultAcc<Dim, Idx>;
0056   std::cout << "Using alpaka accelerator: " << alpaka::getAccName<Acc>()
0057             << std::endl;
0058 
0059   // Select a device and create queue for it
0060   auto const platformAcc = alpaka::Platform<Acc>{};
0061   auto const devAcc = getDevByIdx(platformAcc, 0u);
0062 
0063   using Queue = Queue<Acc, Blocking>;
0064   auto queue = Queue{devAcc};
0065 
0066   uint32_t n = 10000;
0067 
0068   uint32_t blocksPerGrid = n;
0069   uint32_t threadsPerBlock = 1;
0070   uint32_t elementsPerThread = 4;
0071   using WorkDiv = WorkDivMembers<Dim, Idx>;
0072   auto workDiv = WorkDiv{blocksPerGrid, threadsPerBlock, elementsPerThread};
0073 
0074   // Create a device for host for memory allocation, using the first CPU
0075   // available
0076   auto const platformDevCpu = alpaka::Platform<DevCpu>{};
0077   auto devHost = getDevByIdx(platformDevCpu, 0u);
0078 
0079   // Allocate memory on the device side:
0080   auto bufAcc = alpaka::allocBuf<float, uint32_t>(devAcc, n);
0081 
0082   alpaka::exec<Acc>(queue, workDiv, VectorOpKernel{},
0083                     alpaka::getPtrNative(bufAcc), n);
0084 
0085   alpaka::wait(queue);
0086 
0087   // Allocate memory on the host side:
0088   auto bufHost = alpaka::allocBuf<float, uint32_t>(devHost, n);
0089   // Copy bufAcc to bufHost
0090   alpaka::memcpy(queue, bufHost, bufAcc);
0091   // Calculate on the host and compare result
0092   for (uint32_t i = 0u; i < n; i++) {
0093     EXPECT_FLOAT_EQ(bufHost[i], static_cast<float>(std::sin(i)));
0094   }
0095 }
0096 
0097 struct VecMemOpKernel {
0098   template <typename Acc>
0099   ALPAKA_FN_ACC void operator()(Acc const& acc,
0100                                 vecmem::data::vector_view<float> result) const {
0101     using namespace alpaka;
0102     auto const globalThreadIdx = getIdx<alpaka::Grid, alpaka::Threads>(acc)[0u];
0103 
0104     // It is possible to get index type from the accelerator,
0105     // but for simplicity we just repeat the type here
0106     if (globalThreadIdx < result.size()) {
0107       result.ptr()[globalThreadIdx] = process(acc, globalThreadIdx);
0108     }
0109   }
0110 };
0111 
0112 GTEST_TEST(AlpakaBasic, VecMemOp) {
0113   using namespace alpaka;
0114   using Dim = DimInt<1>;
0115   using Idx = uint32_t;
0116 
0117   // Select a device and create queue for it
0118   using Acc = ExampleDefaultAcc<Dim, Idx>;
0119   auto const platformAcc = alpaka::Platform<Acc>{};
0120   auto const devAcc = getDevByIdx(platformAcc, 0u);
0121 
0122   using Queue = Queue<Acc, Blocking>;
0123   auto alpaka_queue = Queue{devAcc};
0124 
0125   uint32_t n = 10000;
0126 
0127   uint32_t blocksPerGrid = n;
0128   uint32_t threadsPerBlock = 1;
0129   uint32_t elementsPerThread = 4;
0130   using WorkDiv = WorkDivMembers<Dim, Idx>;
0131   auto workDiv = WorkDiv{blocksPerGrid, threadsPerBlock, elementsPerThread};
0132 
0133   traccc::alpaka::queue traccc_queue(&alpaka_queue);
0134   traccc::alpaka::vecmem_objects vo(traccc_queue);
0135 
0136   vecmem::memory_resource& host_mr = vo.host_mr();
0137   vecmem::memory_resource& device_mr = vo.device_mr();
0138   vecmem::copy& vm_copy = vo.copy();
0139 
0140   vecmem::vector<float> host_vector{n, &host_mr};
0141 
0142   auto host_buffer = vecmem::get_data(host_vector);
0143   auto device_buffer = vm_copy.to(vecmem::get_data(host_vector), device_mr,
0144                                   vecmem::copy::type::host_to_device);
0145   auto data_dev_vec_buf = vecmem::get_data(device_buffer);
0146 
0147   std::cout << "Using alpaka accelerator: " << alpaka::getAccName<Acc>()
0148             << std::endl;
0149 
0150   alpaka::exec<Acc>(alpaka_queue, workDiv, VecMemOpKernel{}, data_dev_vec_buf);
0151   alpaka::wait(alpaka_queue);
0152 
0153   vm_copy(device_buffer, host_buffer, vecmem::copy::type::device_to_host)
0154       ->wait();
0155 
0156   for (uint32_t i = 0u; i < n; i++) {
0157     EXPECT_FLOAT_EQ(host_vector[i], static_cast<float>(std::sin(i)));
0158   }
0159 }