aos/lib/mdb/mdb.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

275 lines
8.1 KiB
C

/**
* \file
* \brief
*/
/*
* Copyright (c) 2007, 2008, 2010, 2011, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <stdio.h>
#include <string.h>
#include <errors/errno.h>
#include <aos/types.h>
#include <barrelfish_kpi/syscalls.h>
#include <barrelfish_kpi/distcaps.h>
#include <capabilities.h>
#include <cap_predicates.h>
#include <mdb/mdb.h>
#include <mdb/mdb_tree.h>
#include <mdb/mdb_counters.h>
//#include <mdb/types.h>
static void
mdb_set_cte_relations(struct cte *cte, uint8_t relations, uint8_t mask)
{
if (mask & RRELS_COPY_BIT) {
cte->mdbnode.remote_copies = (relations & RRELS_COPY_BIT) != 0;
}
if (mask & RRELS_ANCS_BIT) {
cte->mdbnode.remote_ancs = (relations & RRELS_ANCS_BIT) != 0;
}
if (mask & RRELS_DESC_BIT) {
cte->mdbnode.remote_descs = (relations & RRELS_DESC_BIT) != 0;
}
}
void mdb_set_relations(struct cte *cte, uint8_t relations, uint8_t mask)
{
assert(cte != NULL);
bool old_copies = cte->mdbnode.remote_copies;
bool old_ancs = cte->mdbnode.remote_ancs;
bool old_descs = cte->mdbnode.remote_descs;
mdb_set_cte_relations(cte, relations, mask);
if (cte->mdbnode.remote_copies == old_copies
&& cte->mdbnode.remote_ancs == old_ancs
&& cte->mdbnode.remote_descs == old_descs)
{
// nothing changed
return;
}
// find all copies and set attributes on them
for (struct cte *next = mdb_successor(cte);
next && is_copy(&next->cap, &cte->cap);
next = mdb_successor(next))
{
#ifndef NDEBUG
if (!(next->mdbnode.remote_copies == old_copies
&& next->mdbnode.remote_ancs == old_ancs
&& next->mdbnode.remote_descs == old_descs))
{
printf("WARNING: rrels out of sync! %p:%d%d%d vs %p:%d%d%d\n",
cte, old_copies, old_ancs, old_descs,
next, next->mdbnode.remote_copies,
next->mdbnode.remote_ancs, next->mdbnode.remote_descs);
}
#endif
mdb_set_cte_relations(next, relations, mask);
}
for (struct cte *prev = mdb_predecessor(cte);
prev && is_copy(&prev->cap, &cte->cap);
prev = mdb_predecessor(prev))
{
#ifndef NDEBUG
if (!(prev->mdbnode.remote_copies == old_copies
&& prev->mdbnode.remote_ancs == old_ancs
&& prev->mdbnode.remote_descs == old_descs))
{
printf("WARNING: rrels out of sync! %p:%d%d%d vs %p:%d%d%d\n",
cte, old_copies, old_ancs, old_descs,
prev, prev->mdbnode.remote_copies,
prev->mdbnode.remote_ancs, prev->mdbnode.remote_descs);
}
#endif
mdb_set_cte_relations(prev, relations, mask);
}
}
/// Check if #cte has any descendants
uint64_t mdb_has_descendants_count;
bool has_descendants(struct cte *cte)
{
mdb_has_descendants_count++;
assert(cte != NULL);
struct cte *next = mdb_find_greater(&cte->cap, false);
return next && get_type_root(next->cap.type) == get_type_root(cte->cap.type)
&& get_address(&next->cap) < get_address(&cte->cap) + get_size(&cte->cap);
}
bool has_ancestors(struct cte *cte) {
return mdb_find_ancestor(cte) != NULL;
}
uint64_t mdb_find_ancestor_count = 0;
struct cte *mdb_find_ancestor(struct cte *cte)
{
assert(cte != NULL);
struct cte *result = NULL;
mdb_find_ancestor_count++;
#if 0
// XXX: this check should have its own predicate
if (!get_address(&cte->cap) && !get_size(&cte->cap)) {
return false;
}
#endif
result = mdb_find_less(&cte->cap, false);
if (result
&& get_type_root(result->cap.type) == get_type_root(cte->cap.type)
&& get_address(&result->cap) + get_size(&result->cap)
>= get_address(&cte->cap) + get_size(&cte->cap))
{
return result;
}
// cte is preceded in the ordering by a non-ancestor. This imples one of
// two situations:
// 1) cte has no ancestors
// 2) cte has ancestors but also has siblings earlier in the
// ordering, thus the ancestor cannot have the same base
// address as cte.
// If we query for the zero-length memory region at cte's start
// address, we will not get cte itself back as the end of our query
// is at cte's start address.
// Similarly, we cannot get a sibling of cte that ends where cte
// starts, as the beginning of our query is not in that sibling's
// region.
// Thus we must get its ancestor if present, or no cap at all.
int find_result;
result = NULL;
mdb_find_range(get_type_root(cte->cap.type),
get_address(&cte->cap), 0,
MDB_RANGE_FOUND_SURROUNDING,
&result, &find_result);
if (find_result != MDB_RANGE_NOT_FOUND) {
assert(find_result == MDB_RANGE_FOUND_SURROUNDING);
assert(result);
assert(get_address(&result->cap) <= get_address(&cte->cap));
assert(get_address(&result->cap) + get_size(&result->cap)
>= get_address(&cte->cap) + get_size(&cte->cap));
// don't cound find_ancestor range queries for range query counter
mdb_find_range_count--;
}
else {
assert(!result);
}
return result;
}
uint64_t mdb_has_copies_count;
/// Checks if #cte has any copies
bool has_copies(struct cte *cte)
{
mdb_has_copies_count++;
assert(cte != NULL);
struct cte *next = mdb_successor(cte);
// don't count calls to mdb_successor() from has_copies()
mdb_successor_count--;
if (next && is_copy(&next->cap, &cte->cap)) {
return true;
}
struct cte *prev = mdb_predecessor(cte);
// don't count calls to mdb_predecessor() from has_copies()
mdb_predecessor_count--;
if (prev && is_copy(&prev->cap, &cte->cap)) {
return true;
}
return false;
}
/**
* \brief Returns a copy of the #cap
*/
errval_t mdb_get_copy(struct capability *cap, struct capability **ret)
{
assert(cap != NULL);
assert(ret != NULL);
struct cte *cte = mdb_find_equal(cap);
if (cte) {
*ret = &cte->cap;
return SYS_ERR_OK;
}
else {
return SYS_ERR_NO_LOCAL_COPIES;
}
}
bool mdb_is_sane(void)
{
if (mdb_check_invariants() != 0) {
return false;
}
// TODO: check following conditon on each element of mdb
//if ((lvaddr_t)walk < BASE_PAGE_SIZE || walk->cap.type == ObjType_Null) {
// return false;
//}
return true;
}
/**
* Place #dest_start in the mapping database in the appropriate location.
*
* Look for its relations: copies and descendants and place in accordance.
* If no relations found, place at the top and set map_head to point to it.
*/
void set_init_mapping(struct cte *dest_start, size_t num)
{
for (size_t i = 0; i < num; i++) {
mdb_insert(&dest_start[i]);
}
}
/// Remove one cap from the mapping database
void remove_mapping(struct cte *cte)
{
mdb_remove(cte);
}
void mdb_print_counters(coreid_t core)
{
// create variables that match naming of microbenchmarks
uint64_t insert_one_count = mdb_insert_count;
uint64_t remove_one_count = mdb_remove_count;
uint64_t iterate_1_count = mdb_predecessor_count + mdb_successor_count;
uint64_t has_copies_count = mdb_has_copies_count;
uint64_t has_ancestors_count = mdb_find_ancestor_count;
uint64_t has_descendants_count = mdb_has_descendants_count;
uint64_t query_address_count = mdb_find_range_count;
static uint64_t uid = 0;
printf("[core %d][%"PRIu64"] MDB operation counts:\n", core, uid);
#define PRINT_OP(op) printf("[core %d][%"PRIu64"] " #op "=%"PRIu64"\n", core, uid, op##_count);
PRINT_OP(insert_one);
PRINT_OP(remove_one);
//PRINT_OP(mdb_find_equal);
//PRINT_OP(mdb_find_less);
//PRINT_OP(mdb_find_greater);
PRINT_OP(iterate_1);
PRINT_OP(has_copies);
PRINT_OP(has_ancestors);
PRINT_OP(has_descendants);
PRINT_OP(query_address);
#undef PRINT_OP
uid++;
}