Refactor to move alloc stuff to corealloc.c (4/7)
[akaros.git] / kern / src / corealloc.c
1 /* Copyright (c) 2009, 2012, 2015 The Regents of the University of California
2  * Barret Rhoden <brho@cs.berkeley.edu>
3  * Valmon Leymarie <leymariv@berkeley.edu>
4  * Kevin Klues <klueska@cs.berkeley.edu>
5  * See LICENSE for details.
6  */
7
8 #include <arch/topology.h>
9 #include <sys/queue.h>
10 #include <env.h>
11 #include <corerequest.h>
12 #include <kmalloc.h>
13
14 /* The pcores in the system. (array gets alloced in init()).  */
15 struct sched_pcore *all_pcores;
16
17 /* TAILQ of all unallocated, idle (CG) cores */
18 struct sched_pcore_tailq idlecores = TAILQ_HEAD_INITIALIZER(idlecores);
19
20 /* Initialize any data assocaited with doing core allocation. */
21 void corealloc_init(void)
22 {
23         /* Allocate all of our pcores. */
24         all_pcores = kzmalloc(sizeof(struct sched_pcore) * num_cores, 0);
25         /* init the idlecore list.  if they turned off hyperthreading, give them the
26          * odds from 1..max-1.  otherwise, give them everything by 0 (default mgmt
27          * core).  TODO: (CG/LL) better LL/CG mgmt */
28 #ifndef CONFIG_DISABLE_SMT
29         for (int i = 1; i < num_cores; i++)
30                 TAILQ_INSERT_TAIL(&idlecores, pcoreid2spc(i), alloc_next);
31 #else
32         assert(!(num_cores % 2));
33         for (int i = 1; i < num_cores; i += 2)
34                 TAILQ_INSERT_TAIL(&idlecores, pcoreid2spc(i), alloc_next);
35 #endif /* CONFIG_DISABLE_SMT */
36 }
37
38 /* Track the pcore properly when it is allocated to p. This code assumes that
39  * the scheduler that uses it holds a lock for the duration of the call. */
40 void __track_core_alloc(struct proc *p, uint32_t pcoreid)
41 {
42         struct sched_pcore *spc;
43
44         assert(pcoreid < num_cores);    /* catch bugs */
45         spc = pcoreid2spc(pcoreid);
46         assert(spc->alloc_proc != p);   /* corruption or double-alloc */
47         spc->alloc_proc = p;
48         /* if the pcore is prov to them and now allocated, move lists */
49         if (spc->prov_proc == p) {
50                 TAILQ_REMOVE(&p->ksched_data.crd.prov_not_alloc_me, spc, prov_next);
51                 TAILQ_INSERT_TAIL(&p->ksched_data.crd.prov_alloc_me, spc, prov_next);
52         }
53         /* Actually allocate the core, removing it from the idle core list. */
54         TAILQ_REMOVE(&idlecores, spc, alloc_next);
55 }
56
57 /* Track the pcore properly when it is deallocated from p. This code assumes
58  * that the scheduler that uses it holds a lock for the duration of the call.
59  * */
60 void __track_core_dealloc(struct proc *p, uint32_t pcoreid)
61 {
62         struct sched_pcore *spc;
63
64         assert(pcoreid < num_cores);    /* catch bugs */
65         spc = pcoreid2spc(pcoreid);
66         spc->alloc_proc = 0;
67         /* if the pcore is prov to them and now deallocated, move lists */
68         if (spc->prov_proc == p) {
69                 TAILQ_REMOVE(&p->ksched_data.crd.prov_alloc_me, spc, prov_next);
70                 /* this is the victim list, which can be sorted so that we pick the
71                  * right victim (sort by alloc_proc reverse priority, etc).  In this
72                  * case, the core isn't alloc'd by anyone, so it should be the first
73                  * victim. */
74                 TAILQ_INSERT_HEAD(&p->ksched_data.crd.prov_not_alloc_me, spc,
75                                   prov_next);
76         }
77         /* Actually dealloc the core, putting it back on the idle core list. */
78         TAILQ_INSERT_TAIL(&idlecores, spc, alloc_next);
79 }
80
81 /* Bulk interface for __track_core_dealloc */
82 void __track_core_dealloc_bulk(struct proc *p, uint32_t *pc_arr,
83                                uint32_t nr_cores)
84 {
85         for (int i = 0; i < nr_cores; i++)
86                 __track_core_dealloc(p, pc_arr[i]);
87 }
88
89 /* Get an idle core from our pcore list and return its core_id. Don't
90  * consider the chosen core in the future when handing out cores to a
91  * process. This code assumes that the scheduler that uses it holds a lock
92  * for the duration of the call. This will not give out provisioned cores. */
93 int __get_any_idle_core(void)
94 {
95         struct sched_pcore *spc;
96         int ret = -1;
97
98         while ((spc = TAILQ_FIRST(&idlecores))) {
99                 /* Don't take cores that are provisioned to a process */
100                 if (spc->prov_proc)
101                         continue;
102                 assert(!spc->alloc_proc);
103                 TAILQ_REMOVE(&idlecores, spc, alloc_next);
104                 ret = spc2pcoreid(spc);
105                 break;
106         }
107         return ret;
108 }
109
110 /* Detect if a pcore is idle or not. */
111 /* TODO: if we end up using this a lot, track CG-idleness as a property of
112  * the SPC instead of doing a linear search. */
113 static bool __spc_is_idle(struct sched_pcore *spc)
114 {
115         struct sched_pcore *i;
116
117         TAILQ_FOREACH(i, &idlecores, alloc_next) {
118                 if (spc == i)
119                         return TRUE;
120         }
121         return FALSE;
122 }
123
124 /* Same as __get_any_idle_core() except for a specific core id. */
125 int __get_specific_idle_core(int coreid)
126 {
127         struct sched_pcore *spc = pcoreid2spc(coreid);
128         int ret = -1;
129
130         assert((coreid >= 0) && (coreid < num_cores));
131         if (__spc_is_idle(pcoreid2spc(coreid)) && !spc->prov_proc) {
132                 assert(!spc->alloc_proc);
133                 TAILQ_REMOVE(&idlecores, spc, alloc_next);
134                 ret = coreid;
135         }
136         return ret;
137 }
138
139 /* Reinsert a core obtained via __get_any_idle_core() or
140  * __get_specific_idle_core() back into the idlecore map. This code assumes
141  * that the scheduler that uses it holds a lock for the duration of the call.
142  * This will not give out provisioned cores. */
143 void __put_idle_core(int coreid)
144 {
145         struct sched_pcore *spc = pcoreid2spc(coreid);
146
147         assert((coreid >= 0) && (coreid < num_cores));
148         TAILQ_INSERT_TAIL(&idlecores, spc, alloc_next);
149 }