From b368b82a7369ae06caee97c0f6fac4e76bf37c64 Mon Sep 17 00:00:00 2001
From: David Hendriks <davidhendriks93@gmail.com>
Date: Wed, 5 May 2021 13:35:40 +0100
Subject: [PATCH] Added a testfunction that logs how much time is spent where

---
 include/binary_c_python.h |  11 ++
 src/binary_c_python.c     | 254 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 265 insertions(+)

diff --git a/include/binary_c_python.h b/include/binary_c_python.h
index be717c3b9..918b80fa4 100644
--- a/include/binary_c_python.h
+++ b/include/binary_c_python.h
@@ -18,6 +18,17 @@ int run_system(char * argstring,
                char ** const error_buffer,
                size_t * const nbytes);
 
+int run_systemtest(char * argstring,
+               long int custom_logging_func_memaddr,
+               struct libbinary_c_store_t * store,
+               struct persistent_data_t * persistent_data,
+               int write_logfile,
+               int population,
+               char ** const buffer,
+               char ** const error_buffer,
+               size_t * const nbytes,
+               double * binary_c_times);
+
 /* =================================================================== */
 /* Functions to call other API functionality like help and arglines    */
 /* =================================================================== */
diff --git a/src/binary_c_python.c b/src/binary_c_python.c
index c4df7d76b..2635b5a74 100644
--- a/src/binary_c_python.c
+++ b/src/binary_c_python.c
@@ -9,6 +9,11 @@
 #include <stdint.h>
 #include <string.h>
 
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+
 /*
  * binary_c/PYTHON API interface functions
  *
@@ -72,6 +77,8 @@ static char module_docstring[] MAYBE_UNUSED =
 // Evolution function docstrings
 static char run_system_docstring[] = 
     "Function to run a system. This is a general function that will be able to handle different kinds of situations: single system run with different settings, population run with different settings, etc. To avoid having too many functions doing slightly different things. \n\nArguments:\n\targstring: argument string for binary_c\n\t(opt) custom_logging_func_memaddr: memory address value for custom logging function. Default = -1 (None)\n\t(opt) store_memaddr: memory adress of the store. Default = -1 (None)\n\t(opt) write_logfile: Boolean (in int form) for whether to enable the writing of the log function. Default = 0\n\t(opt) population: Boolean (in int form) for whether this system is part of a population run. Default = 0.";
+static char test_run_system_docstring[] = 
+    "Function to run a system. This is a general function that will be able to handle different kinds of situations: single system run with different settings, population run with different settings, etc. To avoid having too many functions doing slightly different things. \n\nArguments:\n\targstring: argument string for binary_c\n\t(opt) custom_logging_func_memaddr: memory address value for custom logging function. Default = -1 (None)\n\t(opt) store_memaddr: memory adress of the store. Default = -1 (None)\n\t(opt) write_logfile: Boolean (in int form) for whether to enable the writing of the log function. Default = 0\n\t(opt) population: Boolean (in int form) for whether this system is part of a population run. Default = 0.";
 
 // Utility function docstrings
 static char return_arglines_docstring[] =
@@ -104,6 +111,7 @@ static char test_func_docstring[] =
 
 // Evolution function headers
 static PyObject* python_run_system(PyObject *self, PyObject *args, PyObject *kwargs);
+static PyObject* test_python_run_system(PyObject *self, PyObject *args, PyObject *kwargs);
 
 // Utility function headers
 static PyObject* python_return_arglines(PyObject *self, PyObject *args);
@@ -126,6 +134,7 @@ static PyObject* python_test_func(PyObject *self, PyObject *args);
 static PyMethodDef module_methods[] = {
     // Wierdly, this casting to a PyCFunction, which usually takes only 2 args, now works when giving keywords. See https://stackoverflow.com/q/10264080
     {"run_system", (PyCFunction)python_run_system, METH_VARARGS|METH_KEYWORDS, run_system_docstring}, 
+    {"test_run_system", (PyCFunction)test_python_run_system, METH_VARARGS|METH_KEYWORDS, test_run_system_docstring}, 
 
     //
     {"return_arglines", python_return_arglines, METH_VARARGS, return_arglines_docstring},
@@ -269,6 +278,7 @@ static PyObject* python_run_system(PyObject *self, PyObject *args, PyObject *kwa
     return return_string;
 }
 
+
 /* ============================================================================== */
 /* Wrappers to functions that call other API functionality like help and arglines */
 /* ============================================================================== */
@@ -1318,3 +1328,247 @@ int free_store_memaddr(struct libbinary_c_store_t * store,
 
     return 0;
 }
