← Back to team overview

maria-developers team mailing list archive

Re: Step#4: MDEV-7950 Item_func::type() takes 0.26% in OLTP RO

 

Hi Sergey,

I'm sending a new version,  which takes into account your review
suggestions and our skype discussion.

Thanks.

On 05/08/2015 12:27 PM, Sergey Vojtovich wrote:
Hi Alexander,

following profiler reports for build_equal_items* in your and mine patches.
For OLTP RO they're equal. I guess Item_func::build_equal_items() was not
inlined due to recursion?

Bar's patch
-----------
0.06% Item_func_eq::build_equal_items_and_cond()
0.05% build_equal_items()
0.01% Item_func::build_equal_items()
0.00% Item_func::build_equal_items_and_cond()

Svoj's patch
------------
0.06% build_equal_items()
0.05% Item_func_eq::build_equal_items_and_cond()
0.01% Item_func::build_equal_items()
0.00% Item::build_equal_items_and_cond()

Regards,
Sergey

On Thu, May 07, 2015 at 01:58:28PM +0400, Sergey Vojtovich wrote:
Hi Alexander,

comments inline.

On Wed, May 06, 2015 at 07:51:18PM +0400, Alexander Barkov wrote:
Hi Sergey,

Please review a patch for the next step for MDEV-7950

(one small thing at a time, to avoid huge unclear patches)

Thanks.

diff --git a/sql/item.h b/sql/item.h
index 043605a..a665d23 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1133,6 +1133,13 @@ class Item: public Type_std_attributes
      update_used_tables();
      return this;
    }
+  virtual COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                           bool link_item_fields,
+                                           COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    return Item::build_equal_items(thd, inherited, link_item_fields);
+  }
    /*
      Checks whether the item is:
      - a simple equality (field=field_item or field=constant_item), or
cond_equal_ref is initialized to 0 by caller, why duplicate initialization here
and everywhere else?

When you write XXX::build_equal_items() you force static call indeed, but not
inlining, which we're aiming for. That is non-inlined static call as such won't
save us much compared to virtual call.

I think our aim should be to keep build_equal_items_and_cond() virtual and have
build_equal_items() inlined into the former. So we mostly rely on compiler's
optimizer.

I _believe_ it should be clever enough to optimize the following as described
above:
class Item
{
   ...
   virtual build_equal_items_and_cond()
   { return build_equal_items(); }
   ...
}

This should be easy to test by adding "inline" to build_equal_items()
declaration and compiling with -Winline.

Makes sense?

...skip...

index 53f249d..0c279ed 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -1989,6 +2002,11 @@ class COND_EQUAL: public Sql_alloc
    {
      upper_levels= 0;
    }
+  COND_EQUAL(Item_equal *item_equal)
+   :upper_levels(0)
+  {
+    current_level.push_back(item_equal);
+  }
    void copy(COND_EQUAL &cond_equal)
    {
      max_members= cond_equal.max_members;
If possible, here and everywhere else please use
push_back(item_equal, thd->mem_root). This will save us one
pthread_getspecific() call.

@@ -1998,6 +2016,8 @@ class COND_EQUAL: public Sql_alloc
      else
        current_level= cond_equal.current_level;
    }
+  Item_equal *build_item_equal_from_current_level(THD *thd,
+                                                  COND_EQUAL *inherited);
  };


@@ -2106,8 +2126,23 @@ class Item_cond_and :public Item_cond
    void mark_as_condition_AND_part(TABLE_LIST *embedding);
    virtual uint exists2in_reserved_items() { return list.elements; };
    bool walk_top_and(Item_processor processor, uchar *arg);
+  void build_new_level(THD *thd, COND_EQUAL *cond_equal);
    COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                            bool link_item_fields);
Didn't get the need for build_item_equal_from_current_level() and
build_new_level(). Is it just some minor refactoring?

...skip...
diff --git a/sql/item_func.h b/sql/item_func.h
index 0d57c2b..01e1527 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -133,6 +133,15 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
    }
    COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
                            bool link_item_fields);
+  COND *build_equal_items_and_cond(THD *thd, COND_EQUAL *inherited,
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
+  {
+    *cond_equal_ref= NULL;
+    COND *cond= build_equal_items(thd, inherited, link_item_fields);
+    DBUG_ASSERT(cond == this);
+    return cond;
+  }
    bool eq(const Item *item, bool binary_cmp) const;
    virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
    virtual bool have_rev_func() const { return 0; }
The only difference from base build_equal_items_and_cond() is just DBUG_ASSERT().
I think assert can be moved into base implementation with more complex condition
too (assuming we'll decide to keep only base implementation).

...skip...

diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 95778f0..7658a24 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -13053,23 +13127,14 @@ static COND *build_equal_items(JOIN *join, COND *cond,

    if (cond)
    {
-    cond= cond->build_equal_items(thd, inherited, link_equal_fields);
-    if (cond->type() == Item::COND_ITEM &&
-        ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
-      cond_equal= &((Item_cond_and*) cond)->m_cond_equal;
-
-    else if (cond->type() == Item::FUNC_ITEM &&
-             ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+    cond= cond->build_equal_items_and_cond(thd, inherited, link_equal_fields,
+                                           &cond_equal);
+    if (cond_equal)
      {
-      cond_equal= new COND_EQUAL;
-      cond_equal->current_level.push_back((Item_equal *) cond);
+      cond_equal->upper_levels= inherited;
+      inherited= cond_equal;
      }
    }
-  if (cond_equal)
-  {
-    cond_equal->upper_levels= inherited;
-    inherited= cond_equal;
-  }
    *cond_equal_ref= cond_equal;

    if (join_list && !ignore_on_conds)
I believe this *cond_equal_ref= cond_equal is probably not needed. Initialize
cond_equal_ref directly and remove cond_equal variable.

Regards,
Sergey
diff --git a/sql/item.h b/sql/item.h
index 043605a..017d348 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1128,9 +1128,11 @@ class Item: public Type_std_attributes
   void print_value(String *);
   virtual void update_used_tables() {}
   virtual COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                                  bool link_item_fields)
+                                  bool link_item_fields,
+                                  COND_EQUAL **cond_equal_ref)
   {
     update_used_tables();
+    DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
     return this;
   }
   /*
@@ -2335,7 +2337,8 @@ class Item_field :public Item_ident
     update_table_bitmaps();
   }
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                                  bool link_item_fields)
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref)
   {
     /*
       normilize_cond() replaced all conditions of type
@@ -2351,7 +2354,8 @@ class Item_field :public Item_ident
         SELECT * FROM t1 WHERE DEFAULT(a);
     */
     DBUG_ASSERT(type() != FIELD_ITEM);
