1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_SRC_CORE_LIB_GPRPP_PER_CPU_H
16 #define GRPC_SRC_CORE_LIB_GPRPP_PER_CPU_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <algorithm>
21 #include <cstddef>
22 #include <limits>
23 #include <memory>
24 
25 #include "src/core/lib/iomgr/exec_ctx.h"
26 
27 namespace grpc_core {
28 
29 class PerCpuOptions {
30  public:
31   // Set the number of cpus that colocate on the same shard
SetCpusPerShard(size_t cpus_per_shard)32   PerCpuOptions SetCpusPerShard(size_t cpus_per_shard) {
33     cpus_per_shard_ = std::max<size_t>(1, cpus_per_shard);
34     return *this;
35   }
36 
37   // Set the maximum number of allowable shards
SetMaxShards(size_t max_shards)38   PerCpuOptions SetMaxShards(size_t max_shards) {
39     max_shards_ = std::max<size_t>(1, max_shards);
40     return *this;
41   }
42 
cpus_per_shard()43   size_t cpus_per_shard() const { return cpus_per_shard_; }
max_shards()44   size_t max_shards() const { return max_shards_; }
45 
46   size_t Shards();
47   size_t ShardsForCpuCount(size_t cpu_count);
48 
49  private:
50   size_t cpus_per_shard_ = 1;
51   size_t max_shards_ = std::numeric_limits<size_t>::max();
52 };
53 
54 template <typename T>
55 class PerCpu {
56  public:
57   // Options are not defaulted to try and force consideration of what the
58   // options specify.
PerCpu(PerCpuOptions options)59   explicit PerCpu(PerCpuOptions options) : cpus_(options.Shards()) {}
60 
this_cpu()61   T& this_cpu() { return data_[ExecCtx::Get()->starting_cpu() % cpus_]; }
62 
begin()63   T* begin() { return data_.get(); }
end()64   T* end() { return data_.get() + cpus_; }
begin()65   const T* begin() const { return data_.get(); }
end()66   const T* end() const { return data_.get() + cpus_; }
67 
68  private:
69   const size_t cpus_;
70   std::unique_ptr<T[]> data_{new T[cpus_]};
71 };
72 
73 }  // namespace grpc_core
74 
75 #endif  // GRPC_SRC_CORE_LIB_GPRPP_PER_CPU_H
76