LCOV - code coverage report
Current view: top level - src/Tools/Thread_pinning - Thread_pinning.cpp (source / functions) Hit Total Coverage
Test: streampu_clean.info Lines: 51 114 44.7 %
Date: 2024-07-31 15:48:41 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_pinning/Thread_pinning.hpp"
      15             : #include "Tools/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         111 : Thread_pinning::is_init()
      30             : {
      31         111 :     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             :     if (g_enable_logs)
     157             :     {
     158             :         std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
     159             :     }
     160             : #endif
     161           0 :     g_mtx.unlock();
     162           0 : }
     163             : 
     164             : // Thread pinning second function using hwloc objects
     165             : void
     166          54 : Thread_pinning::pin(const std::string hwloc_objects)
     167             : {
     168          54 :     g_mtx.lock();
     169             : 
     170             : #ifdef SPU_HWLOC
     171          54 :     if (Thread_pinning::is_init())
     172             :     {
     173             :         // Objects parsing
     174          54 :         std::vector<std::string> hwloc_objects_vector = Thread_pinning_utils::thread_parser(hwloc_objects);
     175             : 
     176             :         // getting the pairs
     177          54 :         std::vector<std::pair<hwloc_obj_type_t, int>> object_numbers;
     178         108 :         for (auto obj : hwloc_objects_vector)
     179          54 :             object_numbers.push_back(Thread_pinning_utils::str_to_hwloc_object(obj));
     180             : 
     181             :         // getting topology depth of each object
     182          54 :         std::vector<int> object_depth = {};
     183         108 :         for (auto obj : object_numbers)
     184          54 :             object_depth.push_back(hwloc_get_type_or_below_depth(g_topology, obj.first));
     185             : 
     186             :         // Allocating cpu_set
     187          54 :         hwloc_bitmap_t all_pus = hwloc_bitmap_alloc();
     188          54 :         hwloc_bitmap_zero(all_pus);
     189             : 
     190         108 :         for (size_t i = 0; i < object_numbers.size(); ++i)
     191             :         {
     192          54 :             hwloc_obj_t obj = hwloc_get_obj_by_depth(g_topology, object_depth[i], object_numbers[i].second);
     193          54 :             if (obj == nullptr)
     194             :             {
     195           0 :                 std::stringstream message;
     196           0 :                 message << "obj is nullptr ('Type' = " << hwloc_objects_vector[i] << ").";
     197           0 :                 throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
     198           0 :             }
     199          54 :             hwloc_bitmap_or(all_pus, all_pus, obj->cpuset);
     200             :         }
     201             : 
     202          54 :         if (g_enable_logs)
     203             :         {
     204             :             char c[128];
     205           0 :             hwloc_bitmap_snprintf(c, 128, all_pus);
     206             : 
     207           0 :             std::clog << "Thread pinning info -- ";
     208           0 :             for (size_t i = 0; i < hwloc_objects_vector.size(); ++i)
     209             :             {
     210           0 :                 std::clog << "Object = " << hwloc_objects_vector[i] << " | number = " << object_numbers[i].second
     211           0 :                           << std::endl;
     212             :             }
     213           0 :             std::clog << "bitmap: " << all_pus << std::endl;
     214             :         }
     215             : 
     216             :         /* And try to bind ourself there. */
     217          54 :         if (hwloc_set_cpubind(g_topology, all_pus, HWLOC_CPUBIND_THREAD))
     218             :         {
     219             :             char* str;
     220           0 :             int error = errno;
     221           0 :             hwloc_bitmap_asprintf(&str, all_pus);
     222           0 :             std::clog << "Couldn't bind to cpuset " << str << ": " << strerror(error) << std::endl;
     223           0 :             free(str);
     224             :         }
     225             : 
     226             :         /* Free our cpuset copy */
     227          54 :         hwloc_bitmap_free(all_pus);
     228          54 :     }
     229             :     else
     230             :     {
     231           0 :         if (g_enable_logs)
     232             :         {
     233             :             std::clog << "You can't call the 'pin' method if you have not call the 'init' method before, nothing will "
     234           0 :                       << "be done." << std::endl;
     235             :         }
     236             :     }
     237             : #else
     238             :     if (g_enable_logs)
     239             :     {
     240             :         std::clog << "'pin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
     241             :     }
     242             : #endif
     243          54 :     g_mtx.unlock();
     244          54 : }
     245             : 
     246             : void
     247          47 : Thread_pinning::unpin()
     248             : {
     249          47 :     g_mtx.lock();
     250             : #ifdef SPU_HWLOC
     251          48 :     if (!Thread_pinning::is_init())
     252             :     {
     253           0 :         if (g_enable_logs)
     254             :         {
     255             :             std::clog << "You can't call the 'unpin' method if you have not call the 'init' method before, nothing "
     256           0 :                       << "will be done." << std::endl;
     257             :         }
     258             :     }
     259             :     else
     260             :     {
     261             :         // get cpuset of root object
     262          48 :         hwloc_cpuset_t unpin_set = hwloc_bitmap_dup(hwloc_get_obj_by_depth(g_topology, 0, 0)->cpuset);
     263          48 :         if (hwloc_set_cpubind(g_topology, unpin_set, HWLOC_CPUBIND_THREAD))
     264             :         {
     265             :             char* bitmap_str;
     266           0 :             int error = errno;
     267           0 :             hwloc_bitmap_asprintf(&bitmap_str, unpin_set);
     268           0 :             std::clog << "'unpin' method failed ('bitmap_str' = " << bitmap_str << ", 'error' = " << strerror(error)
     269           0 :                       << ")" << std::endl;
     270           0 :             free(bitmap_str);
     271             :         }
     272          48 :         hwloc_bitmap_free(unpin_set);
     273             :     }
     274             : #else
     275             :     if (g_enable_logs)
     276             :     {
     277             :         std::clog << "'unpin' method do nothing as StreamPU has not been linked with the 'hwloc' library." << std::endl;
     278             :     }
     279             : #endif
     280          48 :     g_mtx.unlock();
     281          48 : }
     282             : 
     283             : std::string
     284           0 : Thread_pinning::get_cur_cpuset_str()
     285             : {
     286             : #ifdef SPU_HWLOC
     287           0 :     hwloc_cpuset_t cur_cpuset = hwloc_bitmap_alloc();
     288             : 
     289           0 :     hwloc_get_cpubind(g_topology, cur_cpuset, HWLOC_CPUBIND_THREAD);
     290             : 
     291             :     char c[128];
     292           0 :     hwloc_bitmap_snprintf(c, 128, cur_cpuset);
     293             : 
     294             :     /* Free our cpuset copy */
     295           0 :     hwloc_bitmap_free(cur_cpuset);
     296             : 
     297           0 :     return std::string(c);
     298             : #else
     299             :     std::stringstream message;
     300             :     message << "'get_cur_cpuset_str' method can be called only if StreamPU is linked with the 'hwloc' library.";
     301             :     throw tools::runtime_error(__FILE__, __LINE__, __func__, message.str());
     302             : #endif
     303             : }

Generated by: LCOV version 1.14