-    return Item_ident::build_equal_items(thd, inherited, link_item_fields);
+    return Item_ident::build_equal_items(thd, inherited, link_item_fields,
+                                         cond_equal_ref);
   }
   bool is_result_field() { return false; }
   void set_result_field(Field *field) {}
@@ -3593,7 +3597,8 @@ class Item_ref :public Item_ident
   table_map used_tables() const;		
   void update_used_tables(); 
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                                  bool link_item_fields)
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref)
   {
     /*
       normilize_cond() replaced all conditions of type
@@ -3604,7 +3609,8 @@ class Item_ref :public Item_ident
       already be replaced. No Item_ref referencing to Item_field are possible.
     */
     DBUG_ASSERT(real_type() != FIELD_ITEM);
-    return Item_ident::build_equal_items(thd, inherited, link_item_fields);
+    return Item_ident::build_equal_items(thd, inherited, link_item_fields,
+                                         cond_equal_ref);
   }
   bool const_item() const 
   {
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 53f249d..0a3bf41 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -563,7 +563,8 @@ class Item_func_eq :public Item_bool_rowready_func2
   const char *func_name() const { return "="; }
   Item *negated_item();
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                          bool link_item_fields);
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref);
   bool check_equality(THD *thd, COND_EQUAL *cond, List<Item> *eq_list);
   /* 
     - If this equality is created from the subquery's IN-equality:
@@ -1772,7 +1773,8 @@ class Item_cond :public Item_bool_func
     used_tables_and_const_cache_update_and_join(list);
   }
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                          bool link_item_fields);
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref);
   virtual void print(String *str, enum_query_type query_type);
   void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
   friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
@@ -1960,6 +1962,9 @@ class Item_equal: public Item_bool_func
   void fix_length_and_dec();
   bool fix_fields(THD *thd, Item **ref);
   void update_used_tables();
+  COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref);
   bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
   Item *transform(Item_transformer transformer, uchar *arg);
   virtual void print(String *str, enum_query_type query_type);
@@ -1989,6 +1994,11 @@ class COND_EQUAL: public Sql_alloc
   { 
     upper_levels= 0;
   }
+  COND_EQUAL(Item_equal *item, MEM_ROOT *mem_root)
+   :upper_levels(0)
+  {
+    current_level.push_back(item, mem_root);
+  }
   void copy(COND_EQUAL &cond_equal)
   {
     max_members= cond_equal.max_members;
@@ -2107,7 +2117,8 @@ class Item_cond_and :public Item_cond
   virtual uint exists2in_reserved_items() { return list.elements; };
   bool walk_top_and(Item_processor processor, uchar *arg);
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                          bool link_item_fields);
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref);
 };
 
 inline bool is_cond_and(Item *item)
diff --git a/sql/item_func.h b/sql/item_func.h
index 0d57c2b..a5ddb24 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -132,7 +132,8 @@ class Item_func :public Item_func_or_sum, public Used_tables_and_const_cache
     used_tables_and_const_cache_update_and_join(arg_count, args);
   }
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                          bool link_item_fields);
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref);
   bool eq(const Item *item, bool binary_cmp) const;
   virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
   virtual bool have_rev_func() const { return 0; }
diff --git a/sql/item_sum.h b/sql/item_sum.h
index b540b44..056c623 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -445,7 +445,8 @@ class Item_sum :public Item_func_or_sum
   table_map used_tables() const { return used_tables_cache; }
   void update_used_tables ();
   COND *build_equal_items(THD *thd, COND_EQUAL *inherited,
-                          bool link_item_fields)
+                          bool link_item_fields,
+                          COND_EQUAL **cond_equal_ref)
   {
     /*
       Item_sum (and derivants) of the original WHERE/HAVING clauses
@@ -453,7 +454,8 @@ class Item_sum :public Item_func_or_sum
       build_equal_items() is called. See Item::split_sum_func2().
     */
     DBUG_ASSERT(0);
