From 7f99ca8c59c1910d860f9ffbf6c01af5ca7783d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Max=20L=C3=BCbke?= Date: Mon, 1 Feb 2021 11:09:20 +0100 Subject: [PATCH] commenting DHT_Wrapper and change compiler macro --- src/DHT/DHT.c | 2 +- src/DHT/DHT.h | 4 +- src/DHT/DHT_Wrapper.cpp | 70 ++++++++++--- src/DHT/DHT_Wrapper.h | 222 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 281 insertions(+), 17 deletions(-) diff --git a/src/DHT/DHT.c b/src/DHT/DHT.c index a4f07f4b8..165953540 100644 --- a/src/DHT/DHT.c +++ b/src/DHT/DHT.c @@ -141,7 +141,7 @@ int DHT_write(DHT *table, void *send_key, void *send_data) { #ifdef DHT_STATISTICS table->stats->evictions += 1; #endif - result = DHT_WRITE_SUCCESS_WITH_COLLISION; + result = DHT_WRITE_SUCCESS_WITH_EVICTION; break; } } else diff --git a/src/DHT/DHT.h b/src/DHT/DHT.h index 88a4ab632..4eff08179 100644 --- a/src/DHT/DHT.h +++ b/src/DHT/DHT.h @@ -22,7 +22,7 @@ /** Returned by a call of DHT_read if no bucket with given key was found. */ #define DHT_READ_MISS -2 /** Returned by DHT_write if a bucket was evicted. */ -#define DHT_WRITE_SUCCESS_WITH_COLLISION -3 +#define DHT_WRITE_SUCCESS_WITH_EVICTION -3 /** Returned when no errors occured. */ #define DHT_SUCCESS 0 @@ -236,7 +236,7 @@ extern int DHT_free(DHT* table, int* eviction_counter, int* readerror_counter); * -# calls of DHT_write (w_access) * -# calls of DHT_read (r_access) * -# read misses (see DHT_READ_MISS) - * -# collisions (see DHT_WRITE_SUCCESS_WITH_COLLISION) + * -# collisions (see DHT_WRITE_SUCCESS_WITH_EVICTION) * 3-6 will reset with every call of this function finally the amount of new * written entries is printed out (since the last call of this funtion). * diff --git a/src/DHT/DHT_Wrapper.cpp b/src/DHT/DHT_Wrapper.cpp index 376e6ac8b..a57c2ba8f 100644 --- a/src/DHT/DHT_Wrapper.cpp +++ b/src/DHT/DHT_Wrapper.cpp @@ -13,10 +13,12 @@ uint64_t get_md5(int key_size, void *key) { unsigned char sum[MD5_DIGEST_LENGTH]; uint64_t retval, *v1, *v2; + // calculate md5 using MD5 functions MD5_Init(&ctx); MD5_Update(&ctx, key, key_size); MD5_Final(sum, &ctx); + // divide hash in 2 64 bit parts and XOR them v1 = (uint64_t *)&sum[0]; v2 = (uint64_t *)&sum[8]; retval = *v1 ^ *v2; @@ -26,10 +28,14 @@ uint64_t get_md5(int key_size, void *key) { DHT_Wrapper::DHT_Wrapper(t_simparams *params, MPI_Comm dht_comm, int buckets_per_process, int data_size, int key_size) { + // initialize DHT object dht_object = DHT_create(dht_comm, buckets_per_process, data_size, key_size, &get_md5); + + // allocate memory for fuzzing buffer fuzzing_buffer = (double *)malloc(key_size); + // extract needed values from sim_param struct this->dt_differ = params->dt_differ; this->dht_log = params->dht_log; this->dht_signif_vector = params->dht_signif_vector; @@ -37,7 +43,9 @@ DHT_Wrapper::DHT_Wrapper(t_simparams *params, MPI_Comm dht_comm, } DHT_Wrapper::~DHT_Wrapper() { + // free DHT DHT_free(dht_object, NULL, NULL); + // free fuzzing buffer free(fuzzing_buffer); } @@ -45,8 +53,11 @@ void DHT_Wrapper::checkDHT(int length, std::vector &out_result_index, double *work_package, double dt) { void *key; int res; + // var count -> count of variables per grid cell int var_count = dht_prop_type_vector.size(); + // loop over every grid cell contained in work package for (int i = 0; i < length; i++) { + // point to current grid cell key = (void *)&(work_package[i * var_count]); // fuzz data (round, logarithm etc.) @@ -55,12 +66,16 @@ void DHT_Wrapper::checkDHT(int length, std::vector &out_result_index, // overwrite input with data from DHT, IF value is found in DHT res = DHT_read(dht_object, fuzzing_buffer, key); + // if DHT_SUCCESS value was found ... if (res == DHT_SUCCESS) { - // flag that this line is replaced by DHT-value, do not simulate!! + // ... and grid cell will be marked as 'not to be simulating' out_result_index[i] = false; dht_hits++; - } else if (res == DHT_READ_MISS) { - // this line is untouched, simulation is needed + + } + // ... otherwise ... + else if (res == DHT_READ_MISS) { + // grid cell needs to be simulated by PHREEQC out_result_index[i] = true; dht_miss++; } else { @@ -75,22 +90,26 @@ void DHT_Wrapper::fillDHT(int length, std::vector &result_index, void *key; void *data; int res; + // var count -> count of variables per grid cell int var_count = dht_prop_type_vector.size(); - + // loop over every grid cell contained in work package for (int i = 0; i < length; i++) { key = (void *)&(work_package[i * var_count]); data = (void *)&(results[i * var_count]); + // If true grid cell was simulated, needs to be inserted into dht if (result_index[i]) { - // If true -> was simulated, needs to be inserted into dht - // fuzz data (round, logarithm etc.) fuzzForDHT(var_count, key, dt); + // insert simulated data with fuzzed key into DHT res = DHT_write(dht_object, fuzzing_buffer, data); + // if data was successfully written ... if (res != DHT_SUCCESS) { - if (res == DHT_WRITE_SUCCESS_WITH_COLLISION) { + // ... also check if a previously written value was evicted + if (res == DHT_WRITE_SUCCESS_WITH_EVICTION) { + // and increment internal eviciton counter dht_evictions++; } else { // MPI ERROR ... WHAT TO DO NOW? @@ -139,32 +158,55 @@ uint64_t DHT_Wrapper::getEvictions() { return this->dht_evictions; } void DHT_Wrapper::fuzzForDHT(int var_count, void *key, double dt) { unsigned int i = 0; // introduce fuzzing to allow more hits in DHT + // loop over every variable of grid cell for (i = 0; i < (unsigned int)var_count; i++) { + // check if variable is defined as 'act' if (dht_prop_type_vector[i] == "act") { - // with log10 + // if log is enabled (default) if (dht_log) { - if (((double *)key)[i] < 0) + // if variable is smaller than 0, which would be a strange result, + // warn the user and set fuzzing_buffer to 0 at this index + if (((double *)key)[i] < 0) { cerr << "dht_wrapper.cpp::fuzz_for_dht(): Warning! Negative value in " "key!" << endl; + fuzzing_buffer[i] = 0; + } + // if variable is 0 set fuzzing buffer to 0 else if (((double *)key)[i] == 0) fuzzing_buffer[i] = 0; + // otherwise ... else + // round current variable value by applying log with base 10, negate + // (since the actual values will be between 0 and 1) and cut result + // after significant digit fuzzing_buffer[i] = ROUND(-(std::log10(((double *)key)[i])), dht_signif_vector[i]); - } else { - // without log10 + } + // if log is disabled + else { + // just round by cutting after signifanct digit fuzzing_buffer[i] = ROUND((((double *)key)[i]), dht_signif_vector[i]); } - } else if (dht_prop_type_vector[i] == "logact") { + } + // if variable is defined as 'logact' (log was already applied e.g. pH) + else if (dht_prop_type_vector[i] == "logact") { + // just round by cutting after signifanct digit fuzzing_buffer[i] = ROUND((((double *)key)[i]), dht_signif_vector[i]); - } else if (dht_prop_type_vector[i] == "ignore") { + } + // if defined ass 'ignore' ... + else if (dht_prop_type_vector[i] == "ignore") { + // ... just set fuzzing buffer to 0 fuzzing_buffer[i] = 0; - } else { + } + // and finally, if type is not defined, print error message + else { cerr << "dht_wrapper.cpp::fuzz_for_dht(): Warning! Probably wrong " "prop_type!" << endl; } } + // if timestep differs over iterations set current current time step at the + // end of fuzzing buffer if (dt_differ) fuzzing_buffer[var_count] = dt; } \ No newline at end of file diff --git a/src/DHT/DHT_Wrapper.h b/src/DHT/DHT_Wrapper.h index fa836cdf5..c1d0edd88 100644 --- a/src/DHT/DHT_Wrapper.h +++ b/src/DHT/DHT_Wrapper.h @@ -12,44 +12,266 @@ extern "C" { #include +/** + * @brief Cut double value after signif digit + * + * Macro to round a double value by cutting every digit after significant digit + * + */ #define ROUND(value, signif) \ (((int)(pow(10.0, (double)signif) * value)) * pow(10.0, (double)-signif)) namespace poet { +/** + * @brief Return user-defined md5sum + * + * This function will calculate a hashsum with the help of md5sum. Therefore the + * md5sum for a given key is calculated and divided into two 64-bit parts. These + * will be XORed and returned as the hash. + * + * @param key_size Size of key in bytes + * @param key Pointer to key + * @return uint64_t Hashsum as an unsigned 64-bit integer + */ +static uint64_t get_md5(int key_size, void *key); + +/** + * @brief C++-Wrapper around DHT implementation + * + * Provides an API to interact with the current DHT implentation. This class is + * POET specific and can't be used outside the POET application. + * + */ class DHT_Wrapper { public: + /** + * @brief Construct a new dht wrapper object + * + * The constructor will initialize the private dht_object of this class by + * calling DHT_create with all given parameters. Also the fuzzing buffer will + * be allocated and all needed parameters extracted from simparams struct. + * + * @param params Simulation parameter struct returned at initialization + * @param dht_comm Communicator which addresses all participating DHT + * processes + * @param buckets_per_process Count of buckets to allocate for each process + * @param data_size Size of data in bytes + * @param key_size Size of key in bytes + */ DHT_Wrapper(t_simparams *params, MPI_Comm dht_comm, int buckets_per_process, int data_size, int key_size); + /** + * @brief Destroy the dht wrapper object + * + * By destroying this object the DHT will also be freed. Since all statistics + * are stored inside this object, no statistics will be retrieved during the + * call of DHT_free. After freeing the DHT the fuzzing buffer will be also + * freed. + * + */ ~DHT_Wrapper(); + /** + * @brief Check if values of workpackage are stored in DHT + * + * Call DHT_read for all grid cells of the given workpackage and if a + * previously simulated grid cell was found mark this grid cell as 'not be + * simulated'. Therefore all values of a grid cell are fuzzed by fuzzForDHT + * and used as input key. The correspondending retrieved value might be stored + * directly into the memory area of the work_package and out_result_index is + * marked with false ('not to be simulated'). + * + * @param length Count of grid cells inside work package + * @param[out] out_result_index Indexing work packages which should be simulated + * @param[in,out] work_package Pointer to current work package + * @param dt Current timestep of simulation + */ void checkDHT(int length, std::vector &out_result_index, double *work_package, double dt); + + /** + * @brief Write simulated values into DHT + * + * Call DHT_write for all grid cells of the given workpackage which was + * simulated shortly before by the worker. Whether the grid cell was simulated + * is given by result_index. For every grid cell indicated with true inside + * result_index write the simulated value into the DHT. + * + * @param length Count of grid cells inside work package + * @param result_index Indexing work packages which was simulated + * @param work_package Pointer to current work package which was used as input + * of PHREEQC + * @param results Pointer to current work package which are the resulting + * outputs of the PHREEQC simulation + * @param dt Current timestep of simulation + */ void fillDHT(int length, std::vector &result_index, double *work_package, double *results, double dt); + /** + * @brief Dump current DHT state into file. + * + * This function will simply execute DHT_to_file with given file name (see + * DHT.h for more info). + * + * @param filename Name of the dump file + * @return int Returns 0 on success, otherwise an error value + */ int tableToFile(const char *filename); + + /** + * @brief Load dump file into DHT. + * + * This function will simply execute DHT_from_file with given file name (see + * DHT.h for more info). + * + * @param filename Name of the dump file + * @return int Returns 0 on success, otherwise an error value + */ int fileToTable(const char *filename); + /** + * @brief Print a detailed statistic of DHT usage. + * + * This function will simply execute DHT_print_statistics with given file name + * (see DHT.h for more info). + * + */ void printStatistics(); + /** + * @brief Get the Hits object + * + * @return uint64_t Count of hits + */ uint64_t getHits(); + + /** + * @brief Get the Misses object + * + * @return uint64_t Count of read misses + */ uint64_t getMisses(); + + /** + * @brief Get the Evictions object + * + * @return uint64_t Count of evictions + */ uint64_t getEvictions(); private: + /** + * @brief Transform given workpackage into DHT key + * + * A given workpackage will be transformed into a DHT key by rounding each + * value of a workpackage to a given significant digit. Three different types + * of variables 'act', 'logact' and 'ignore' are used. Those types are given + * via the dht_signif_vector. + * + * If a variable is defined as 'act', dht_log is true and non-negative, the + * logarithm with base 10 will be applied. After that the value is negated. In + * case the value is 0 the fuzzing_buffer is also set to 0 at this position. + * If the value is negative a correspondending warning will be printed to + * stderr and the fuzzing buffer will be set to 0 at this index. + * + * If a variable is defined as 'logact' the value will be cut after the + * significant digit. + * + * If a variable ist defined as 'ignore' the fuzzing_buffer will be set to 0 + * at the index of the variable. + * + * If dt_differ is true the current time step of the simulation will be set at + * the end of the fuzzing_buffer. + * + * @param var_count Count of variables for the current work package + * @param key Pointer to work package handled as the key + * @param dt Current time step of the simulation + */ void fuzzForDHT(int var_count, void *key, double dt); + /** + * @brief DHT handle + * + * Stores information about the DHT. Will be used as a handle for each DHT + * library call. + * + */ DHT *dht_object; + /** + * @brief Count of hits + * + * The counter will be incremented if a previously simulated workpackage can + * be retrieved with a given key. + * + */ uint64_t dht_hits = 0; + + /** + * @brief Count of read misses + * + * The counter will be incremented if a given key doesn't retrieve a value + * from the DHT. + * + */ uint64_t dht_miss = 0; + + /** + * @brief Count of evictions + * + * If a value in the DHT must be evicted because of lack of space/reaching the + * last index etc., this counter will be incremented. + * + */ uint64_t dht_evictions = 0; + /** + * @brief Rounded work package values + * + * Stores rounded work package values and serves as the DHT key pointer. + * + */ double *fuzzing_buffer; + /** + * @brief Indicates change in time step during simulation + * + * If set to true, the time step of simulation will differ between iterations, + * so the current time step must be stored inside the DHT key. Otherwise wrong + * values would be obtained. + * + * If set to false the time step doesn't need to be stored in the DHT key. + * + */ bool dt_differ; + + /** + * @brief Logarithm before rounding + * + * Indicates if the logarithm with base 10 will be applied to a variable + * before rounding. + * + * Defaults to true. + * + */ bool dht_log; + + /** + * @brief Significant digits for each variable + * + * Stores the rounding/significant digits for each variable of the work + * package. + * + */ std::vector dht_signif_vector; + + /** + * @brief Type of each variable + * + * Defines the type of each variable of the work package. + * + */ std::vector dht_prop_type_vector; }; } // namespace poet