Changeset: fdebce90a3f3 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=fdebce90a3f3
Modified Files:
monetdb5/extras/pyapi/Benchmarks/pyapi_test.sh
monetdb5/extras/pyapi/benchmark.c
monetdb5/extras/pyapi/pyapi.c
monetdb5/extras/pyapi/pyapi.h
monetdb5/extras/pyapi/pytypes.h
monetdb5/extras/pyapi/type_conversion.c
monetdb5/extras/pyapi/unicode.c
Branch: pyapi
Log Message:
Added more documentation, and moved some code around for increased clarity.
diffs (truncated from 1520 to 300 lines):
diff --git a/monetdb5/extras/pyapi/Benchmarks/pyapi_test.sh
b/monetdb5/extras/pyapi/Benchmarks/pyapi_test.sh
--- a/monetdb5/extras/pyapi/Benchmarks/pyapi_test.sh
+++ b/monetdb5/extras/pyapi/Benchmarks/pyapi_test.sh
@@ -4,7 +4,7 @@
export PYAPI_BASE_DIR=$HOME
# The terminal to start mserver with, examples are 'gnome-terminal', 'xterm',
'konsole'
export TERMINAL=x-terminal-emulator
-# A command that tests if the mserver is still running (used to find out when
the shutting down is completed)
+# A command that tests if the mserver is still running (used to find out when
the shutting down of mserver is completed)
export MSERVERTEST='netstat -ant | grep "127.0.0.1:50000.*LISTEN">/dev/null'
# Testing parameters
@@ -53,6 +53,20 @@ export PYAPI_TESTFILE=$PYAPI_MONETDB_DIR
# Graph file location
export
PYAPI_GRAPHFILE=$PYAPI_MONETDB_DIR/monetdb5/extras/pyapi/Benchmarks/graph.py
+# Try a bunch of popular different terminals
+type $TERMINAL >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ export TERMINAL=gnome-terminal
+fi
+type $TERMINAL >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ export TERMINAL=xterm
+fi
+type $TERMINAL >/dev/null 2>&1
+if [ $? -ne 0 ]; then
+ export TERMINAL=konsole
+fi
+
function pyapi_build {
echo "Making directory $PYAPI_TEST_DIR."
mkdir $PYAPI_TEST_DIR && cd $PYAPI_TEST_DIR
diff --git a/monetdb5/extras/pyapi/benchmark.c
b/monetdb5/extras/pyapi/benchmark.c
--- a/monetdb5/extras/pyapi/benchmark.c
+++ b/monetdb5/extras/pyapi/benchmark.c
@@ -1,3 +1,10 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright 2008-2015 MonetDB B.V.
+ */
#include "benchmark.h"
@@ -13,7 +20,10 @@ static unsigned long long memtrace_memor
#ifdef __MALLOC_DEPRECATED //if this isn't defined MALLOC_HOOKS aren't
supported, probably
// We are using malloc/free hooks which are deprecated, so we have to ignore
the warnings
// (This is obviously bad practice, but the alternative is having to recompile
Python and then tracing both PyMemAlloc/Realloc and GDKmalloc/realloc calls,
this is much easier, and we aren't using them in a thread context and no thread
safety is why they are deprecated in the first place)
+
+#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
/* Prototypes for our hooks. */
static void *my_malloc_hook (size_t, const void *);
static void my_free_hook (void*, const void *);
diff --git a/monetdb5/extras/pyapi/pyapi.c b/monetdb5/extras/pyapi/pyapi.c
--- a/monetdb5/extras/pyapi/pyapi.c
+++ b/monetdb5/extras/pyapi/pyapi.c
@@ -15,14 +15,16 @@
#include "sql_catalog.h"
#include "pyapi.h"
+// Python library
#undef _GNU_SOURCE
#undef _XOPEN_SOURCE
#undef _POSIX_C_SOURCE
#include <Python.h>
+// Numpy Library
#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
#ifdef __INTEL_COMPILER
-//intel compiler complains about trailing comma's in numpy source code, so
hopefully this works
+// Intel compiler complains about trailing comma's in numpy source code, so
hopefully this works
#pragma warning(disable:271)
#endif
#include <numpy/arrayobject.h>
@@ -35,133 +37,56 @@
#include "formatinput.h"
#include "benchmark.h"
-//#define _PYAPI_VERBOSE_
-//#define _PYAPI_WARNINGS_
-#define _PYAPI_DEBUG_
-
-#include <stdint.h>
-
-#include <stdio.h>
-#include <string.h>
-
-#ifdef WIN32
-
-#else
+#ifndef WIN32
+// These libraries are used for PYTHON_MAP operations on Linux [to start new
processes and wait on them]
#include <sys/types.h>
#include <sys/wait.h>
#endif
const char* pyapi_enableflag = "embedded_py";
+const char* verbose_enableflag = "enable_pyverbose";
+const char* warning_enableflag = "enable_pywarnings";
+const char* debug_enableflag = "enable_pydebug";
+#ifdef _PYAPI_TESTING_
const char* zerocopyinput_disableflag = "disable_pyzerocopyinput";
const char* zerocopyoutput_disableflag = "disable_pyzerocopyoutput";
-const char* verbose_enableflag = "enable_pyverbose";
-const char* debug_enableflag = "enable_pydebug";
const char* numpy_string_array_enableflag = "enable_numpystringarray";
const char* alwaysunicode_enableflag = "enable_alwaysunicode";
const char* bytearray_disableflag = "disable_bytearray";
const char* benchmark_output_flag = "pyapi_benchmark_output";
-
-
-
+static bool option_zerocopyinput;
+static bool option_zerocopyoutput;
+static bool option_numpy_string_array;
+static bool option_bytearray;
+static bool option_alwaysunicode;
+static char *benchmark_output;
+#endif
#ifdef _PYAPI_VERBOSE_
-#define VERBOSE_MESSAGE(...) { \
- if (shm_id > 0) printf("%d: ", shm_id); \
- printf(__VA_ARGS__); \
- fflush(stdout); \
-}
-#else
-#define VERBOSE_MESSAGE(...) ((void) 0)
+static bool option_verbose;
#endif
-
+#ifdef _PYAPI_DEBUG_
+static bool option_debug;
+#endif
#ifdef _PYAPI_WARNINGS_
-#define WARNING_MESSAGE(...) { \
- fprintf(stderr, __VA_ARGS__); \
- fflush(stdout); \
-}
-#else
-#define WARNING_MESSAGE(...) ((void) 0)
+static bool option_warning;
#endif
-
-#define GDK_Alloc(var, size) { \
- var = GDKzalloc(size); \
- if (var == NULL) { \
- msg = createException(MAL, "pyapi.eval", MAL_MALLOC_FAIL); \
- goto wrapup; \
- } \
-}
-
-#define GDK_Free(var) { \
- if (var != NULL) \
- GDKfree(var); \
-}
-
-const char * pyarg_tabwidth[] = {"TABWIDTH", "MULTIPROCESSING"};
-
-struct _ParseArguments
-{
- int tab_width;
- bool multiprocessing;
-};
-#define ParseArguments struct _ParseArguments
-
-struct _ReturnBatDescr
-{
- int npy_type; //npy type
- size_t element_size; //element size in bytes
- size_t bat_count; //number of elements in bat
- size_t bat_size; //bat size in bytes
- size_t bat_start; //start position of bat
- bool has_mask; //if the return value has a mask or
not
-};
-#define ReturnBatDescr struct _ReturnBatDescr
-
-struct _PyInput{
- void *dataptr;
- BAT *bat;
- int bat_type;
- size_t count;
- bool scalar;
-};
-#define PyInput struct _PyInput
-
-struct _PyReturn{
- PyArrayObject *numpy_array;
- PyArrayObject *numpy_mask;
- void *array_data;
- bool *mask_data;
- size_t count;
- size_t memory_size;
- int result_type;
- bool multidimensional;
-};
-#define PyReturn struct _PyReturn
-
int PyAPIEnabled(void) {
return (GDKgetenv_istrue(pyapi_enableflag)
|| GDKgetenv_isyes(pyapi_enableflag));
}
static MT_Lock pyapiLock;
-static MT_Lock pyapiSluice;
static int pyapiInitialized = FALSE;
-
-#define bte_TO_PYSCALAR(mtpe, value) PyInt_FromLong((lng)value)
-#define bit_TO_PYSCALAR(mtpe, value) PyInt_FromLong((lng)value)
-#define sht_TO_PYSCALAR(mtpe, value) PyInt_FromLong((lng)value)
-#define int_TO_PYSCALAR(mtpe, value) PyInt_FromLong((lng)value)
-#define lng_TO_PYSCALAR(mtpe, value) PyLong_FromLong(value)
-#define flt_TO_PYSCALAR(mtpe, value) PyFloat_FromDouble(value)
-#define dbl_TO_PYSCALAR(mtpe, value) PyFloat_FromDouble(value)
-
-#define SCALAR_TO_PYSCALAR(mtpe, value) mtpe##_TO_PYSCALAR(mtpe, value)
-
-
+#ifdef _PYAPI_TESTING_
+// This #define converts a BAT 'bat' of BAT type 'TYPE_mtpe' to a Numpy array
of type 'nptpe'
+// This only works with numeric types (bit, byte, int, long, float, double),
strings are handled separately
+// if _PYAPI_TESTING_ is enabled, and option_zerocopyinput is set to FALSE,
the BAT is copied. Otherwise the internal BAT pointer is passed to the numpy
array (zero copy)
#define BAT_TO_NP(bat, mtpe, nptpe)
\
if (!option_zerocopyinput) {
\
vararray = PyArray_Zeros(1, (npy_intp[1]) {(t_end-t_start)},
PyArray_DescrFromType(nptpe), 0); \
- for(j = t_start; j < t_end; j++) {
\
+ for(j = t_start; j < t_end; j++) {
\
PyArray_SETITEM((PyArrayObject*)vararray,
PyArray_GETPTR1((PyArrayObject*)vararray, j - t_start),
SCALAR_TO_PYSCALAR(mtpe, ((mtpe*) Tloc(bat, BUNfirst(bat)))[j]));
\
}
\
} else {
\
@@ -169,8 +94,16 @@ static int pyapiInitialized = FALSE;
nptpe, NULL, &((mtpe*) Tloc(bat, BUNfirst(bat)))[t_start], 0,
\
NPY_ARRAY_CARRAY || !NPY_ARRAY_WRITEABLE, NULL);
\
}
+#else
+#define BAT_TO_NP(bat, mtpe, nptpe)
\
+ vararray = PyArray_New(&PyArray_Type, 1, (npy_intp[1])
{(t_end-t_start)}, \
+ nptpe, NULL, &((mtpe*) Tloc(bat, BUNfirst(bat)))[t_start], 0,
\
+ NPY_ARRAY_CARRAY || !NPY_ARRAY_WRITEABLE, NULL);
+#endif
-#define BAT_MMAP(bat, mtpe, batstore) {
\
+// This #define creates a new BAT with the internal data and mask from a Numpy
array, without copying the data
+// 'bat' is a BAT* pointer, which will contain the new BAT. TYPE_'mtpe' is the
BAT type, and 'batstore' is the heap storage type of the BAT (this should be
STORE_CMEM or STORE_SHARED)
+#define CREATE_BAT_ZEROCOPY(bat, mtpe, batstore) {
\
bat = BATnew(TYPE_void, TYPE_##mtpe, 0, TRANSIENT);
\
BATseqbase(bat, seqbase); bat->T->nil = 0; bat->T->nonil = 1;
\
bat->tkey = 0; bat->tsorted = 0; bat->trevsorted = 0;
\
@@ -204,9 +137,12 @@ static int pyapiInitialized = FALSE;
bat->S->copiedtodisk = false;
\
\
/*Take over the data from the numpy array*/
\
- if (ret->numpy_array != NULL) PyArray_CLEARFLAGS(ret->numpy_array,
NPY_ARRAY_OWNDATA); \
+ if (ret->numpy_array != NULL)
PyArray_CLEARFLAGS((PyArrayObject*)ret->numpy_array, NPY_ARRAY_OWNDATA);
\
}
+// This #define converts a Numpy Array to a BAT by copying the internal data
to the BAT. It assumes the BAT 'bat' is already created with the proper size.
+// This should only be used with integer data that can be cast. It assumes the
Numpy Array has an internal array of type 'mtpe_from', and the BAT has an
internal array of type 'mtpe_to'.
+// it then does the cast by simply doing BAT[i] = (mtpe_to)
((mtpe_from*)NUMPY_ARRAY[i]), which only works if both mtpe_to and mtpe_from
are integers
#define NP_COL_BAT_LOOP(bat, mtpe_to, mtpe_from) {
\
if (mask == NULL)
\
{
\
@@ -231,6 +167,9 @@ static int pyapiInitialized = FALSE;
}
\
} }
+// This #define converts a Numpy Array to a BAT by copying the internal data
to the BAT. It converts the data from the Numpy Array to the BAT using a
function
+// This function has to have the prototype 'bool function(void *data, size_t
memory_size, mtpe_to *resulting_value)', and either return False (if conversion
fails)
+// or write the value into the 'resulting_value' pointer. This is used
convertring strings/unicodes/python objects to numeric values.
#define NP_COL_BAT_LOOP_FUNC(bat, mtpe_to, func) {
\
mtpe_to value;
\
if (mask == NULL)
\
@@ -267,6 +206,7 @@ static int pyapiInitialized = FALSE;
} }
+// This #define is for converting a numeric numpy array into a string BAT.
'conv' is a function that turns a numeric value of type 'mtpe' to a char* array.
#define NP_COL_BAT_STR_LOOP(bat, mtpe, conv)
\
if (mask == NULL)
\
{
\
@@ -293,6 +233,15 @@ static int pyapiInitialized = FALSE;
}
\
}
+// This is here so we can remove the option_zerocopyoutput from the zero copy
conditionals if testing is disabled
+#ifdef _PYAPI_TESTING_
+#define ZEROCOPY_OUTPUT option_zerocopyoutput &&
+#else
+#define ZEROCOPY_OUTPUT
+#endif
+
+// This very big #define combines all the previous #defines for one big
#define that is responsible for converting a Numpy array (described in the
PyReturn object 'ret')
+// to a BAT of type 'mtpe'. This should only be used for numeric BATs (but can
be used for any Numpy Array). The resulting BAT will be stored in 'bat'.
#define NP_CREATE_BAT(bat, mtpe) {
\
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list