LCOV - code coverage report
Current view: top level - src/Tools/Thread/Thread_pinning - Thread_pinning.cpp (source / functions) Hit Total Coverage
Test: streampu_clean.info Lines: 53 114 46.5 %
Date: 2025-03-14 12:33:06 Functions: 5 9 55.6 %

          Line data    Source code
       1             : #include <cerrno>
       2             : #include <cstdio>
       3             : #include <cstring>
       4             : #include <functional>
       5             : #include <iostream>
       6             : #include <mutex>
       7             : #include <sstream>
       8             : #include <vector>
       9             : #ifdef SPU_HWLOC
      10             : #include <hwloc.h>
      11             : #endif
      12             : 
      13             : #include "Tools/Exception/exception.hpp"
      14             : #include "Tools/Thread/Thread_pinning/Thread_pinning.hpp"
      15             : #include "Tools/Thread/Thread_pinning/Thread_pinning_utils.hpp"
      16             : 
      17             : using namespace spu;
      18             : using namespace spu::tools;
      19             : 
      20             : #ifdef SPU_HWLOC
      21             : static hwloc_topology_t g_topology;
      22             : static int g_topodepth = 0;
      23             : #endif
      24             : static bool g_is_init = false;
      25             : static std::mutex g_mtx;
      26             : static bool g_enable_logs = false;
      27             : 
      28             : bool
      29         426 : Thread_pinning::is_init()
      30             : {
      31         426 :     return g_is_init;
      32             : }
      33             : 
      34             : void
      35           2 : Thread_pinning::init()
      36             : {
      37           2 :     if (!Thread_pinning::is_init())
      38             :     {
      39           2 :         g_mtx.lock();
      40           2 :         if (!Thread_pinning::is_init())
      41             :         {
      42           2 :             g_is_init = true;
      43             : 
      44             : #ifdef SPU_HWLOC
      45             :             /* Allocate and initialize topology object. */
      46           2 :             hwloc_topology_init(&g_topology);
      47             : 
      48             :             /* ... Optionally, put detection configuration here to ignore
      49             :              some objects types, define a synthetic topology, etc....
      50             :              The default is to detect all the objects of the machine that
      51             :              the caller is allowed to access.  See Configure Topology
      52             :              Detection. */
      53             : 
      54             :             /* Perform the topology detection. */
      55           2 :             hwloc_topology_load(g_topology);
      56             : 
      57             :             /* Optionally, get some additional topology information
      58             :              in case we need the topology depth later. */
      59           2 :             g_topodepth = hwloc_topology_get_depth(g_topology);
      60             : #endif
      61             :         }
      62           2 :         g_mtx.unlock();
      63             :     }
      64           2 : }
      65             : 
      66             : void
      67           2 : Thread_pinning::destroy()
      68             : {
      69           2 :     if (Thread_pinning::is_init())
      70             :     {
      71           2 :         g_mtx.lock();
      72           2 :         if (Thread_pinning::is_init())
      73             :         {
      74             : #ifdef SPU_HWLOC
      75             :             /* Destroy topology object. */
      76           2 :             hwloc_topology_destroy(g_topology);
      77           2 :             g_topodepth = 0;
      78             : #endif
      79           2 :             g_is_init = false;
      80             :         }
      81           2 :         g_mtx.unlock();
      82             :     }
      83           2 : }
      84             : 
      85             : void
      86           0 : Thread_pinning::set_logs(const bool enable_logs)
      87             : {
      88           0 :     g_mtx.lock();
      89           0 :     g_enable_logs = enable_logs;
      90           0 :     g_mtx.unlock();
      91           0 : }
      92             : 
      93             : bool
      94           0 : Thread_pinning::is_logs()
      95             : {
      96           0 :     return g_enable_logs;
      97             : }
      98             : 
      99             : void
     100           0 : Thread_pinning::pin(const size_t puid)
     101             : {
     102           0 :     g_mtx.lock();
     103             : #ifdef SPU_HWLOC
     104           0 :     if (Thread_pinning::is_init())
     105             :     {
     106           0 :         int pu_depth = hwloc_get_type_or_below_depth(g_topology, HWLOC_OBJ_PU);
     107           0 :         hwloc_obj_t pu_obj = hwloc_get_obj_by_depth(g_topology, pu_depth, puid);
     108             : 
     109           0 :         if (pu_obj == nullptr)
     110             :         {
     111           0 :             std::stringstream message;
     112           0 :             message << "'pu_obj' is nullptr ('puid' = " << puid << ").";
     113           0 :             throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
     114           0 :         }
     115             : 
     116             :         /* Get a copy of its cpuset that we may modify. */
     117           0 :         hwloc_cpuset_t cpuset = hwloc_bitmap_dup(pu_obj->cpuset);
     118             : 
     119             :         /* Get only one logical processor (in case the core is
     120             :         SMT/hyper-threaded). */
     121           0 :         hwloc_bitmap_singlify(cpuset);
     122             : 
     123           0 :         if (g_enable_logs)
     124             :         {
     125             :             char c[128];
     126           0 :             hwloc_bitmap_snprintf(c, 128, cpuset);
     127             : 
     128             :             std::cerr << "Thread pinning info -- "
     129           0 :                       << "PU logical index (hwloc): " << pu_obj->logical_index << " -- "
     130           0 :                       << "P OS index: " << pu_obj->os_index << " -- "
     131           0 :                       << "bitmap: " << c << std::endl;
     132             :         }
     133             : 
     134             :         /* And try to bind ourself there. */
     135           0 :         if (hwloc_set_cpubind(g_topology, cpuset, HWLOC_CPUBIND_THREAD))
     136             :         {
     137             :             char* str;
     138           0 :             int error = errno;
     139           0 :             hwloc_bitmap_asprintf(&str, pu_obj->cpuset);
     140           0 :             std::clog << "Couldn't bind to cpuset " << str << ": " << strerror(error) << std::endl;
     141           0 :             free(str);
     142             :         }
     143             : 
     144             :         /* Free our cpuset copy */
     145           0 :         hwloc_bitmap_free(cpuset);
     146             :     }
     147             :     else
     148             :     {
     149           0 :         if (g_enable_logs)
     150             :         {
     151             :             std::clog << "You can't call the 'pin' method if you have not call the 'init' method before, nothing will "
     152           0 :                       << "be done." << std::endl;
     153             :         }
     154             :     }
     155             : #else
     156             :     (void)puid;
     157             :     if (g_enable_logs)
     158             :     {
     159             :         std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
     160             :     }
     161             : #endif
     162           0 :     g_mtx.unlock();
     163           0 : }
     164             : 
     165             : // Thread pinning second function using hwloc objects
     166             : void
     167         223 : Thread_pinning::pin(const std::string hwloc_objects)
     168             : {
     169         223 :     g_mtx.lock();
     170             : 
     171             : #ifdef SPU_HWLOC
     172         223 :     if (Thread_pinning::is_init())
     173             :     {
     174             :         // Objects parsing
     175          54 :         std::vector<std::string> hwloc_objects_vector = Thread_pinning_utils::thread_parser(hwloc_objects);
     176             : 
     177             :         // getting the pairs
     178          54 :         std::vector<std::pair<hwloc_obj_type_t, int>> object_numbers;
     179         108 :         for (auto obj : hwloc_objects_vector)
     180          54 :             object_numbers.push_back(Thread_pinning_utils::str_to_hwloc_object(obj));
     181             : 
     182             :         // getting topology depth of each object
     183          54 :         std::vector<int> object_depth = {};
     184         108 :         for (auto obj : object_numbers)
     185          54 :             object_depth.push_back(hwloc_get_type_or_below_depth(g_topology, obj.first));
     186             : 
     187             :         // Allocating cpu_set
     188          54 :         hwloc_bitmap_t all_pus = hwloc_bitmap_alloc();
     189          54 :         hwloc_bitmap_zero(all_pus);
     190             : 
     191         108 :         for (size_t i = 0; i < object_numbers.size(); ++i)
     192             :         {
     193          54 :             hwloc_obj_t obj = hwloc_get_obj_by_depth(g_topology, object_depth[i], object_numbers[i].second);
     194          54 :             if (obj == nullptr)
     195             :             {
     196           0 :                 std::stringstream message;
     197           0 :                 message << "obj is nullptr ('Type' = " << hwloc_objects_vector[i] << ").";
     198           0 :                 throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
     199           0 :             }
     200          54 :             hwloc_bitmap_or(all_pus, all_pus, obj->cpuset);
     201             :         }
     202             : 
     203          54 :         if (g_enable_logs)
     204             :         {
     205             :             char c[128];
     206           0 :             hwloc_bitmap_snprintf(c, 128, all_pus);
     207             : 
     208           0 :             std::clog << "Thread pinning info -- ";
     209           0 :             for (size_t i = 0; i < hwloc_objects_vector.size(); ++i)
     210             :             {
     211           0 :                 std::clog << "Object = " << hwloc_objects_vector[i] << " | number = " << object_numbers[i].second
     212           0 :                           << std::endl;
     213             :             }
     214           0 :             std::clog << "bitmap: " << all_pus << std::endl;
     215             :         }
     216             : 
     217             :         /* And try to bind ourself there. */
     218          54 :         if (hwloc_set_cpubind(g_topology, all_pus, HWLOC_CPUBIND_THREAD))
     219             :         {
     220             :             char* str;
     221           0 :             int error = errno;
     222           0 :             hwloc_bitmap_asprintf(&str, all_pus);
     223           0 :             std::clog << "Couldn't bind to cpuset " << str << ": " << strerror(error) << std::endl;
     224           0 :             free(str);
     225             :         }
     226             : 
     227             :         /* Free our cpuset copy */
     228          54 :         hwloc_bitmap_free(all_pus);
     229          54 :     }
     230             :     else
     231             :     {
     232         169 :         if (g_enable_logs)
     233             :         {
     234             :             std::clog << "You can't call the 'pin' method if you have not call the 'init' method before, nothing will "
     235           0 :                       << "be done." << std::endl;
     236             :         }
     237             :     }
     238             : #else
     239             :     (void)hwloc_objects;
     240             :     if (g_enable_logs)
     241             :     {
     242             :         std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
     243             :     }
     244             : #endif
     245         223 :     g_mtx.unlock();
     246         223 : }
     247             : 
     248             : void
     249         191 : Thread_pinning::unpin()
     250             : {
     251         191 :     g_mtx.lock();
     252             : #ifdef SPU_HWLOC
     253         194 :     if (!Thread_pinning::is_init())
     254             :     {
     255         146 :         if (g_enable_logs)
     256             :         {
     257             :             std::clog << "You can't call the 'unpin' method if you have not call the 'init' method before, nothing "
     258           0 :                       << "will be done." << std::endl;
     259             :         }
     260             :     }
     261             :     else
     262             :     {
     263             :         // get cpuset of root object
     264          48 :         hwloc_cpuset_t unpin_set = hwloc_bitmap_dup(hwloc_get_obj_by_depth(g_topology, 0, 0)->cpuset);
     265          48 :         if (hwloc_set_cpubind(g_topology, unpin_set, HWLOC_CPUBIND_THREAD))
     266             :         {
     267             :             char* bitmap_str;
     268           0 :             int error = errno;
     269           0 :             hwloc_bitmap_asprintf(&bitmap_str, unpin_set);
     270           0 :             std::clog << "'unpin' method failed ('bitmap_str' = " << bitmap_str << ", 'error' = " << strerror(error)
     271           0 :                       << ")" << std::endl;
     272           0 :             free(bitmap_str);
     273             :         }
     274          48 :         hwloc_bitmap_free(unpin_set);
     275             :     }
     276             : #else
     277             :     if (g_enable_logs)
     278             :     {
     279             :         std::clog << "'unpin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
     280             :     }
     281             : #endif
     282         194 :     g_mtx.unlock();
     283         194 : }
     284             : 
     285             : std::string
     286           0 : Thread_pinning::get_cur_cpuset_str()
     287             : {
     288             : #ifdef SPU_HWLOC
     289           0 :     hwloc_cpuset_t cur_cpuset = hwloc_bitmap_alloc();
     290             : 
     291           0 :     hwloc_get_cpubind(g_topology, cur_cpuset, HWLOC_CPUBIND_THREAD);
     292             : 
     293             :     char c[128];
     294           0 :     hwloc_bitmap_snprintf(c, 128, cur_cpuset);
     295             : 
     296             :     /* Free our cpuset copy */
     297           0 :     hwloc_bitmap_free(cur_cpuset);
     298             : 
     299           0 :     return std::string(c);
     300             : #else
     301             :     std::stringstream message;
     302             :     message << "'get_cur_cpuset_str' method can be called only if StreamPU is linked with the 'hwloc' library.";
     303             :     throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
     304             : #endif
     305             : }

Generated by: LCOV version 1.14