LCOV - code coverage report
Current view: top level - datahandlinglibs/test/apps - test_lb_allocation_app.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 54 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 16 0

            Line data    Source code
       1              : /**
       2              :  * @file test_lb_allocation_app.cxx Test application for LB allocations.
       3              :  *
       4              :  * This is part of the DUNE DAQ Application Framework, copyright 2020.
       5              :  * Licensing/copyright details are in the COPYING file that you should have
       6              :  * received with this code.
       7              :  */
       8              : 
       9              : #include "datahandlinglibs/models/IterableQueueModel.hpp"
      10              : #include "datahandlinglibs/models/SkipListLatencyBufferModel.hpp"
      11              : #include "datahandlinglibs/concepts/RawDataProcessorConcept.hpp"
      12              : #include "logging/Logging.hpp"
      13              : 
      14              : #include "CLI/App.hpp"
      15              : #include "CLI/Config.hpp"
      16              : #include "CLI/Formatter.hpp"
      17              : 
      18              : #include <atomic>
      19              : #include <chrono>
      20              : #include <memory>
      21              : #include <random>
      22              : #include <string>
      23              : #include <vector>
      24              : 
      25              : #ifdef WITH_LIBNUMA_SUPPORT
      26              : #include <numaif.h>
      27              : #endif
      28              : 
      29              : //#define REGISTER (*(volatile unsigned char*)0x1234)
      30              : 
      31              : using namespace dunedaq::datahandlinglibs;
      32              : 
      33              : namespace {
      34              : 
      35              :   struct kBlock // Dummy data type for LB test
      36              :   {
      37            0 :     kBlock(){};
      38              :     char data[1024];
      39              :   };
      40              : 
      41              :   std::size_t lb_capacity = 1000; // LB capacity
      42              :  
      43              :   bool numa_aware_test = false;
      44              :   int num_numa_nodes = 2;
      45              :   bool intrinsic_test = false;
      46              :   bool aligned_test = false;
      47              :   bool prefill = false; // Prefill the LB
      48              :   std::size_t alignment_size = 4096;
      49              : }
      50              : 
      51              : int
      52            0 : main(int argc, char** argv)
      53              : {
      54            0 :   int runsecs = 5;
      55              : 
      56              :   // Run marker
      57            0 :   std::atomic<bool> marker{ true };
      58              : 
      59              :   // Counter for ops/s
      60            0 :   std::atomic<int> newops = 0;
      61              : 
      62            0 :   CLI::App app{"datahandlinglibs_test_lb_allocation"};
      63            0 :   app.add_option("-c", lb_capacity, "Capacity/size of latency buffer.");
      64            0 :   app.add_flag("--numa_aware", numa_aware_test, "Test NUMA aware allocator.");
      65            0 :   app.add_option("--num_numa_nodes", num_numa_nodes, "Number of NUMA nodes to test allocation on.");
      66            0 :   app.add_flag("--intrinsic", intrinsic_test, "Test Intrinsic allocator.");
      67            0 :   app.add_flag("--aligned", aligned_test, "Test aligned allocator.");
      68            0 :   app.add_option("--alignment_size", alignment_size, "Set alignment size. Default: 4096");
      69            0 :   app.add_flag("--prefill", prefill, "Interface to init");
      70            0 :   CLI11_PARSE(app, argc, argv);
      71              : 
      72            0 :   if (numa_aware_test) { // check if test is issued...
      73              : #ifdef WITH_LIBNUMA_SUPPORT
      74            0 :     TLOG() << "NUMA aware allocator test...";
      75              : 
      76            0 :     for (int i=0; i<num_numa_nodes; ++i) { // for number of nodes...
      77            0 :       TLOG() << "  # Allocating NUMA aware LB on node " << i;
      78            0 :       IterableQueueModel<kBlock> numaIQM(lb_capacity, true, i, false, 0);
      79              : 
      80            0 :       if (prefill) { // Force page-fault issues?
      81            0 :         TLOG() << "  -> Prefilling LB...";
      82            0 :         numaIQM.force_pagefault();
      83              :       }
      84              : 
      85            0 :       for (std::size_t i=0; i<lb_capacity-1; ++i) { // Fill the LB
      86            0 :         numaIQM.write(kBlock());
      87              :       }
      88              :     
      89              :       // Test if the elements' pointers are on correct NUMA node.
      90              :       // Virtual addresses might be misleading between virt. and phys. addresses due to IOMMU!
      91            0 :       int numa_node = -1;
      92            0 :       get_mempolicy(&numa_node, NULL, 0, (void*)numaIQM.front(), MPOL_F_NODE | MPOL_F_ADDR);
      93            0 :       if (i != numa_node) { TLOG() << "Discrepancy in expected NUMA node and first element residency!"; }
      94            0 :       TLOG() << "  -> NUMA " << i << " IQM front virt.addr.: " << std::hex << (void*)numaIQM.front() << " is on: " << numa_node << std::dec;
      95            0 :       get_mempolicy(&numa_node, NULL, 0, (void*)numaIQM.back(), MPOL_F_NODE | MPOL_F_ADDR);
      96            0 :       if (i != numa_node) { TLOG() << "Discrepancy in expected NUMA node and last element residency!"; }
      97            0 :       TLOG() << "  -> NUMA " << i << " IQM back virt.addr.: " << std::hex << (void*)numaIQM.back() << " is on: " << numa_node << std::dec;
      98            0 :     }
      99            0 :     TLOG() << "  -> Done.";
     100              : #else
     101              :     TLOG() << "  -> NUMA support is turned off build-time. Passed on NUMA demo.";
     102              : #endif
     103              :   }
     104              : 
     105            0 :   if (intrinsic_test) {
     106            0 :     TLOG() << "Intrinsic allocator test...";
     107            0 :     IterableQueueModel<kBlock> intrIQM(lb_capacity, false, 0, true, alignment_size);
     108            0 :     if (prefill) {
     109            0 :       TLOG() << "  -> Prefilling LB...";
     110            0 :       intrIQM.force_pagefault();
     111              :     }
     112              : 
     113            0 :     for (std::size_t i=0; i<lb_capacity-1; ++i) { // Fill the LB
     114            0 :       intrIQM.write(kBlock());
     115              :     }
     116              : 
     117            0 :     TLOG() << "  -> Done.";
     118            0 :   }
     119              : 
     120            0 :   if (aligned_test) {
     121            0 :     TLOG() << "Aligned allocator test...";
     122            0 :     IterableQueueModel<kBlock> alignedIQM(lb_capacity, false, 0, false, alignment_size);
     123            0 :     if (prefill) {
     124            0 :       TLOG() << "  -> Prefilling LB...";
     125            0 :       alignedIQM.force_pagefault();
     126              :     }
     127              : 
     128            0 :     for (std::size_t i=0; i<lb_capacity-1; ++i) { // Fill the LB
     129            0 :       alignedIQM.write(kBlock());
     130              :     }
     131              : 
     132            0 :     TLOG() << "  -> Done.";
     133            0 :   }
     134              : 
     135              :   // Test app ends. Below there are general producer/consumer/stats threads.
     136              :   return 0;
     137              : 
     138              :   // Stats
     139              :   auto stats = std::thread([&]() {
     140              :     TLOG() << "Spawned stats thread...";
     141              :     while (marker) {
     142              :       TLOG() << "ops/s ->  " << newops.exchange(0);
     143              :       std::this_thread::sleep_for(std::chrono::seconds(1));
     144              :     }
     145              :   });
     146              : 
     147              :   // Producer
     148              :   auto producer = std::thread([&]() {
     149              :     TLOG() << "Spawned producer thread...";
     150              :     while (marker) {
     151              :       std::this_thread::sleep_for(std::chrono::seconds(1));
     152              :     }
     153              :   });
     154              : 
     155              :   // Consumer
     156              :   auto consumer = std::thread([&]() {
     157              :     TLOG() << "Spawned consumer thread...";
     158              :     while (marker) {
     159              :       std::this_thread::sleep_for(std::chrono::seconds(1));
     160              :     }
     161              :   });
     162              : 
     163              :   // Killswitch that flips the run marker
     164              :   auto killswitch = std::thread([&]() {
     165              :     TLOG() << "Application will terminate in 5s...";
     166              :     std::this_thread::sleep_for(std::chrono::seconds(runsecs));
     167              :     marker.store(false);
     168              :   });
     169              : 
     170              :   // Join local threads
     171              :   TLOG() << "Flipping killswitch in order to stop...";
     172              :   if (killswitch.joinable()) {
     173              :     killswitch.join();
     174              :   }
     175              : 
     176              :   // Exit
     177              :   TLOG() << "Exiting.";
     178              :   return 0;
     179            0 : }
        

Generated by: LCOV version 2.0-1