@@ -42,6 +42,9 @@ DEFINE_int32(task_group_runqueue_capacity, 4096,
4242DEFINE_int32 (task_group_ntags, 1 , " TaskGroup will be grouped by number ntags" );
4343DEFINE_bool (task_group_set_worker_name, true ,
4444 " Whether to set the name of the worker thread" );
45+ DEFINE_bool (thread_affinity, false , " Whether to Bind Cores" );
46+ DEFINE_string (cpu_set , " " ,
47+ " Set of CPUs to which cores are bound, for example, 0-3,5,6-7; default: all" );
4548
4649namespace bthread {
4750
@@ -58,6 +61,7 @@ extern pthread_mutex_t g_task_control_mutex;
5861extern BAIDU_THREAD_LOCAL TaskGroup* tls_task_group;
5962void (*g_worker_startfn)() = NULL ;
6063void (*g_tagged_worker_startfn)(bthread_tag_t ) = NULL ;
64+ std::vector<unsigned > TaskControl::_cpus;
6165
6266// May be called in other modules to run startfn in non-worker pthreads.
6367void run_worker_startfn () {
@@ -74,8 +78,17 @@ void run_tagged_worker_startfn(bthread_tag_t tag) {
7478
7579struct WorkerThreadArgs {
7680 WorkerThreadArgs (TaskControl* _c, bthread_tag_t _t) : c(_c), tag(_t) {}
81+
82+ WorkerThreadArgs* set_cpuId (unsigned _cpuId) {
83+ if (FLAGS_thread_affinity) {
84+ cpuId = _cpuId;
85+ }
86+ return this ;
87+ }
88+
7789 TaskControl* c;
7890 bthread_tag_t tag;
91+ unsigned cpuId;
7992};
8093
8194void * TaskControl::worker_thread (void * arg) {
@@ -87,6 +100,9 @@ void* TaskControl::worker_thread(void* arg) {
87100 auto dummy = static_cast <WorkerThreadArgs*>(arg);
88101 auto c = dummy->c ;
89102 auto tag = dummy->tag ;
103+ if (FLAGS_thread_affinity) {
104+ bind_thread (pthread_self (), _cpus[dummy->cpuId ]);
105+ }
90106 delete dummy;
91107 run_tagged_worker_startfn (tag);
92108
@@ -209,6 +225,13 @@ int TaskControl::init(int concurrency) {
209225 }
210226 _concurrency = concurrency;
211227
228+ if (FLAGS_thread_affinity) {
229+ if (parse_cpuset (FLAGS_cpu_set, _cpus) == -1 || _cpus.empty ()) {
230+ LOG (ERROR) << " invalid cpuset=" << FLAGS_cpu_set;
231+ return -1 ;
232+ }
233+ }
234+
212235 // task group group by tags
213236 for (int i = 0 ; i < FLAGS_task_group_ntags; ++i) {
214237 _tagged_ngroup[i].store (0 , std::memory_order_relaxed);
@@ -241,6 +264,7 @@ int TaskControl::init(int concurrency) {
241264 _workers.resize (_concurrency);
242265 for (int i = 0 ; i < _concurrency; ++i) {
243266 auto arg = new WorkerThreadArgs (this , i % FLAGS_task_group_ntags);
267+ arg->set_cpuId (i % _cpus.size ());
244268 const int rc = pthread_create (&_workers[i], NULL , worker_thread, arg);
245269 if (rc) {
246270 delete arg;
@@ -284,6 +308,7 @@ int TaskControl::add_workers(int num, bthread_tag_t tag) {
284308 // _concurrency before create a worker.
285309 _concurrency.fetch_add (1 );
286310 auto arg = new WorkerThreadArgs (this , tag);
311+ arg->set_cpuId ((i + old_concurency) % _cpus.size ());
287312 const int rc = pthread_create (
288313 &_workers[i + old_concurency], NULL , worker_thread, arg);
289314 if (rc) {
@@ -309,6 +334,43 @@ TaskGroup* TaskControl::choose_one_group(bthread_tag_t tag) {
309334 return NULL ;
310335}
311336
337+ int TaskControl::parse_cpuset (std::string value, std::vector<unsigned >& cpus) {
338+ static std::regex r (" (\\ d+-)?(\\ d+)(,(\\ d+-)?(\\ d+))*" );
339+ std::smatch match;
340+ std::set<unsigned > cpuset;
341+ if (value.empty ()) {
342+ cpus = get_current_cpus ();
343+ return 0 ;
344+ }
345+ if (std::regex_match (value, match, r)) {
346+ for (butil::StringSplitter split (value.data (), ' ,' ); split; ++split) {
347+ butil::StringPiece cpuIds (split.field (), split.length ());
348+ cpuIds.trim_spaces ();
349+ butil::StringPiece beg = cpuIds;
350+ butil::StringPiece end = cpuIds;
351+ auto dash = cpuIds.find (' -' );
352+ if (dash != cpuIds.npos ) {
353+ beg = cpuIds.substr (0 , dash);
354+ end = cpuIds.substr (dash + 1 );
355+ }
356+ unsigned b;
357+ unsigned e;
358+ int ret;
359+ ret = butil::StringSplitter (beg, ' \t ' ).to_uint (&b);
360+ ret = ret | butil::StringSplitter (end, ' \t ' ).to_uint (&e);
361+ if (ret != 0 || b > e) {
362+ return -1 ;
363+ }
364+ for (auto i = b; i <= e; ++i) {
365+ cpuset.insert (i);
366+ }
367+ }
368+ cpus.assign (cpuset.begin (), cpuset.end ());
369+ return 0 ;
370+ }
371+ return -1 ;
372+ }
373+
312374#ifdef BRPC_BTHREAD_TRACER
313375void TaskControl::stack_trace (std::ostream& os, bthread_t tid) {
314376 _task_tracer.Trace (os, tid);
0 commit comments