diff --git a/logger/Makefile.am b/logger/Makefile.am index f18e11a8ca6eefa2e4edb4fbf946930250dacbf3..29fc5213dc997dee014ac183e7241ed9f6605f55 100644 --- a/logger/Makefile.am +++ b/logger/Makefile.am @@ -48,11 +48,11 @@ SUBDIRS = tests # List required headers include_HEADERS = logger_header.h logger_loader_io.h logger_particle.h logger_time.h logger_tools.h logger_reader.h \ - logger_index.h logger_logfile.h + logger_logfile.h # Common source files AM_SOURCES = logger_header.c logger_loader_io.c logger_particle.c logger_time.c logger_tools.c logger_reader.c \ - logger_index.c logger_logfile.c + logger_logfile.c if HAVEPYTHON AM_SOURCES += logger_python_wrapper.c endif diff --git a/logger/logger_loader_io.c b/logger/logger_loader_io.c index e879dea0f25da9e3385910c6545f612211dc918a..f18f9bb7eb2eaf88ba11eaf916c0a68a27cfd2d2 100644 --- a/logger/logger_loader_io.c +++ b/logger/logger_loader_io.c @@ -59,7 +59,8 @@ void *logger_loader_io_mmap_file(char *filename, size_t *file_size, else fd = open(filename, O_RDWR); - if (fd == -1) error("Unable to open file %s (%s).", filename, strerror(errno)); + if (fd == -1) + error("Unable to open file %s (%s).", filename, strerror(errno)); /* get the file size. */ *file_size = logger_loader_io_get_file_size(fd); diff --git a/logger/logger_particle.c b/logger/logger_particle.c index b159b521a0df1831008791e5540861d788a065b2..6809e0edf6125e66cbb8807cc98eeb31b5e04ecd 100644 --- a/logger/logger_particle.c +++ b/logger/logger_particle.c @@ -154,8 +154,10 @@ size_t logger_particle_read(struct logger_particle *part, } } - /* Get the time of current record. */ - if (times->next) { + /* Get the time of current record. + This check is required for the manipulating the file before + the initialization of the time_array. */ + if (times->size != 0) { part->time = time_array_get_time(times, offset); } else part->time = -1; diff --git a/logger/logger_reader.h b/logger/logger_reader.h index 3a964aea29e5f72253080f23f6a105bfab7740eb..c4a3ba8912676cf332344e6ec4ebd2943a8afa79 100644 --- a/logger/logger_reader.h +++ b/logger/logger_reader.h @@ -47,7 +47,6 @@ #ifndef __LOGGER_LOGGER_READER_H__ #define __LOGGER_LOGGER_READER_H__ -#include "logger_index.h" #include "logger_loader_io.h" #include "logger_logfile.h" #include "logger_particle.h" @@ -66,9 +65,6 @@ struct logger_reader { /* Time of each index file. #TODO */ double *times; - /* Information contained in the index file. */ - struct logger_index index; - /* Informations contained in the file header. */ struct logger_logfile log; diff --git a/logger/logger_time.c b/logger/logger_time.c index a88745876acea9c7f4f4736afb82fec5be450b22..125c7ea94b3866daedcd1391df3c9f7d98736a26 100644 --- a/logger/logger_time.c +++ b/logger/logger_time.c @@ -21,6 +21,51 @@ #include "logger_logfile.h" #include "logger_reader.h" +/** + * @brief Check if enough space is available and increase it if required. + * + * @param t The #time_array. + */ +void time_array_ensure_size(struct time_array *t) { + /* Check if we still have some place. */ + if (t->size < t->capacity) return; + + /* Increase the size */ + t->capacity *= 2; + + t->time = realloc(t->time, sizeof(double) * t->capacity); + if (t->time == NULL) error("Failed to realloc time memory."); + + t->int_time = realloc(t->int_time, sizeof(integertime_t) * t->capacity); + if (t->int_time == NULL) error("Failed to realloc integer time memory."); + + t->offset = realloc(t->offset, sizeof(size_t) * t->capacity); + if (t->offset == NULL) error("Failed to realloc offset memory."); +} + +/** + * @brief Add an element to the #time_array. + * + * @param t The #time_array. + * @param int_time The time in integer. + * @param time The time in double. + * @param offset The offset of the record. + */ +void time_array_append(struct time_array *t, const integertime_t int_time, + const double time, const size_t offset) { + + /* Increase the available space if required */ + time_array_ensure_size(t); + + /* Copy the values */ + t->time[t->size] = time; + t->int_time[t->size] = int_time; + t->offset[t->size] = offset; + + /* Increase the size used. */ + t->size += 1; +} + /** * @brief read a time record. * @@ -95,8 +140,19 @@ size_t time_offset_first_record(const struct header *h) { * @param t #time_array to initialize. */ void time_array_init(struct time_array *t) { - t->next = NULL; - t->prev = NULL; + /* Allocate the arrays */ + t->int_time = malloc(sizeof(integertime_t) * LOGGER_TIME_INIT_SIZE); + if (t->int_time == NULL) error("Failed to initialize the integer times."); + + t->time = malloc(sizeof(double) * LOGGER_TIME_INIT_SIZE); + if (t->time == NULL) error("Failed to initialize the times."); + + t->offset = malloc(sizeof(size_t) * LOGGER_TIME_INIT_SIZE); + if (t->offset == NULL) error("Failed to initialize the offsets."); + + /* Initialize the sizes */ + t->size = 0; + t->capacity = LOGGER_TIME_INIT_SIZE; } /** @@ -108,9 +164,6 @@ void time_array_init(struct time_array *t) { void time_array_populate(struct time_array *t, struct logger_logfile *log) { /* Initialize a few variables. */ - t->next = NULL; - t->prev = NULL; - integertime_t int_time = 0; double time = 0; @@ -121,81 +174,69 @@ void time_array_populate(struct time_array *t, struct logger_logfile *log) { size_t offset = time_offset_first_record(&log->header); while (offset < file_size) { /* read current time record and store it. */ - t->offset = offset; size_t tmp_offset = offset; time_read(&int_time, &time, log->reader, tmp_offset); - t->int_time = int_time; - t->time = time; + time_array_append(t, int_time, time, offset); /* get next record. */ int test = tools_get_next_record(&log->header, log->log.map, &offset, log->log.file_size); if (test == -1) break; - - /* allocate next time_array. */ - struct time_array *tmp = malloc(sizeof(struct time_array)); - tmp->prev = t; - tmp->next = NULL; - t->next = tmp; - t = tmp; } - - /* free unused time_array. */ - struct time_array *tmp = t->prev; - tmp->next = NULL; - free(t); } /** - * @brief access the time of a given record (by its offset) + * @brief access the time of a given record (by its offset). * - * @param t #time_array to access - * @param offset offset of the record + * @param t #time_array to access. + * @param offset offset of the record. * - * @return integer time of the record + * @return integer time of the record. */ integertime_t time_array_get_integertime(struct time_array *t, const size_t offset) { - const struct time_array *tmp = time_array_get_time_array(t, offset); - return tmp->int_time; + size_t ind = time_array_get_index(t, offset); + return t->int_time[ind]; } /** - * @brief access the time of a given record (by its offset) + * @brief access the time of a given record (by its offset). * - * @param t #time_array to access - * @param offset offset of the record + * @param t #time_array to access. + * @param offset offset of the record. * - * @return time of the record + * @return time of the record. */ double time_array_get_time(const struct time_array *t, const size_t offset) { - const struct time_array *tmp = time_array_get_time_array(t, offset); - return tmp->time; + size_t ind = time_array_get_index(t, offset); + return t->time[ind]; } /** - * @brief access the #time_array of a given record (by its offset) + * @brief Find the index of the last time record written before a given offset. * * @param t #time_array to access. * @param offset offset of the record. * - * @return pointer to the requested #time_array + * @return The index of the last time record. */ -struct time_array *time_array_get_time_array(const struct time_array *t, - const size_t offset) { +size_t time_array_get_index(const struct time_array *t, const size_t offset) { #ifdef SWIFT_DEBUG_CHECKS if (!t) error("NULL pointer."); #endif - const struct time_array *tmp; + /* Find the time_array with the correct offset. */ - for (tmp = t; tmp->next && tmp->offset <= offset; tmp = tmp->next) { - } + for (size_t i = 1; i < t->size; i++) { + if (offset < t->offset[i]) { + return i - 1; + } - /* If providing the offset of a time_array, need to give it back. */ - if (tmp->offset == offset) return (struct time_array *)tmp; + else if (offset == t->offset[i]) + return i; + } - return (struct time_array *)tmp->prev; + error("Unable to find the required offset."); } /** @@ -204,11 +245,19 @@ struct time_array *time_array_get_time_array(const struct time_array *t, * @param t #time_array to free */ void time_array_free(struct time_array *t) { - struct time_array *tmp; - for (tmp = t; t->next; t = tmp) { - tmp = t->next; - free(t); - } + /* Free the arrays */ + free(t->int_time); + t->int_time = NULL; + + free(t->time); + t->time = NULL; + + free(t->offset); + t->offset = NULL; + + /* Reset the counters */ + t->size = 0; + t->capacity = 0; } /** @@ -217,21 +266,18 @@ void time_array_free(struct time_array *t) { * @param t #time_array to print */ void time_array_print(const struct time_array *t) { - size_t threshold = 4; + const size_t threshold = 4; - size_t n = time_array_count(t); + size_t n = t->size; size_t up_threshold = n - threshold; - printf("Times (size %lu): [%lli (%g)", n, t->int_time, t->time); + printf("Times (size %lu): [%lli (%g)", n, t->int_time[0], t->time[0]); /* Loop over all elements. */ for (size_t i = 1; i < n; i++) { - if (!t->next) error("Next pointer not initialized %zi.", i); - - t = t->next; /* Skip the times at the center of the array. */ if (i < threshold || i > up_threshold) - printf(", %lli (%g)", t->int_time, t->time); + printf(", %lli (%g)", t->int_time[i], t->time[i]); if (i == threshold) printf(", ..."); } @@ -245,37 +291,20 @@ void time_array_print(const struct time_array *t) { * @param t #time_array to print */ void time_array_print_offset(const struct time_array *t) { - size_t threshold = 4; + const size_t threshold = 4; - size_t n = time_array_count(t); + size_t n = t->size; size_t up_threshold = n - threshold; - printf("Times (size %lu): [%lu", n, t->offset); + printf("Times (size %lu): [%lu", n, t->offset[0]); /* Loop over all elements. */ for (size_t i = 1; i < n; i++) { - t = t->next; /* Skip the offset in the middle of the array. */ - if (i < threshold || i > up_threshold) printf(", %lu", t->offset); + if (i < threshold || i > up_threshold) printf(", %lu", t->offset[i]); if (i == threshold) printf(", ..."); } printf("]\n"); } - -/** - * @brief count number of element in #time_array - * - * @param t #time_array to count - * - * @return number of element - */ -size_t time_array_count(const struct time_array *t) { - size_t count = 1; - for (const struct time_array *tmp = t; tmp->next; tmp = tmp->next) { - count += 1; - } - - return count; -} diff --git a/logger/logger_time.h b/logger/logger_time.h index 09bf85ff96c53358ce6111be01ca3307463720fe..272746b6ed4406fe70e45ac16f137c4c37048fc7 100644 --- a/logger/logger_time.h +++ b/logger/logger_time.h @@ -27,6 +27,8 @@ typedef long long integertime_t; struct logger_reader; +#define LOGGER_TIME_INIT_SIZE 1024 + /** * @brief This structure contains all the time record. * @@ -39,28 +41,27 @@ struct logger_reader; * * The time step of an offset can be obtained with * #time_array_get_integertime, #time_array_get_time and - * #time_array_get_time_array. - * - * The size of the time array can be accessed with - * #time_array_count. + * #time_array_get_index. */ struct time_array { - /* Pointer to next element. */ - void *next; + /* Integertime of the records. */ + integertime_t *int_time; - /* Pointer to prev element. */ - void *prev; + /* Double time of the records. */ + double *time; - /* Integertime of this time record. */ - integertime_t int_time; + /* Offset in the file of the time records. */ + size_t *offset; - /* Double time of this time record. */ - double time; + /* Number of element in the arrays. */ + size_t size; - /* Offset in the file of this time record. */ - size_t offset; + /* Maximum number of element available */ + size_t capacity; }; +void time_array_append(struct time_array *t, const integertime_t int_time, + const double time, const size_t offset); size_t time_read(integertime_t *int_time, double *time, const struct logger_reader *reader, size_t offset); @@ -72,8 +73,7 @@ integertime_t time_array_get_integertime(struct time_array *t, double time_array_get_time(const struct time_array *t, const size_t offset); -struct time_array *time_array_get_time_array(const struct time_array *t, - const size_t offset); +size_t time_array_get_index(const struct time_array *t, const size_t offset); void time_array_free(struct time_array *t); @@ -81,8 +81,6 @@ void time_array_print(const struct time_array *t); void time_array_print_offset(const struct time_array *t); -size_t time_array_count(const struct time_array *t); - size_t time_offset_first_record(const struct header *h); #endif // __LOGGER_LOGGER_TIMELINE_H__ diff --git a/logger/tests/Makefile.am b/logger/tests/Makefile.am index 4d2f181bfde15a285e833393e1c55c6936755de4..dd94462b8b98b0a089d0f959b81c603c29911a76 100644 --- a/logger/tests/Makefile.am +++ b/logger/tests/Makefile.am @@ -20,17 +20,18 @@ AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/logger $(HDF5_CPPFLAGS) $(GSL_IN AM_LDFLAGS = ../../src/.libs/libswiftsim.a ../.libs/liblogger.a $(HDF5_LDFLAGS) $(HDF5_LIBS) $(FFTW_LIBS) $(TCMALLOC_LIBS) $(JEMALLOC_LIBS) $(TBBMALLOC_LIBS) $(GRACKLE_LIBS) $(GSL_LIBS) $(PROFILER_LIBS) # List of programs and scripts to run in the test suite -TESTS = testLogfileHeader testLogfileReader +TESTS = testLogfileHeader testLogfileReader testTimeArray # List of test programs to compile -check_PROGRAMS = testLogfileHeader testLogfileReader +check_PROGRAMS = testLogfileHeader testLogfileReader testTimeArray # Rebuild tests when SWIFT is updated. -$(check_PROGRAMS): ../../src/.libs/libswiftsim.a +$(check_PROGRAMS): ../../src/.libs/libswiftsim.a ../.libs/liblogger.a # Sources for the individual programs testLogfileHeader_SOURCES = testLogfileHeader.c testLogfileReader_SOURCES = testLogfileReader.c +testTimeArray_SOURCES = testTimeArray.c # Files necessary for distribution EXTRA_DIST = testLogfileHeader.yml testLogfileReader.yml diff --git a/logger/tests/testTimeArray.c b/logger/tests/testTimeArray.c new file mode 100644 index 0000000000000000000000000000000000000000..602cdccad7b370c39f190bb3ae4fc345ccdebb25 --- /dev/null +++ b/logger/tests/testTimeArray.c @@ -0,0 +1,76 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2019 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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/>. + * + ******************************************************************************/ + +#include "logger_time.h" +#include <time.h> +#include <stdlib.h> + +#define NUMBER_OF_ELEMENT 10000 +#define TIME_BASE 0.04 +#define OFFSET_BASE 1000 + +int main(int argc, char *argv[]) { + + if (NUMBER_OF_ELEMENT < LOGGER_TIME_INIT_SIZE) { + error("Not testing the reallocation."); + } + + srand(100); + /* Initialize the time array */ + struct time_array times; + time_array_init(×); + + /* Add elements */ + for(size_t i = 0; i < NUMBER_OF_ELEMENT; i++) { + integertime_t int_time = i; + double time = i * TIME_BASE; + size_t offset = i * OFFSET_BASE; + + time_array_append(×, int_time, time, offset); + } + + /* Check the elements */ + for(size_t i = 0; i < NUMBER_OF_ELEMENT; i++) { + integertime_t int_time = i; + double time = i * TIME_BASE; + size_t offset = i * OFFSET_BASE; + + /* Ensure that we can get the correct offset when looking + in between the records. */ + int r = rand() % OFFSET_BASE; + size_t read_offset = offset + r; + + /* The offset cannot be larger than the largest one */ + if (i == NUMBER_OF_ELEMENT - 1) { + read_offset = offset; + } + + /* Get the index from the offset */ + size_t ind = time_array_get_index(×, read_offset); + + /* Check the values obtained */ + assert(i == ind); + assert(int_time == times.int_time[ind]); + assert(time == times.time[ind]); + assert(offset == times.offset[ind]); + } + + + return 0; +}