1 ////////////////////////////////////////////////////////////////////////////////
2 //  Copyright (c) 2007-2015 Hartmut Kaiser
3 //  Copyright (c) 2008-2009 Chirag Dekate, Anshul Tandon
4 //  Copyright (c) 2012-2013 Thomas Heller
5 //
6 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
7 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 ////////////////////////////////////////////////////////////////////////////////
9 
10 #ifndef HPX_RUNTIME_THREADS_CPU_MASK_HPP
11 #define HPX_RUNTIME_THREADS_CPU_MASK_HPP
12 
13 #include <hpx/config.hpp>
14 #include <hpx/util/assert.hpp>
15 
16 #include <climits>
17 #include <cstddef>
18 #include <cstdint>
19 #include <string>
20 
21 #if defined(HPX_HAVE_MORE_THAN_64_THREADS) || (defined(HPX_HAVE_MAX_CPU_COUNT) \
22             && HPX_HAVE_MAX_CPU_COUNT > 64)
23 #  if defined(HPX_HAVE_MAX_CPU_COUNT)
24 #    include <bitset>
25 #  else
26 #    include <boost/dynamic_bitset.hpp>
27 #  endif
28 #endif
29 
30 namespace hpx { namespace threads
31 {
32     /// \cond NOINTERNAL
33 #if !defined(HPX_HAVE_MORE_THAN_64_THREADS) || (defined(HPX_HAVE_MAX_CPU_COUNT) \
34              && HPX_HAVE_MAX_CPU_COUNT <= 64)
35     typedef std::uint64_t mask_type;
36     typedef std::uint64_t mask_cref_type;
37 
bits(std::size_t idx)38     inline std::uint64_t bits(std::size_t idx)
39     {
40        HPX_ASSERT(idx < CHAR_BIT * sizeof(mask_type));
41        return std::uint64_t(1) << idx;
42     }
43 
any(mask_cref_type mask)44     inline bool any(mask_cref_type mask)
45     {
46         return mask != 0;
47     }
48 
not_(mask_cref_type mask)49     inline mask_type not_(mask_cref_type mask)
50     {
51         return ~mask;
52     }
53 
test(mask_cref_type mask,std::size_t idx)54     inline bool test(mask_cref_type mask, std::size_t idx)
55     {
56         HPX_ASSERT(idx < CHAR_BIT * sizeof(mask_type));
57         return (bits(idx) & mask) != 0;
58     }
59 
set(mask_type & mask,std::size_t idx)60     inline void set(mask_type& mask, std::size_t idx)
61     {
62         HPX_ASSERT(idx < CHAR_BIT * sizeof(mask_type));
63         mask |= bits(idx);
64     }
65 
unset(mask_type & mask,std::size_t idx)66     inline void unset(mask_type& mask, std::size_t idx)
67     {
68         HPX_ASSERT(idx < CHAR_BIT * sizeof(mask_type));
69         mask &= not_(bits(idx));
70     }
71 
mask_size(mask_cref_type)72     inline std::size_t mask_size(mask_cref_type /*mask*/)
73     {
74         return CHAR_BIT * sizeof(mask_type);
75     }
76 
resize(mask_type &,std::size_t s)77     inline void resize(mask_type& /*mask*/, std::size_t s)
78     {
79         HPX_ASSERT(s <= CHAR_BIT * sizeof(mask_type));
80     }
81 
find_first(mask_cref_type mask)82     inline std::size_t find_first(mask_cref_type mask)
83     {
84         if (mask) {
85             std::size_t c = 0;    // Will count mask's trailing zero bits.
86 
87             // Set mask's trailing 0s to 1s and zero rest.
88             mask = (mask ^ (mask - 1)) >> 1;
89             for (/**/; mask; ++c)
90                 mask >>= 1;
91 
92             return c;
93         }
94         return ~std::size_t(0);
95     }
96 
equal(mask_cref_type lhs,mask_cref_type rhs,std::size_t=0)97     inline bool equal(mask_cref_type lhs, mask_cref_type rhs, std::size_t = 0)
98     {
99         return lhs == rhs;
100     }
101 
102     // return true if at least one of the masks has a bit set
bit_or(mask_cref_type lhs,mask_cref_type rhs,std::size_t=0)103     inline bool bit_or(mask_cref_type lhs, mask_cref_type rhs, std::size_t = 0)
104     {
105         return (lhs | rhs) != 0;
106     }
107 
108     // return true if at least one bit is set in both masks
bit_and(mask_cref_type lhs,mask_cref_type rhs,std::size_t=0)109     inline bool bit_and(mask_cref_type lhs, mask_cref_type rhs, std::size_t = 0)
110     {
111         return (lhs & rhs) != 0;
112     }
113 
114     // returns the number of bits set
115     // taken from https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
count(mask_cref_type mask)116     inline std::size_t count(mask_cref_type mask)
117     {
118         std::size_t c; // c accumulates the total bits set in v
119         for (c = 0; mask; c++)
120         {
121               mask &= mask - 1; // clear the least significant bit set
122         }
123         return c;
124     }
125 
reset(mask_type & mask)126     inline void reset(mask_type& mask)
127     {
128         mask = 0ull;
129     }
130 
131 #define HPX_CPU_MASK_PREFIX "0x"
132 
133 #else
134 # if defined(HPX_HAVE_MAX_CPU_COUNT)
135     typedef std::bitset<HPX_HAVE_MAX_CPU_COUNT> mask_type;
136     typedef std::bitset<HPX_HAVE_MAX_CPU_COUNT> const& mask_cref_type;
137 # else
138     typedef boost::dynamic_bitset<std::uint64_t> mask_type;
139     typedef boost::dynamic_bitset<std::uint64_t> const& mask_cref_type;
140 # endif
141 
142     inline bool any(mask_cref_type mask)
143     {
144         return mask.any();
145     }
146 
147     inline mask_type not_(mask_cref_type mask)
148     {
149         return ~mask;
150     }
151 
152     inline bool test(mask_cref_type mask, std::size_t idx)
153     {
154         return mask.test(idx);
155     }
156 
157     inline void set(mask_type& mask, std::size_t idx)
158     {
159         mask.set(idx);
160     }
161 
162     inline void unset(mask_type& mask, std::size_t idx)
163     {
164         mask.set(idx, 0);
165     }
166 
167     inline std::size_t mask_size(mask_cref_type mask)
168     {
169         return mask.size();
170     }
171 
172     inline void resize(mask_type& mask, std::size_t s)
173     {
174 # if defined(HPX_HAVE_MAX_CPU_COUNT)
175         HPX_ASSERT(s <= mask.size());
176 # else
177         return mask.resize(s);
178 # endif
179     }
180 
181     inline std::size_t find_first(mask_cref_type mask)
182     {
183 # if defined(HPX_HAVE_MAX_CPU_COUNT)
184         if (mask.any())
185         {
186             for (std::size_t i = 0; i != HPX_HAVE_MAX_CPU_COUNT; ++i)
187             {
188                 if (mask[i])
189                     return i;
190             }
191         }
192         return ~std::size_t(0);
193 # else
194         return mask.find_first();
195 # endif
196     }
197 
198 # if defined(HPX_HAVE_MAX_CPU_COUNT)
199 #define HPX_CPU_MASK_PREFIX "0b"
200 #else
201 #define HPX_CPU_MASK_PREFIX "0x"
202 #endif
203 
204     inline bool equal(mask_cref_type lhs, mask_cref_type rhs, std::size_t = 0)
205     {
206         return lhs == rhs;
207     }
208 
209     // return true if at least one of the masks has a bit set
210     inline bool bit_or(mask_cref_type lhs, mask_cref_type rhs, std::size_t = 0)
211     {
212         return (lhs | rhs).any();
213     }
214 
215     // return true if at least one bit is set in both masks
216     inline bool bit_and(mask_cref_type lhs, mask_cref_type rhs, std::size_t = 0)
217     {
218         return (lhs & rhs).any();
219     }
220 
221     // returns the number of bits set
222     inline std::size_t count(mask_cref_type mask)
223     {
224         return mask.count();
225     }
226 
227     inline void reset(mask_type& mask)
228     {
229         mask.reset();
230     }
231 
232 #endif
233 
234     HPX_API_EXPORT std::string to_string(mask_cref_type);
235     /// \endcond
236 }}
237 
238 #endif /*HPX_RUNTIME_THREADS_CPU_MASK_HPP*/
239