Hi hackers! Here is the new patch version. With the help of Mikhail Bakhterev I've optimized subroutines of the penalty function. Index build time now is roughly equivalent to build time before patch (test attached to thread start). Time of SELECT statement execution is reduced by 40%. Changes in the patch: 1. Wrong usage of realms is fixed 2. Cube size and margin (edge) functions are optimized to reduce memory write instructions count (result of these functions were written on evey cycle of a loop) 3. All private functions are marked as static inline 4. Comments are formatted per project style
I'm going to put this to commitfest queue, because performance of gist queries is improved significantly and I do not see any serious drawbacks. Any ideas about this patch are welcome. Especialy I'm conserned about portability of pack_float function. Does every supported Postgres platform conforms to IEEE 754 floating point specification? Also I'm not sure about possibility to hit any problems with float NaNs during float package? Best regards, Andrey Borodin, Octonica & Ural Federal University.
diff --git a/contrib/cube/cube.c b/contrib/cube/cube.c index 3feddef..dec314f 100644 --- a/contrib/cube/cube.c +++ b/contrib/cube/cube.c @@ -91,20 +91,22 @@ PG_FUNCTION_INFO_V1(cube_enlarge); /* ** For internal use only */ -int32 cube_cmp_v0(NDBOX *a, NDBOX *b); -bool cube_contains_v0(NDBOX *a, NDBOX *b); -bool cube_overlap_v0(NDBOX *a, NDBOX *b); -NDBOX *cube_union_v0(NDBOX *a, NDBOX *b); -void rt_cube_size(NDBOX *a, double *sz); -NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep); -bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); -bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); +static inline int32 cube_cmp_v0(NDBOX *a, NDBOX *b); +static inline bool cube_contains_v0(NDBOX *a, NDBOX *b); +static inline bool cube_overlap_v0(NDBOX *a, NDBOX *b); +static inline NDBOX *cube_union_v0(NDBOX *a, NDBOX *b); +static inline float pack_float(float actualValue, int realm); +static inline void rt_cube_size(NDBOX *a, double *sz); +static inline void rt_cube_edge(NDBOX *a, double *sz); +static inline NDBOX *g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep); +static inline bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); +static inline bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy); /* ** Auxiliary funxtions */ -static double distance_1D(double a1, double a2, double b1, double b2); -static bool cube_is_point_internal(NDBOX *cube); +static inline double distance_1D(double a1, double a2, double b1, double b2); +static inline bool cube_is_point_internal(NDBOX *cube); /***************************************************************************** @@ -420,6 +422,15 @@ g_cube_decompress(PG_FUNCTION_ARGS) PG_RETURN_POINTER(entry); } +static inline float +pack_float(float actualValue, int realm) +{ + /* two bits for realm, other for value */ + /* we have 4 realms */ + int realmAjustment = *((int*)&actualValue)/4; + int realCode = realm * (INT32_MAX/4) + realmAjustment; + return *((float*)&realCode); +} /* ** The GiST Penalty method for boxes @@ -428,6 +439,11 @@ g_cube_decompress(PG_FUNCTION_ARGS) Datum g_cube_penalty(PG_FUNCTION_ARGS) { + /* REALM 0: No extension is required, volume is zero, return edge */ + /* REALM 1: No extension is required, return nonzero volume */ + /* REALM 2: Volume extension is zero, return nonzero edge extension */ + /* REALM 3: Volume extension is nonzero, return it */ + GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); float *result = (float *) PG_GETARG_POINTER(2); @@ -441,9 +457,33 @@ g_cube_penalty(PG_FUNCTION_ARGS) rt_cube_size(DatumGetNDBOX(origentry->key), &tmp2); *result = (float) (tmp1 - tmp2); - /* - * fprintf(stderr, "penalty\n"); fprintf(stderr, "\t%g\n", *result); - */ + if( *result == 0 ) + { + double tmp3 = tmp1; /* remember entry volume */ + rt_cube_edge(ud, &tmp1); + rt_cube_edge(DatumGetNDBOX(origentry->key), &tmp2); + *result = (float) (tmp1 - tmp2); + if( *result == 0 ) + { + if( tmp3 != 0 ) + { + *result = pack_float(tmp3, 1); /* REALM 1 */ + } + else + { + *result = pack_float(tmp1, 0); /* REALM 0 */ + } + } + else + { + *result = pack_float(*result, 2); /* REALM 2 */ + } + } + else + { + *result = pack_float(*result, 3); /* REALM 3 */ + } + PG_RETURN_FLOAT8(*result); } @@ -626,7 +666,7 @@ g_cube_same(PG_FUNCTION_ARGS) /* ** SUPPORT ROUTINES */ -bool +static inline bool g_cube_leaf_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy) @@ -658,7 +698,7 @@ g_cube_leaf_consistent(NDBOX *key, return (retval); } -bool +static inline bool g_cube_internal_consistent(NDBOX *key, NDBOX *query, StrategyNumber strategy) @@ -688,7 +728,7 @@ g_cube_internal_consistent(NDBOX *key, return (retval); } -NDBOX * +static inline NDBOX * g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep) { NDBOX *retval; @@ -701,7 +741,7 @@ g_cube_binary_union(NDBOX *r1, NDBOX *r2, int *sizep) /* cube_union_v0 */ -NDBOX * +static inline NDBOX * cube_union_v0(NDBOX *a, NDBOX *b) { int i; @@ -875,25 +915,40 @@ cube_size(PG_FUNCTION_ARGS) PG_RETURN_FLOAT8(result); } -void +static inline void rt_cube_size(NDBOX *a, double *size) { int i; + double result = 0; - if (a == (NDBOX *) NULL) - *size = 0.0; - else + if (a != (NDBOX *) NULL) + { + result = 1.0; + for (i = 0; i < DIM(a); i++) + result *= UR_COORD(a, i) - LL_COORD(a, i); + } + *size = Abs(result); + return; +} + +static inline void +rt_cube_edge(NDBOX *a, double *size) +{ + int i; + double result = 0; + + if (a != (NDBOX *) NULL) { - *size = 1.0; for (i = 0; i < DIM(a); i++) - *size = (*size) * Abs(UR_COORD(a, i) - LL_COORD(a, i)); + result += Abs(UR_COORD(a, i) - LL_COORD(a, i)); } + *size = result; return; } /* make up a metric in which one box will be 'lower' than the other -- this can be useful for sorting and to determine uniqueness */ -int32 +static inline int32 cube_cmp_v0(NDBOX *a, NDBOX *b) { int i; @@ -1080,7 +1135,7 @@ cube_ge(PG_FUNCTION_ARGS) /* Contains */ /* Box(A) CONTAINS Box(B) IFF pt(A) < pt(B) */ -bool +static inline bool cube_contains_v0(NDBOX *a, NDBOX *b) { int i; @@ -1150,7 +1205,7 @@ cube_contained(PG_FUNCTION_ARGS) /* Overlap */ /* Box(A) Overlap Box(B) IFF (pt(a)LL < pt(B)UR) && (pt(b)LL < pt(a)UR) */ -bool +static inline bool cube_overlap_v0(NDBOX *a, NDBOX *b) { int i;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers