1/** 2 * \file 3 * \brief Distributed (percore) memory server: stealing related code 4 */ 5 6/* 7 * Copyright (c) 2007-2011, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#include <stdlib.h> 16#include <stdio.h> 17#include <string.h> 18#include <getopt.h> 19 20#include <inttypes.h> 21#include <barrelfish/barrelfish.h> 22#include <trace/trace.h> 23#include <trace_definitions/trace_defs.h> 24#include <mm/mm.h> 25#include <if/mem_defs.h> 26#include <if/monitor_blocking_defs.h> 27 28#include <thc/thc.h> 29#include <thc/thcsync.h> 30 31#include <if/mem_defs.h> 32#include <if/mem_defs.h> 33#include <if/mem_thc.h> 34 35// #include "barrier.h" 36 37#include "mem_serv.h" 38#include "steal.h" 39 40/// Keep track of our peer mem_servs 41struct peer_core { 42 coreid_t id; 43 bool is_bound; 44 struct mem_thc_client_binding_t cl; 45 thc_lock_t lock; 46}; 47 48coreid_t mycore; 49static struct peer_core *peer_cores; 50static int num_peers; 51 52// FIXME: possible race if handling two concurrent alloc request that both 53// try to connect to the same peer 54static errval_t connect_peer(struct peer_core *peer) 55{ 56 assert(peer != NULL); 57 58 errval_t err; 59 struct mem_binding *b; 60 61 // debug_printf("connecting to %u\n", peer->id); 62 63 char service_name[NAME_LEN]; 64 snprintf(service_name, NAME_LEN, "%s.%d", MEMSERV_DIST, peer->id); 65 66 err = mem_thc_connect_by_name(service_name, 67 get_default_waitset(), 68 IDC_BIND_FLAGS_DEFAULT, 69 &b); 70 if (err_is_fail(err)) { 71 DEBUG_ERR(err, "could not bind (thc)"); 72 return err; 73 } 74 75 err = mem_thc_init_client(&peer->cl, b, b); 76 if (err_is_fail(err)) { 77 DEBUG_ERR(err, "could not init client (thc)"); 78 return err; 79 } 80 81 thc_lock_init(&peer->lock); 82 83 return SYS_ERR_OK; 84} 85 86static errval_t steal_from_serv(struct peer_core *peer, 87 struct capref *ret_cap, 88 uint8_t bits, 89 genpaddr_t minbase, 90 genpaddr_t maxlimit) 91{ 92 assert(peer != NULL); 93 94 errval_t err; 95 96 if (!peer->is_bound) { 97 printf("Connecting to new peer\n"); 98 err = connect_peer(peer); 99 if (err_is_fail(err)) { 100 DEBUG_ERR(err, "failed to connect to peer"); 101 return err; 102 } 103 peer->is_bound = true; 104 } 105 106 // due to the single-waiter rule of thc we need to make sure we only 107 // ever have one of these rpcs outstanding at a time. 108 thc_lock_acquire(&peer->lock); 109 peer->cl.call_seq.steal(&peer->cl, bits, minbase, maxlimit, 110 &err, ret_cap); 111 thc_lock_release(&peer->lock); 112 113 return err; 114} 115 116// Round-robin steal. Try to get memory from each peer in turn. 117static errval_t rr_steal(struct capref *ret_cap, uint8_t bits, 118 genpaddr_t minbase, genpaddr_t maxlimit) 119{ 120 errval_t err = MM_ERR_NOT_FOUND; 121 static int next_serv = 0; 122 123 int serv = next_serv; 124 struct peer_core *peer = &peer_cores[serv]; 125 126 int i; 127 for (i = 0; i < num_peers; i++) { 128 if (serv >= num_peers) { 129 serv = 0; 130 } 131 peer = &peer_cores[serv++]; 132 if (peer->id == mycore) { 133 continue; 134 } 135 printf("%d: Trying to steal from %d/%d\n", disp_get_core_id(), i, num_peers); 136 err = steal_from_serv(peer, ret_cap, bits, minbase, maxlimit); 137 if (err_is_ok(err)) { 138 break; 139 } 140 } 141 next_serv = serv; 142 143 /* 144 if (i >= num_peers) { 145 debug_printf("rr_steal: could not steal from any peers\n"); 146 } 147 */ 148 149 return err; 150} 151 152 153static errval_t steal_and_alloc(struct capref *ret_cap, uint8_t steal_bits, 154 uint8_t alloc_bits, 155 genpaddr_t minbase, genpaddr_t maxlimit) 156{ 157 errval_t err; 158 159 struct capref ramcap; 160 struct capability info; 161 162 /* 163 debug_printf("steal_and_alloc(steal_bits: %d, alloc_bits: %d, " 164 "minbase: 0x%"PRIxGENPADDR", maxlimit: 0x%"PRIxGENPADDR")\n", 165 steal_bits, alloc_bits, minbase, maxlimit); 166 */ 167 168 err = rr_steal(&ramcap, steal_bits, minbase, maxlimit); 169 if (err_is_fail(err)) { 170 return err; 171 } 172 173 // XXX: Mark as local to this core, until we have x-core cap management 174 err = monitor_cap_set_remote(ramcap, false); 175 if(err_is_fail(err)) { 176 DEBUG_ERR(err, "Warning: failed to set cap non-remote. " 177 "This memory will leak."); 178 } 179 180 err = debug_cap_identify(ramcap, &info); 181 if (err_is_fail(err)) { 182 return err_push(err, MON_ERR_CAP_IDENTIFY); 183 } 184#if 0 185 debug_printf("STOLEN cap is type %d Ram base 0x%"PRIxGENPADDR 186 " (%"PRIuGENPADDR") Bits %d\n", 187 info.type, info.u.ram.base, info.u.ram.base, 188 info.u.ram.bits); 189#endif 190 if(steal_bits != log2ceil(info.u.ram.bytes)) { 191 printf("asked for %d bits, but got %d bits of type %d\n", 192 steal_bits, log2ceil(info.u.ram.bytes), info.type); 193 } 194 assert(steal_bits == log2ceil(info.u.ram.bytes)); 195 196 memsize_t mem_to_add = (memsize_t)info.u.ram.bytes; 197 198 err = mm_free(&mm_percore, ramcap, info.u.ram.base, log2ceil(info.u.ram.bytes)); 199 if (err_is_fail(err)) { 200 if (err_no(err) == MM_ERR_NOT_FOUND) { 201 // memory wasn't there initially, add it 202 err = mm_add(&mm_percore, ramcap, log2ceil(info.u.ram.bytes), info.u.ram.base); 203 if (err_is_fail(err)) { 204 return err_push(err, MM_ERR_MM_ADD); 205 } 206 mem_total += mem_to_add; 207 } else { 208 return err_push(err, MM_ERR_MM_FREE); 209 } 210 } 211 212 mem_avail += mem_to_add; 213 214 err = percore_alloc(ret_cap, alloc_bits, minbase, maxlimit); 215 216 return err; 217} 218 219 220void try_steal(errval_t *ret, struct capref *cap, uint8_t bits, 221 genpaddr_t minbase, genpaddr_t maxlimit) 222{ 223 printf("[%d][%"PRIuDOMAINID"]: failed percore alloc request: bits: %d going to STEAL\n", 224 disp_get_core_id(), disp_get_domain_id(), bits); 225 printf("%p %p %p %p %p %p\n", __builtin_return_address(0), 226 __builtin_return_address(1), 227 __builtin_return_address(2), 228 __builtin_return_address(3), 229 __builtin_return_address(4), 230 __builtin_return_address(5)); 231 //DEBUG_ERR(*ret, "allocation of %d bits in 0x%" PRIxGENPADDR 232 // "-0x%" PRIxGENPADDR " failed", bits, minbase, maxlimit); 233 *ret = steal_and_alloc(cap, bits+1, bits, minbase, maxlimit); 234 if (err_is_fail(*ret)) { 235 DEBUG_ERR(*ret, "stealing of %d bits in 0x%" PRIxGENPADDR "-0x%" 236 PRIxGENPADDR " failed", bits, minbase, maxlimit); 237 *cap = NULL_CAP; 238 } 239// *ret = MM_ERR_NOT_FOUND; 240// *cap = NULL_CAP; 241} 242 243errval_t init_peers(coreid_t core, int len_cores, coreid_t *cores) 244{ 245 // initialise info about our peers 246 mycore = core; 247 num_peers = len_cores; 248 peer_cores = malloc(num_peers * sizeof(struct peer_core)); 249 if (peer_cores == NULL) { 250 return LIB_ERR_MALLOC_FAIL; 251 } 252 253 for (int i = 0; i < num_peers; i++) { 254 peer_cores[i].id = cores[i]; 255 peer_cores[i].is_bound = false; 256 } 257 258 return SYS_ERR_OK; 259} 260 261errval_t percore_steal_handler_common(uint8_t bits, 262 genpaddr_t minbase, 263 genpaddr_t maxlimit, 264 struct capref *retcap) 265{ 266 struct capref cap; 267 errval_t err, ret; 268 269 trace_event(TRACE_SUBSYS_MEMSERV, TRACE_EVENT_MEMSERV_PERCORE_ALLOC, bits); 270 /* debug_printf("%d: percore steal request: bits: %d\n", disp_get_core_id(), bits); */ 271 272 // refill slot allocator if needed 273 err = slot_prealloc_refill(mm_percore.slot_alloc_inst); 274 if (err_is_fail(err)) { 275 DEBUG_ERR(err, "Warning: failure in slot_prealloc_refill\n"); 276 cap = NULL_CAP; 277 return err; 278 } 279 280 // refill slab allocator if needed 281 err = slab_refill(&mm_percore.slabs); 282 if (err_is_fail(err)) { 283 DEBUG_ERR(err, "Warning: failure when refilling mm_percore slab\n"); 284 } 285 286 // get actual ram cap 287 ret = percore_alloc(&cap, bits, minbase, maxlimit); 288 if (err_is_fail(ret)){ 289 // debug_printf("percore steal request failed\n"); 290 //DEBUG_ERR(ret, "allocation of stolen %d bits in 0x%" PRIxGENPADDR 291 // "-0x%" PRIxGENPADDR " failed", bits, minbase, maxlimit); 292 cap = NULL_CAP; 293 } 294 295 trace_event(TRACE_SUBSYS_MEMSERV, TRACE_EVENT_MEMSERV_PERCORE_ALLOC_COMPLETE, bits); 296 297 *retcap = cap; 298 return ret; 299} 300 301 302int main(int argc, char ** argv) 303{ 304 return common_main(argc, argv); 305} 306