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

Reply via email to