+
+
+
+
+
+
+
+//// Timing tests
+static PyObject* test_python_run_system(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    double time_start_before = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+    static char* keywords[] = {"argstring", "custom_logging_func_memaddr", "store_memaddr", "persistent_data_memaddr", "write_logfile", "population", NULL};
+
+    /* set vars and default values for some*/
+    char *argstring;
+    long int custom_logging_func_memaddr = -1;
+    PyObject *  store_capsule = NULL;
+    PyObject * persistent_data_capsule = NULL;
+    int write_logfile = 0;
+    int population = 0;
+
+    /* Parse the input tuple */
+    // By using the keywords argument it scans over the given set of kwargs, but if they are not given then the default value is used
+    if(!PyArg_ParseTupleAndKeywords(args, kwargs, "s|lOOii", keywords, &argstring, &custom_logging_func_memaddr, &store_capsule, &persistent_data_capsule, &write_logfile, &population))
+    {
+        return NULL;
+    }
+
+    // TODO: Build in checks for all the capsules
+
+    /* Unpack the capsules */
+    // Persistent data
+    struct libbinary_c_persistent_data_t * persistent_data = NULL;
+    if (persistent_data_capsule != NULL)
+    {
+        if (PyCapsule_IsValid(persistent_data_capsule, "PERSISTENT_DATA"))
+        {
+            if (!(persistent_data = (struct libbinary_c_persistent_data_t *) PyCapsule_GetPointer(persistent_data_capsule, "PERSISTENT_DATA")))
+                return NULL;   
+            debug_printf("Unpacked persistent_data pointer %p from capsule\n", persistent_data);                
+        }
+    }
+
+    // Store
+    struct libbinary_c_store_t * store = NULL;
+    if (store_capsule != NULL)
+    {
+        if (PyCapsule_IsValid(store_capsule, "STORE"))
+        {
+            if (!(store = (struct libbinary_c_store_t *) PyCapsule_GetPointer(store_capsule, "STORE")))
+                return NULL;   
+            debug_printf("Unpacked store pointer %p from capsule\n", store_capsule);            
+        }
+    }
+
+    /* Call c-function */
+    char * buffer;
+    char * error_buffer;
+    size_t nbytes;
+
+    gettimeofday(&tv, NULL);
+    double time_stop_before = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+
+    double * binary_c_times = malloc(3 * sizeof(double));
+
+    int out MAYBE_UNUSED = run_systemtest(argstring,                    // the argstring
+                                      custom_logging_func_memaddr,  // memory adress for the function for custom logging
+                                      store,                // TODO: change. memory adress for the store object
+                                      persistent_data,      // TODO: change. memory adress for the persistent data
+                                      write_logfile,                // boolean for whether to write the logfile
+                                      population,                   // boolean for whether this is part of a population.
+                                      &buffer,
+                                      &error_buffer,
+                                      &nbytes,
+                                      binary_c_times);
+
+    gettimeofday(&tv, NULL);
+    double time_start_after = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+    /* copy the buffer to a python string */
+    PyObject * return_string = Py_BuildValue("s", buffer);
+    PyObject * return_error_string MAYBE_UNUSED = Py_BuildValue("s", error_buffer);
+
+    /* Display error */
+    if(error_buffer != NULL && strlen(error_buffer)>0)
+    {
+        fprintf(stderr,
+                "Error (in function: binary_c_run_system): %s\n",
+                error_buffer);
+    }
+
+    Safe_free(buffer);
+    Safe_free(error_buffer);
+
+    // sleep(1);
+    gettimeofday(&tv, NULL);
+    double time_stop_after = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+
+
+    double binary_c_time_taken_before = binary_c_times[0];
+    double binary_c_time_taken_after = binary_c_times[1];
+    double binary_c_time_taken_during = binary_c_times[2];
+
+    free(binary_c_times);
+
+
+
+    // printf("time_start_before: %f\n", time_start_before);
+    // printf("time_stop_before: %f\n", time_stop_before);
+    // printf("time_start_after: %f\n", time_start_after);
+    // printf("time_stop_after: %f\n", time_stop_after);
+    double time_taken_before = ((double)(time_stop_before - time_start_before)/1000); // in seconds
+    double time_taken_after = ((double)(time_stop_after - time_start_after)/1000); // in seconds
+    double time_taken_during = ((double)(time_start_after - time_stop_before)/1000); // in seconds
+    // printf("Execution time: before: %fs after: %fs during: %fs\n", time_taken_before, time_taken_after, time_taken_during);
+
+
+    PyObject * python_val = Py_BuildValue("[dddddd]", time_taken_before, time_taken_after, time_taken_during, binary_c_time_taken_before, binary_c_time_taken_after, binary_c_time_taken_during);
+    return python_val;
+    // return return_string;
+}
+
+int run_systemtest(char * argstring,
+               long int custom_logging_func_memaddr,
+               struct libbinary_c_store_t * store,
+               struct persistent_data_t * persistent_data,
+               int write_logfile,
+               int population,
+               char ** const buffer,
+               char ** const error_buffer,
+               size_t * const nbytes,
+               double * binary_c_times)
+{
+    struct timeval tv;
+
+    gettimeofday(&tv, NULL);
+    double time_start_before = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+    /* memory for system */
+    struct libbinary_c_stardata_t *stardata = NULL;
+    // store can be NULL, but could be a valid pointer to a store
+    // persistent_data can be NULL, but could be a valid pointer to a persistent_data
+
+    /* Determine whether to free the store memory adress*/
+    Boolean free_store = FALSE;
+    if (store==NULL)
+    {
+        debug_printf("Decided to free the store memaddr\n");
+        free_store = TRUE;
+    }
+
+    /* Determine whether to free the persistent data memory adress*/
+    Boolean free_persistent_data = FALSE;
+    if (persistent_data == NULL)
+    {
+        debug_printf("Decided to free the persistent_data memaddr\n");
+        free_persistent_data = TRUE;
+    }
+
+    /* Set up new system */
+    binary_c_new_system(&stardata,          // stardata
+                        NULL,               // previous_stardatas
+                        NULL,               // preferences
+                        &store,             // store
+                        &persistent_data,   // persistent_data
+                        &argstring,         // argv
+                        -1                  // argc
+    );
+
+    // Add flag to enable
+    /* disable logging */
+    if(write_logfile != 1)
+    {
+        snprintf(stardata->preferences->log_filename,
+                 STRING_LENGTH-1,
+                 "%s",
+                 "/dev/null");
+        snprintf(stardata->preferences->api_log_filename_prefix,
+                 STRING_LENGTH-1,
+                 "%s",
+                 "/dev/null");
+    }
+
+    /* output to strings */
+    stardata->preferences->internal_buffering = INTERNAL_BUFFERING_STORE;
+    stardata->preferences->batchmode = BATCHMODE_LIBRARY;
+
+    /* Check the value of the custom_logging_memaddr */
+    if(custom_logging_func_memaddr != -1)
+    {
+        stardata->preferences->custom_output_function = (void*)(struct stardata_t *)custom_logging_func_memaddr;
+    }
+
+    debug_printf("ensemble_defer: %d\n", stardata->preferences->ensemble_defer);
+
+    gettimeofday(&tv, NULL);
+    double time_stop_before = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+    /* do binary evolution */
+    binary_c_evolve_for_dt(stardata,
+                           stardata->model.max_evolution_time);
+
+    gettimeofday(&tv, NULL);
+    double time_start_after = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+
+    /* get buffer pointer */
+    binary_c_buffer_info(stardata, buffer, nbytes);
+    
+    /* get error buffer pointer */
+    binary_c_error_buffer(stardata, error_buffer);
+
+    /* free stardata (except the buffer) */
+    binary_c_free_memory(&stardata, // Stardata
+        TRUE,                       // free_preferences
+        TRUE,                       // free_stardata
+        free_store,                 // free_store
+        FALSE,                      // free_raw_buffer
+        free_persistent_data        // free_persistent
+    );
+
+
+    gettimeofday(&tv, NULL);
+    long double time_stop_after = (tv.tv_sec) * 1000 + (tv.tv_usec) / 1000;
+    // printf("\t binaryc: time_start_before: %f\n", time_start_before);
+    // printf("\t binaryc: time_stop_before: %f\n", time_stop_before);
+    // printf("\t binaryc: time_start_after: %f\n", time_start_after);
+    // printf("\t binaryc: time_stop_after: %f\n", time_stop_after);
+    long double time_taken_before = ((long double)(time_stop_before - time_start_before)/1000); // in seconds
+    long double time_taken_after = ((long double)(time_stop_after - time_start_after)/1000); // in seconds
+    long double time_taken_during = ((long double)(time_start_after - time_stop_before)/1000); // in seconds
+    // printf("\t binaryc: Execution time: before: %Lfs after: %Lfs during: %Lfs\n", time_taken_before, time_taken_after, time_taken_during);
+
+    binary_c_times[0] = time_taken_before;
+    binary_c_times[1] = time_taken_after;
+    binary_c_times[2] = time_taken_during;
+
+    return 0;
+}
-- 
GitLab