1 /*
2  * Copyright (C) 2018 Joseph Benden <joe@benden.us>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * is provided AS IS, WITHOUT ANY WARRANTY; without even the implied
11  * warranty of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, and
12  * NON-INFRINGEMENT.  See the GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17  * MA 02110-1301, USA.
18  *
19  * In addition, as a special exception, the copyright holders give
20  * permission to link the code of portions of this program with the
21  * OpenSSL library under certain conditions as described in each
22  * individual source file, and distribute linked combinations
23  * including the two.
24  * You must obey the GNU General Public License in all respects
25  * for all of the code used other than OpenSSL.  If you modify
26  * file(s) with this exception, you may extend this exception to your
27  * version of the file(s), but you are not obligated to do so.  If you
28  * do not wish to do so, delete this exception statement from your
29  * version.  If you delete this exception statement from all source
30  * files in the program, then also delete it here.
31  */
32 
33 #include <hwloc.h>
34 #include <assert.h>
35 #include <limits.h>
36 #include <sys/types.h>
37 
38 #include "aircrack-util/cpuset.h"
39 
40 struct ac_cpuset
41 {
42 	size_t nbThreads;
43 
44 	hwloc_topology_t topology;
45 	hwloc_cpuset_t * hwloc_cpusets;
46 };
47 
ac_cpuset_new(void)48 ac_cpuset_t * ac_cpuset_new(void) { return malloc(sizeof(struct ac_cpuset)); }
49 
ac_cpuset_free(ac_cpuset_t * cpuset)50 void ac_cpuset_free(ac_cpuset_t * cpuset) { free(cpuset); }
51 
ac_cpuset_init(ac_cpuset_t * cpuset)52 void ac_cpuset_init(ac_cpuset_t * cpuset)
53 {
54 	assert(cpuset != NULL);
55 
56 	cpuset->nbThreads = 0;
57 	cpuset->hwloc_cpusets = NULL;
58 
59 	hwloc_topology_init(&cpuset->topology);
60 	hwloc_topology_load(cpuset->topology);
61 }
62 
ac_cpuset_destroy(ac_cpuset_t * cpuset)63 void ac_cpuset_destroy(ac_cpuset_t * cpuset)
64 {
65 	assert(cpuset != NULL);
66 
67 	if (cpuset->hwloc_cpusets != NULL)
68 	{
69 		free(cpuset->hwloc_cpusets);
70 		cpuset->hwloc_cpusets = NULL;
71 	}
72 
73 	hwloc_topology_destroy(cpuset->topology);
74 }
75 
ac_cpuset_distribute(ac_cpuset_t * cpuset,size_t count)76 void ac_cpuset_distribute(ac_cpuset_t * cpuset, size_t count)
77 {
78 	assert(cpuset != NULL);
79 
80 	cpuset->nbThreads = count;
81 	cpuset->hwloc_cpusets = calloc(count, sizeof(hwloc_cpuset_t));
82 
83 	if (!cpuset->hwloc_cpusets) return;
84 
85 	hwloc_obj_t root = hwloc_get_root_obj(cpuset->topology);
86 
87 #if defined(HWLOC_API_VERSION) && HWLOC_API_VERSION > 0x00010800
88 	hwloc_distrib(cpuset->topology,
89 				  &root,
90 				  1u,
91 				  cpuset->hwloc_cpusets,
92 				  (unsigned int) count,
93 				  INT_MAX,
94 				  0u);
95 #else
96 	hwloc_distributev(cpuset->topology,
97 					  &root,
98 					  1u,
99 					  cpuset->hwloc_cpusets,
100 					  (unsigned int) count,
101 					  INT_MAX);
102 #endif
103 }
104 
ac_cpuset_bind_thread_at(ac_cpuset_t * cpuset,pthread_t tid,size_t idx)105 void ac_cpuset_bind_thread_at(ac_cpuset_t * cpuset, pthread_t tid, size_t idx)
106 {
107 	assert(cpuset != NULL);
108 
109 	if (idx > cpuset->nbThreads) return;
110 
111 	hwloc_bitmap_singlify(cpuset->hwloc_cpusets[idx]);
112 
113 	if (hwloc_set_thread_cpubind(cpuset->topology,
114 								 tid,
115 								 cpuset->hwloc_cpusets[idx],
116 								 HWLOC_CPUBIND_THREAD))
117 	{
118 		char * str;
119 		int error = errno;
120 		hwloc_bitmap_asprintf(&str, cpuset->hwloc_cpusets[idx]);
121 		fprintf(stderr,
122 				"Couldn't bind thread to cpuset %s: %s\n",
123 				str,
124 				strerror(error));
125 		free(str);
126 	}
127 }
128