diff --git a/include/binary_c_python.h b/include/binary_c_python.h index be717c3b993eb85baac6bf7b7c28a6eecb819432..918b80fa40ba67dfbe374cefc9e19cbd438a04b4 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 c4df7d76b989aad2235b557844cd11c33dff3755..2635b5a74e1efb97562023fde339df3ae8510ea0 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; +}