Merge trunk version 208609 into gupc branch.
[official-gcc.git] / libgupc / smp / upc_affinity.c
bloba558b4785349201f0220fc7ca43b34a3a4125b53
1 /* Copyright (C) 2008-2014 Free Software Foundation, Inc.
2 This file is part of the UPC runtime library.
3 Written by Gary Funck <gary@intrepid.com>
4 and Nenad Vukicevic <nenad@intrepid.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
28 #include "upc_config.h"
29 #include "upc_sysdep.h"
30 #include "upc_defs.h"
31 #include "upc_sup.h"
32 #include "upc_affinity.h"
33 #include "upc_numa.h"
35 /* The opaque type upc_cpu_avoid_t, forward references this type. */
36 struct upc_cpu_avoid_struct
38 cpu_set_t cpu_set;
41 int
42 __upc_affinity_supported ()
44 return 1;
47 /* Calculate the right affinity for the thread based on
48 the currnet scheduling and NUMA policies. Executed by
49 the monitoring thread. AVOID is a pointer to a data
50 structure that lists cpu's that aren't eligible for
51 allocation. */
53 int
54 __upc_affinity_init (upc_info_p u, upc_cpu_avoid_p avoid,
55 const char **err_msg)
57 const upc_sched_policy_t sched_policy = u->sched_policy;
58 const int num_cpus = u->num_cpus;
59 const int num_nodes = u->num_nodes;
60 int t, next_sched_cpu;
61 if (!__upc_numa_init (u, err_msg))
62 return 0;
63 /* Calculate affinity for each thread. */
64 for (t = 0, next_sched_cpu = 0; t < THREADS; ++t)
66 const upc_thread_info_p tinfo = &u->thread_info[t];
67 int pelem, melem;
68 int sched_affinity, mem_affinity;
69 switch (sched_policy)
71 case GUPCR_SCHED_POLICY_CPU:
72 /* One cpu = multiple threads */
73 pelem = t % num_cpus;
74 melem = pelem % num_nodes;
75 sched_affinity = pelem;
76 mem_affinity = melem;
77 break;
78 case GUPCR_SCHED_POLICY_CPU_STRICT:
79 /* One cpu = one thread */
80 while (CPU_ISSET (next_sched_cpu, &avoid->cpu_set)
81 && next_sched_cpu < num_cpus)
83 next_sched_cpu += 1;
85 if (next_sched_cpu >= num_cpus)
87 *err_msg = "UPC error: unable to allocate CPU for all threads.";
88 return 0;
90 pelem = next_sched_cpu;
91 melem = pelem % num_nodes;
92 sched_affinity = pelem;
93 mem_affinity = melem;
94 next_sched_cpu += 1;
95 break;
96 case GUPCR_SCHED_POLICY_NODE:
97 /* Use NUMA for node scheduling */
98 if (!__upc_numa_allocate (u, t, &sched_affinity, &mem_affinity,
99 err_msg))
100 return 0;
101 break;
102 default:
103 /* Auto scheduling */
104 sched_affinity = -1;
105 mem_affinity = -1;
107 tinfo->sched_affinity = sched_affinity;
108 tinfo->mem_affinity = mem_affinity;
110 return 1;
113 /* Allocate, and return a pointer to the data structure used to record
114 the list of CPU's that are unavailable. */
116 upc_cpu_avoid_p
117 __upc_affinity_cpu_avoid_new ()
119 upc_cpu_avoid_p avoid;
120 avoid = (upc_cpu_avoid_p) calloc (1, sizeof (upc_cpu_avoid_t));
121 if (!avoid)
123 perror ("calloc");
124 abort ();
126 return avoid;
129 /* Free the previously allocated data structure that is used
130 to record list of CPU's that are unavailable. */
132 void
133 __upc_affinity_cpu_avoid_free (const upc_cpu_avoid_p avoid)
135 if (avoid)
136 free ((void *) avoid);
139 /* Mark CPU as being unavailable for allocation. */
141 void
142 __upc_affinity_cpu_avoid_set (const int cpu, const upc_cpu_avoid_p avoid)
144 CPU_SET (cpu, &avoid->cpu_set);
147 #ifdef DEBUG_AFFINITY
148 static const char *
149 upc_sched_policy_to_string (const upc_sched_policy_t sched_policy)
151 switch (sched_policy)
153 case GUPCR_SCHED_POLICY_AUTO:
154 return "sched auto";
155 case GUPCR_SCHED_POLICY_NODE:
156 return "sched node";
157 case GUPCR_SCHED_POLICY_CPU:
158 return "sched cpu";
159 case GUPCR_SCHED_POLICY_CPU_STRICT:
160 return "sched strict";
162 return "sched <unknown>";
165 static const char *
166 upc_mem_policy_to_string (const upc_mem_policy_t mem_policy)
168 switch (mem_policy)
170 case GUPCR_MEM_POLICY_AUTO:
171 return "mem auto";
172 case GUPCR_MEM_POLICY_NODE:
173 return "mem node";
174 case GUPCR_MEM_POLICY_STRICT:
175 return "mem strict";
177 return "mem <unknown>";
179 #endif /* DEBUG_AFFINITY */
181 /* Set thread's affinity based on the pre-calculated
182 policies. Executed by each thread as the first thing after thread
183 is created. */
185 void
186 __upc_affinity_set (upc_info_p u, int thread_id)
188 const upc_thread_info_p tinfo = &u->thread_info[thread_id];
189 switch (u->sched_policy)
191 case GUPCR_SCHED_POLICY_CPU:
192 case GUPCR_SCHED_POLICY_CPU_STRICT:
194 const int sched_affinity = tinfo->sched_affinity;
195 cpu_set_t set;
196 CPU_ZERO (&set);
197 CPU_SET (sched_affinity, &set);
198 if (sched_setaffinity (0, sizeof (set), &set))
200 __upc_fatal ("Scheduling cannot be set");
203 break;
204 case GUPCR_SCHED_POLICY_NODE:
205 __upc_numa_sched_set (u, thread_id);
206 break;
207 default:
208 /* auto - no scheduling support */
209 break;
211 /* set memory policy only if we are not AUTO scheduling */
212 if ((u->sched_policy != GUPCR_SCHED_POLICY_AUTO) &&
213 (u->mem_policy != GUPCR_MEM_POLICY_AUTO))
214 __upc_numa_memory_affinity_set (u, thread_id);
215 #ifdef DEBUG_AFFINITY
216 printf ("affinity: %d (%s,%s) scheduling (%d,%d)\n", thread_id,
217 upc_sched_policy_to_string (u->sched_policy),
218 upc_mem_policy_to_string (u->mem_policy),
219 tinfo->sched_affinity, tinfo->mem_affinity);
220 #endif /* DEBUG_AFFINITY */