-    return Item::build_equal_items(thd, inherited, link_item_fields);
+    return Item::build_equal_items(thd, inherited, link_item_fields,
+                                   cond_equal_ref);
   }
   bool is_null() { return null_value; }
   void make_const () 
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 95778f0..2cc0173 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -12773,7 +12773,8 @@ bool Item_func_eq::check_equality(THD *thd, COND_EQUAL *cond_equal,
 
 COND *Item_cond_and::build_equal_items(THD *thd,
                                        COND_EQUAL *inherited,
-                                       bool link_item_fields)
+                                       bool link_item_fields,
+                                       COND_EQUAL **cond_equal_ref)
 {
   Item_equal *item_equal;
   COND_EQUAL cond_equal;
@@ -12785,6 +12786,7 @@ COND *Item_cond_and::build_equal_items(THD *thd,
   List_iterator<Item> li(*args);
   Item *item;
 
+  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
   /*
      Retrieve all conjuncts of this level detecting the equality
      that are subject to substitution by multiple equality items and
@@ -12809,7 +12811,7 @@ COND *Item_cond_and::build_equal_items(THD *thd,
   if (!args->elements && 
       !cond_equal.current_level.elements && 
       !eq_list.elements)
-    return new Item_int((longlong) 1, 1);
+    return new (thd->mem_root) Item_int((longlong) 1, 1);
 
   List_iterator_fast<Item_equal> it(cond_equal.current_level);
   while ((item_equal= it++))
@@ -12833,7 +12835,7 @@ COND *Item_cond_and::build_equal_items(THD *thd,
   while ((item= li++))
   { 
     Item *new_item;
-    if ((new_item= item->build_equal_items(thd, inherited, FALSE))
+    if ((new_item= item->build_equal_items(thd, inherited, false, NULL))
         != item)
     {
       /* This replacement happens only for standalone equalities */
@@ -12848,19 +12850,23 @@ COND *Item_cond_and::build_equal_items(THD *thd,
   args->append(&eq_list);
   args->append((List<Item> *)&cond_equal.current_level);
   update_used_tables();
+  if (cond_equal_ref)
+    *cond_equal_ref= &m_cond_equal;
   return this;
 }
 
 
 COND *Item_cond::build_equal_items(THD *thd,
                                    COND_EQUAL *inherited,
-                                   bool link_item_fields)
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
 {
   List<Item> *args= argument_list();
   
   List_iterator<Item> li(*args);
   Item *item;
 
+  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
   /*
      Make replacement of equality predicates for lower levels
      of the condition expression.
@@ -12870,7 +12876,7 @@ COND *Item_cond::build_equal_items(THD *thd,
   while ((item= li++))
   { 
     Item *new_item;
-    if ((new_item= item->build_equal_items(thd, inherited, FALSE))
+    if ((new_item= item->build_equal_items(thd, inherited, false, NULL))
         != item)
     {
       /* This replacement happens only for standalone equalities */
@@ -12889,11 +12895,14 @@ COND *Item_cond::build_equal_items(THD *thd,
 
 COND *Item_func_eq::build_equal_items(THD *thd,
                                       COND_EQUAL *inherited,
-                                      bool link_item_fields)
+                                      bool link_item_fields,
+                                      COND_EQUAL **cond_equal_ref)
 {
   COND_EQUAL cond_equal;
   cond_equal.upper_levels= inherited;
   List<Item> eq_list;
+
+  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
   /*
     If an equality predicate forms the whole and level,
     we call it standalone equality and it's processed here.
@@ -12909,7 +12918,7 @@ COND *Item_func_eq::build_equal_items(THD *thd,
     Item_equal *item_equal;
     int n= cond_equal.current_level.elements + eq_list.elements;
     if (n == 0)
-      return new Item_int((longlong) 1,1);
+      return new (thd->mem_root) Item_int((longlong) 1,1);
     else if (n == 1)
     {
       if ((item_equal= cond_equal.current_level.pop()))
@@ -12919,10 +12928,14 @@ COND *Item_func_eq::build_equal_items(THD *thd,
         set_if_bigger(thd->lex->current_select->max_equal_elems,
                       item_equal->n_field_items());  
         item_equal->upper_levels= inherited;
+        if (cond_equal_ref)
+          *cond_equal_ref= new (thd->mem_root) COND_EQUAL(item_equal,
+                                                          thd->mem_root);
         return item_equal;
       }
       Item *res= eq_list.pop();
       res->update_used_tables();
+      DBUG_ASSERT(res->type() == FUNC_ITEM);
       return res;
     }
     else
@@ -12946,15 +12959,19 @@ COND *Item_func_eq::build_equal_items(THD *thd,
       cond_equal.current_level= and_cond->m_cond_equal.current_level;
       args->append((List<Item> *)&cond_equal.current_level);
       and_cond->update_used_tables();
+      if (cond_equal_ref)
+        *cond_equal_ref= &and_cond->m_cond_equal;
       return and_cond;
     }
   }
-  return Item_func::build_equal_items(thd, inherited, link_item_fields);
+  return Item_func::build_equal_items(thd, inherited, link_item_fields,
+                                      cond_equal_ref);
 }
 
 
 COND *Item_func::build_equal_items(THD *thd, COND_EQUAL *inherited,
-                                   bool link_item_fields)
+                                   bool link_item_fields,
+                                   COND_EQUAL **cond_equal_ref)
 {
   /* 
     For each field reference in cond, not from equal item predicates,
@@ -12968,6 +12985,20 @@ COND *Item_func::build_equal_items(THD *thd, COND_EQUAL *inherited,
                       &Item::equal_fields_propagator,
                       (uchar *) inherited);
   cond->update_used_tables();
+  DBUG_ASSERT(cond == this);
+  DBUG_ASSERT(!cond_equal_ref || !cond_equal_ref[0]);
+  return cond;
+}
+
+
+COND *Item_equal::build_equal_items(THD *thd, COND_EQUAL *inherited,
+                                    bool link_item_fields,
+                                    COND_EQUAL **cond_equal_ref)
+{
+  COND *cond= Item_func::build_equal_items(thd, inherited, link_item_fields,
+                                           cond_equal_ref);
+  if (cond_equal_ref)
+    *cond_equal_ref= new (thd->mem_root) COND_EQUAL(this, thd->mem_root);
   return cond;
 }
 
@@ -13049,28 +13080,19 @@ static COND *build_equal_items(JOIN *join, COND *cond,
                                bool link_equal_fields)
 {
   THD *thd= join->thd;
-  COND_EQUAL *cond_equal= 0;
+
+  *cond_equal_ref= NULL;
 
   if (cond) 
   {
-    cond= cond->build_equal_items(thd, inherited, link_equal_fields);
-    if (cond->type() == Item::COND_ITEM &&
-        ((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
-      cond_equal= &((Item_cond_and*) cond)->m_cond_equal;
-
-    else if (cond->type() == Item::FUNC_ITEM &&
-             ((Item_cond*) cond)->functype() == Item_func::MULT_EQUAL_FUNC)
+    cond= cond->build_equal_items(thd, inherited, link_equal_fields,
+                                  cond_equal_ref);
+    if (*cond_equal_ref)
     {
-      cond_equal= new COND_EQUAL;
-      cond_equal->current_level.push_back((Item_equal *) cond);
+      (*cond_equal_ref)->upper_levels= inherited;
+      inherited= *cond_equal_ref;
     }
   }
-  if (cond_equal)
-  {
-    cond_equal->upper_levels= inherited;
-    inherited= cond_equal;
-  }
-  *cond_equal_ref= cond_equal;
 
   if (join_list && !ignore_on_conds)
   {

Follow ups

References