diff --git a/src/Makefile.am b/src/Makefile.am index 7556089b828cb901f0ba2b1e576cf4793e3e1e8e..0d3be275a2fa224f9f3e591c702a07ce00897f9f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,7 @@ include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ logger_io.h tracers_io.h tracers.h tracers_struct.h star_formation_io.h fof.h \ star_formation_struct.h star_formation.h star_formation_iact.h \ star_formation_logger.h star_formation_logger_struct.h \ - velociraptor_struct.h velociraptor_io.h random.h memuse.h black_holes.h black_holes_io.h \ + velociraptor_struct.h velociraptor_io.h random.h memuse.h memuse_rnodes.h black_holes.h black_holes_io.h \ black_holes_properties.h black_holes_struct.h feedback.h feedback_struct.h feedback_properties.h # source files for EAGLE cooling @@ -78,7 +78,7 @@ AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c engine_maketasks.c part_type.c xmf.c gravity_properties.c gravity.c \ collectgroup.c hydro_space.c equation_of_state.c \ chemistry.c cosmology.c restart.c mesh_gravity.c velociraptor_interface.c \ - outputlist.c velociraptor_dummy.c logger_io.c memuse.c fof.c \ + outputlist.c velociraptor_dummy.c logger_io.c memuse.c memuse_rnodes.c fof.c \ hashmap.c \ $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) diff --git a/src/memuse.c b/src/memuse.c index 77344cc6cec56544a6e19cc6a71ca2375aa1916c..f3470f6c4569067d4f352cfb970c57d8562745b4 100644 --- a/src/memuse.c +++ b/src/memuse.c @@ -20,6 +20,7 @@ /** * @file memuse.c * @brief file of routines to report about memory use in SWIFT. + * Includes MPI exchanges made by the tasks. * Note reports are in KB. */ @@ -29,6 +30,8 @@ /* Standard includes. */ #include <stdio.h> #include <stdlib.h> +#include <stdint.h> +#include <string.h> #include <sys/types.h> #include <unistd.h> @@ -39,6 +42,8 @@ #include "atomic.h" #include "clocks.h" #include "engine.h" +#include "error.h" +#include "memuse_rnodes.h" #ifdef SWIFT_MEMUSE_REPORTS @@ -101,254 +106,10 @@ struct memuse_labelled_item { size_t count; }; -/* A radix node, this has a single byte key and a pointer to some related - * resource. It also holds a sorted list of children, if any. */ -struct memuse_rnode { - - /* Byte key of this node. */ - uint8_t keypart; - - /* Value of this node, if set. */ - void *ptr; - - /* Sorted pointers to children of this node. */ - struct memuse_rnode **children; - unsigned int count; -}; - /* Persistent radix trie root node. Holds active logs between dumps. */ static struct memuse_rnode *memuse_rnode_root; static int memuse_rnode_root_init = 1; -#ifdef MEMUSE_RNODE_DUMP -/** - * @brief Dump a representation of the radix tree rooted at a node to stdout. - * - * @param depth the depth of the node in the tree, root is 0. - * @param node the node at which to start dumping. - * @param full if not zero then nodes that are not storing a value - * are also reported. - */ -static void memuse_rnode_dump(int depth, struct memuse_rnode *node, int full) { - - /* Value of the full key, to this depth. Assumes full key is a pointer, - * so uncomment when using strings. */ - static union { - // uint8_t key[MEMUSE_MAXLABLEN]; - // char ptr[MEMUSE_MAXLABLEN]; - uint8_t key[sizeof(uintptr_t)]; - void *ptr; - } keyparts = {0}; - - /* Record keypart at this depth. Root has no keypart. */ - if (depth != 0) keyparts.key[depth - 1] = node->keypart; - - // if (node->ptr != NULL || full) { - // keyparts.key[depth] = '\0'; - // - // /* Gather children's keys if full. */ - // char fullkey[MEMUSE_MAXLABLEN]; - // if (full) { - // for (size_t k = 0; k < node->count; k++) { - // fullkey[k] = node->children[k]->keypart; - // } - // fullkey[node->count] = '\0'; - // printf("dump @ depth: %d keypart: %d key: %s value: %p fullkey: %s\n", - // depth, node->keypart, keyparts.ptr, node->ptr, fullkey); - // } else { - // printf("dump @ depth: %d keypart: %d key: %s value: %p\n", depth, - // node->keypart, keyparts.ptr, node->ptr); - // } - //} - - if (node->ptr != NULL || full) { - printf("dump @ depth: %d keypart: %d key: %p value: %p\n", depth, - node->keypart, keyparts.ptr, node->ptr); - } - - /* Recurse to all children. */ - for (size_t k = 0; k < node->count; k++) { - memuse_rnode_dump(depth + 1, node->children[k], full); - } -} -#endif - -/** - * @brief Return the position of a keypart for a list of children. - * If not found returns where it would be inserted. - * - * @param keypart the keypart to locate. - * @param children the list of sorted children. - * @param count the number of children - * - * @return the index of key or where it should be inserted. - */ -static unsigned int memuse_rnode_bsearch(uint8_t keypart, - struct memuse_rnode **children, - unsigned int count) { - - /* Search for lower bound. */ - unsigned int lower = 0; - unsigned int upper = count; - while (lower < upper) { - unsigned int middle = (upper + lower) / 2; - if (keypart > children[middle]->keypart) - lower = middle + 1; - else - upper = middle; - } - return lower; -} - -/** - * @brief Insert a child, if needed, into a list of children. Assumes - * we have sufficient room. - * - * @param child the child to insert, if needed. - * @param children the list of sorted children. - * @param count the number of children - */ -static void memuse_rnode_binsert_child(struct memuse_rnode *child, - struct memuse_rnode **children, - unsigned int *count) { - unsigned int pos = 0; - if (*count > 0) { - - /* Find the child or insertion point. */ - pos = memuse_rnode_bsearch(child->keypart, children, *count); - - /* If not found move all children to make a space, unless we're inserting - * after the end. */ - if (pos < *count && children[pos]->keypart != child->keypart) { - memmove(&children[pos + 1], &children[pos], - (*count - pos) * sizeof(struct memuse_rnode *)); - } - } - - /* Insert new child */ - children[pos] = child; - *count += 1; -} - -/** - * @brief Add a child rnode to an rnode. Making sure we have room and keeping - * the sort order. - * - * @param node the parent node. - * @param child the node to add to the parent, - */ -static void memuse_rnode_add_child(struct memuse_rnode *node, - struct memuse_rnode *child) { - - /* Extend the children list to include a new entry .*/ - void *mem = realloc(node->children, - (node->count + 1) * sizeof(struct memuse_rnode *)); - if (mem == NULL) error("Failed to reallocate rnodes\n"); - node->children = mem; - - /* Insert the new child. */ - memuse_rnode_binsert_child(child, node->children, &node->count); -} - -/** - * @brief Find a child of a node with the given key part. - * - * @param node the node to search. - * @param keypart the key part of the child. - * @return NULL if not found. - */ -static struct memuse_rnode *memuse_rnode_lookup(const struct memuse_rnode *node, - uint8_t keypart) { - - /* Locate the key, or where it would be inserted. */ - if (node->count > 0) { - unsigned int index = - memuse_rnode_bsearch(keypart, node->children, node->count); - if (index < node->count && keypart == node->children[index]->keypart) { - return node->children[index]; - } - } - return NULL; -} - -/** - * @brief insert a child into a node's children list and add a pointer, iff - * this is the destination node for the given key. - * - * @param node the parent node. - * @param depth the depth of the parent node. - * @param key the full key of the eventual leaf node. - * @param keylen the numbers of bytes in the full key. - * @param value pointer that will be stored as the value of the leaf node. - */ -static void memuse_rnode_insert_child(struct memuse_rnode *node, uint8_t depth, - uint8_t *key, uint8_t keylen, - void *value) { - - /* Check if keypart this already exists at this level and add new child if - * not. */ - uint8_t keypart = key[depth]; - struct memuse_rnode *child = memuse_rnode_lookup(node, keypart); - if (child == NULL) { - child = calloc(1, sizeof(struct memuse_rnode)); - child->keypart = keypart; - memuse_rnode_add_child(node, child); - } - - /* Are we at the lowest level yet? */ - depth++; - if (depth == keylen) { - /* Our destination node. */ - -#if SWIFT_DEBUG_CHECKS - if (child->ptr != NULL) - message("Overwriting rnode value: %p with %p", child->ptr, value); -#endif - child->ptr = value; - return; - } - - /* Down we go to the next level. */ - memuse_rnode_insert_child(child, depth, key, keylen, value); - return; -} - -/** - * @brief Find a child node for the given full key. - * - * @param node the current parent node. - * @param depth the depth of the parent node, 0 for first call. - * @param key the full key of the expected child node. - * @param keylen the number of bytes in the key. - */ -static struct memuse_rnode *memuse_rnode_find_child(struct memuse_rnode *node, - uint8_t depth, uint8_t *key, - uint8_t keylen) { - uint8_t keypart = key[depth]; - struct memuse_rnode *child = NULL; - if (node->count > 0) child = memuse_rnode_lookup(node, keypart); - if (child != NULL && (depth + 1) < keylen) { - return memuse_rnode_find_child(child, depth + 1, key, keylen); - } - return child; -} - -/** - * @brief Free all resources associated with a node. - * - * @param node the rnode. - */ -static void memuse_rnode_cleanup(struct memuse_rnode *node) { - - if (!node) return; - - for (size_t k = 0; k < node->count; k++) { - memuse_rnode_cleanup(node->children[k]); - free(node->children[k]); - } - if (node->count > 0) free(node->children); -} - /** * @brief reallocate the entries log if space is needed. */ diff --git a/src/memuse_rnodes.c b/src/memuse_rnodes.c new file mode 100644 index 0000000000000000000000000000000000000000..daf8164fe4d39a2532287e1bfc8b2d132bf05b19 --- /dev/null +++ b/src/memuse_rnodes.c @@ -0,0 +1,271 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2019 Peter W. Draper (p.w.draper@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/** + * @file memuse_rnode.c + * @brief file of routines used for radix nodes in memory loggers. + */ + +/* Config parameters. */ +#include "../config.h" + +/* Standard includes. */ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +/* Local defines. */ +#include "memuse_rnodes.h" + +/* Local includes. */ +#include "atomic.h" +#include "clocks.h" +#include "error.h" + +/** + * @brief Return the position of a keypart for a list of children. + * If not found returns where it would be inserted. + * + * @param keypart the keypart to locate. + * @param children the list of sorted children. + * @param count the number of children + * + * @return the index of key or where it should be inserted. + */ +static unsigned int memuse_rnode_bsearch(uint8_t keypart, + struct memuse_rnode **children, + unsigned int count) { + + /* Search for lower bound. */ + unsigned int lower = 0; + unsigned int upper = count; + while (lower < upper) { + unsigned int middle = (upper + lower) / 2; + if (keypart > children[middle]->keypart) + lower = middle + 1; + else + upper = middle; + } + return lower; +} + +/** + * @brief Insert a child, if needed, into a list of children. Assumes + * we have sufficient room. + * + * @param child the child to insert, if needed. + * @param children the list of sorted children. + * @param count the number of children + */ +static void memuse_rnode_binsert_child(struct memuse_rnode *child, + struct memuse_rnode **children, + unsigned int *count) { + unsigned int pos = 0; + if (*count > 0) { + + /* Find the child or insertion point. */ + pos = memuse_rnode_bsearch(child->keypart, children, *count); + + /* If not found move all children to make a space, unless we're inserting + * after the end. */ + if (pos < *count && children[pos]->keypart != child->keypart) { + memmove(&children[pos + 1], &children[pos], + (*count - pos) * sizeof(struct memuse_rnode *)); + } + } + + /* Insert new child */ + children[pos] = child; + *count += 1; +} + +/** + * @brief Add a child rnode to an rnode. Making sure we have room and keeping + * the sort order. + * + * @param node the parent node. + * @param child the node to add to the parent, + */ +static void memuse_rnode_add_child(struct memuse_rnode *node, + struct memuse_rnode *child) { + + /* Extend the children list to include a new entry .*/ + void *mem = realloc(node->children, + (node->count + 1) * sizeof(struct memuse_rnode *)); + if (mem == NULL) error("Failed to reallocate rnodes\n"); + node->children = mem; + + /* Insert the new child. */ + memuse_rnode_binsert_child(child, node->children, &node->count); +} + +/** + * @brief Find a child of a node with the given key part. + * + * @param node the node to search. + * @param keypart the key part of the child. + * @return NULL if not found. + */ +static struct memuse_rnode *memuse_rnode_lookup(const struct memuse_rnode *node, + uint8_t keypart) { + + /* Locate the key, or where it would be inserted. */ + if (node->count > 0) { + unsigned int index = + memuse_rnode_bsearch(keypart, node->children, node->count); + if (index < node->count && keypart == node->children[index]->keypart) { + return node->children[index]; + } + } + return NULL; +} + +/** + * @brief insert a child into a node's children list and add a pointer, iff + * this is the destination node for the given key. + * + * @param node the parent node. + * @param depth the depth of the parent node. + * @param key the full key of the eventual leaf node. + * @param keylen the numbers of bytes in the full key. + * @param value pointer that will be stored as the value of the leaf node. + */ +void memuse_rnode_insert_child(struct memuse_rnode *node, uint8_t depth, + uint8_t *key, uint8_t keylen, + void *value) { + + /* Check if keypart this already exists at this level and add new child if + * not. */ + uint8_t keypart = key[depth]; + struct memuse_rnode *child = memuse_rnode_lookup(node, keypart); + if (child == NULL) { + child = calloc(1, sizeof(struct memuse_rnode)); + child->keypart = keypart; + memuse_rnode_add_child(node, child); + } + + /* Are we at the lowest level yet? */ + depth++; + if (depth == keylen) { + /* Our destination node. */ + +#if SWIFT_DEBUG_CHECKS + if (child->ptr != NULL) + message("Overwriting rnode value: %p with %p", child->ptr, value); +#endif + child->ptr = value; + return; + } + + /* Down we go to the next level. */ + memuse_rnode_insert_child(child, depth, key, keylen, value); + return; +} + +/** + * @brief Find a child node for the given full key. + * + * @param node the current parent node. + * @param depth the depth of the parent node, 0 for first call. + * @param key the full key of the expected child node. + * @param keylen the number of bytes in the key. + */ +struct memuse_rnode *memuse_rnode_find_child(struct memuse_rnode *node, + uint8_t depth, uint8_t *key, + uint8_t keylen) { + uint8_t keypart = key[depth]; + struct memuse_rnode *child = NULL; + if (node->count > 0) child = memuse_rnode_lookup(node, keypart); + if (child != NULL && (depth + 1) < keylen) { + return memuse_rnode_find_child(child, depth + 1, key, keylen); + } + return child; +} + +/** + * @brief Free all resources associated with a node. + * + * @param node the rnode. + */ +void memuse_rnode_cleanup(struct memuse_rnode *node) { + + if (!node) return; + + for (size_t k = 0; k < node->count; k++) { + memuse_rnode_cleanup(node->children[k]); + free(node->children[k]); + } + if (node->count > 0) free(node->children); +} + +/** + * @brief Dump a representation of the radix tree rooted at a node to stdout. + * + * Debugging code. + * + * @param depth the depth of the node in the tree, root is 0. + * @param node the node at which to start dumping. + * @param full if not zero then nodes that are not storing a value + * are also reported. + */ +void memuse_rnode_dump(int depth, struct memuse_rnode *node, int full) { + + /* Value of the full key, to this depth. Assumes full key is a pointer, + * so uncomment when using strings. */ + static union { + // uint8_t key[MEMUSE_MAXLABLEN]; + // char ptr[MEMUSE_MAXLABLEN]; + uint8_t key[sizeof(uintptr_t)]; + void *ptr; + } keyparts = {0}; + + /* Record keypart at this depth. Root has no keypart. */ + if (depth != 0) keyparts.key[depth - 1] = node->keypart; + + // if (node->ptr != NULL || full) { + // keyparts.key[depth] = '\0'; + // + // /* Gather children's keys if full. */ + // char fullkey[MEMUSE_MAXLABLEN]; + // if (full) { + // for (size_t k = 0; k < node->count; k++) { + // fullkey[k] = node->children[k]->keypart; + // } + // fullkey[node->count] = '\0'; + // printf("dump @ depth: %d keypart: %d key: %s value: %p fullkey: %s\n", + // depth, node->keypart, keyparts.ptr, node->ptr, fullkey); + // } else { + // printf("dump @ depth: %d keypart: %d key: %s value: %p\n", depth, + // node->keypart, keyparts.ptr, node->ptr); + // } + //} + + if (node->ptr != NULL || full) { + printf("dump @ depth: %d keypart: %d key: %p value: %p\n", depth, + node->keypart, keyparts.ptr, node->ptr); + } + + /* Recurse to all children. */ + for (size_t k = 0; k < node->count; k++) { + memuse_rnode_dump(depth + 1, node->children[k], full); + } +} diff --git a/src/memuse_rnodes.h b/src/memuse_rnodes.h new file mode 100644 index 0000000000000000000000000000000000000000..e1f4b2bce4ad56d0571e8d74b1d8b705ed2be29d --- /dev/null +++ b/src/memuse_rnodes.h @@ -0,0 +1,52 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2018 Peter W. Draper (p.w.draper@durham.ac.uk) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_MEMUSE_RNODE_H +#define SWIFT_MEMUSE_RNODE_H + +/* Config parameters. */ +#include "../config.h" + +/* Includes. */ +#include <stdlib.h> + +/* A radix node, this has a single byte key and a pointer to some related + * resource. It also holds a sorted list of children, if any. */ +struct memuse_rnode { + + /* Byte key of this node. */ + uint8_t keypart; + + /* Value of this node, if set. */ + void *ptr; + + /* Sorted pointers to children of this node. */ + struct memuse_rnode **children; + unsigned int count; +}; + +void memuse_rnode_dump(int depth, struct memuse_rnode *node, int full); +void memuse_rnode_insert_child(struct memuse_rnode *node, uint8_t depth, + uint8_t *key, uint8_t keylen, + void *value); +struct memuse_rnode *memuse_rnode_find_child(struct memuse_rnode *node, + uint8_t depth, uint8_t *key, + uint8_t keylen); +void memuse_rnode_cleanup(struct memuse_rnode *node); + +#endif /* SWIFT_MEMUSE_RNODE_H */