WL#5766: PERFORMANCE SCHEMA, stored programs instrumentation

Affects: Server-5.7   —   Status: Complete   —   Priority: Medium

Instrumentation for stored programs:
- stored procedures
- stored functions
- events scheduler events
- table triggers
in the performance schema.

User Documentation
==================

http://dev.mysql.com/doc/refman/5.7/en/statement-summary-tables.html
http://dev.mysql.com/doc/refman/5.7/en/performance-schema-
filtering.html#performance-schema-object-filtering
TABLE performance_schema.setup_instruments
==========================================

Currently, the statements instrumented are:
- "statement/com/...", for COM commands
- "statement/sql/...", for SQL queries.

The stored program instrumentation introduces new types of statement instruments,
to keep track of the internal instructions executed by a MySQL stored programs.

New instruments are named "statement/sp/...".

Note that "sp" stands for "Stored Program",
which is the terminology used in the reference manual.

The list of instruments is implementation dependent.
Tentative list of instruments:

mysql> select * from setup_instruments where name like "statement/sp/%" order by
name;
+--------------------------------+---------+-------+
| NAME                           | ENABLED | TIMED |
+--------------------------------+---------+-------+
| statement/sp/cclose            | YES     | YES   |
| statement/sp/cfetch            | YES     | YES   |
| statement/sp/copen             | YES     | YES   |
| statement/sp/cpop              | YES     | YES   |
| statement/sp/cpush             | YES     | YES   |
| statement/sp/error             | YES     | YES   |
| statement/sp/freturn           | YES     | YES   |
| statement/sp/hpop              | YES     | YES   |
| statement/sp/hpush_jump        | YES     | YES   |
| statement/sp/hreturn           | YES     | YES   |
| statement/sp/jump              | YES     | YES   |
| statement/sp/jump_if_not       | YES     | YES   |
| statement/sp/set               | YES     | YES   |
| statement/sp/set_case_expr     | YES     | YES   |
| statement/sp/set_trigger_field | YES     | YES   |
+--------------------------------+---------+-------+
15 rows in set (0.00 sec)

A new instrument is introduced to keep track of all the EVENTS occurred
scheduled by event scheduler.

New instrument is named "statement/scheduler/event".

mysql> select * from setup_instruments where name like "%statement\/sch%";
+---------------------------+---------+-------+
| NAME                      | ENABLED | TIMED |
+---------------------------+---------+-------+
| statement/scheduler/event | YES     | YES   |
+---------------------------+---------+-------+
1 row in set (0.01 sec)

This will be the nested event for the statements executed inside this event.

TABLE performance_schema.setup_objects
======================================

Schema change:

Column OBJECT_TYPE is changed from
  enum('TABLE')
to
  enum('EVENT', 'FUNCTION', 'PROCEDURE', 'TABLE', 'TRIGGER')

Default data:

After server startup, the content of table setup_objects is by default:

mysql> select * from setup_objects;
+-------------+--------------------+-------------+---------+-------+
| OBJECT_TYPE | OBJECT_SCHEMA      | OBJECT_NAME | ENABLED | TIMED |
+-------------+--------------------+-------------+---------+-------+
| TABLE       | mysql              | %           | NO      | NO    |
| TABLE       | performance_schema | %           | NO      | NO    |
| TABLE       | information_schema | %           | NO      | NO    |
| TABLE       | %                  | %           | YES     | YES   |
| EVENT       | mysql              | %           | NO      | NO    |
| EVENT       | performance_schema | %           | NO      | NO    |
| EVENT       | information_schema | %           | NO      | NO    |
| EVENT       | %                  | %           | YES     | YES   |
| FUNCTION    | mysql              | %           | NO      | NO    |
| FUNCTION    | performance_schema | %           | NO      | NO    |
| FUNCTION    | information_schema | %           | NO      | NO    |
| FUNCTION    | %                  | %           | YES     | YES   |
| PROCEDURE   | mysql              | %           | NO      | NO    |
| PROCEDURE   | performance_schema | %           | NO      | NO    |
| PROCEDURE   | information_schema | %           | NO      | NO    |
| PROCEDURE   | %                  | %           | YES     | YES   |
| TRIGGER     | mysql              | %           | NO      | NO    |
| TRIGGER     | performance_schema | %           | NO      | NO    |
| TRIGGER     | information_schema | %           | NO      | NO    |
| TRIGGER     | %                  | %           | YES     | YES   |
+-------------+--------------------+-------------+---------+-------+
20 rows in set (0.00 sec)

In other words, stored programs are disabled by default in the mysql,
information_schema and performance_schema database, and enabled by default
elsewhere.

TABLE performance_schema.events_statements_current
==================================================

Schema change:

New column NESTING_LEVEL, int(11),
added after NESTING_EVENT_TYPE.

Data change:

For top level statements:
- OBJECT_TYPE = NULL (unchanged)
- OBJECT_SCHEMA = NULL (unchanged)
- OBJECT_NAME = NULL (unchanged)
- NESTING_EVENT_ID is unchanged (currently NULL)
- NESTING_EVENT_TYPE is unchanged (currently NULL)
- NESTING_LEVEL = 0.

For nested statements:
- OBJECT_TYPE = the parent statement object type
- OBJECT_SCHEMA = the parent statement object schema
- OBJECT_NAME = the parent statement object name
- NESTING_EVENT_ID is the parent statement EVENT_ID
- NESTING_EVENT_TYPE is 'STATEMENT'
- NESTING_LEVEL = the parent statement NESTING_LEVEL plus one.

TABLE performance_schema.events_statements_history
==================================================

Same as events_statements_current.

TABLE performance_schema.events_statements_history_long
=======================================================

Same as events_statements_current.

TABLE performance_schema.events_statements_summary_by_program
=============================================================

New table, structure below:

CREATE TABLE `events_statements_summary_by_program` (
  `OBJECT_TYPE` enum('EVENT', 'FUNCTION', 'PROCEDURE', 'TABLE', 'TRIGGER'),
  `OBJECT_SCHEMA` varchar(64) NOT NULL,
  `OBJECT_NAME` varchar(64) NOT NULL,
  `COUNT_STAR` bigint(20) unsigned NOT NULL,
  `SUM_TIMER_WAIT` bigint(20) unsigned NOT NULL,
  `MIN_TIMER_WAIT` bigint(20) unsigned NOT NULL,
  `AVG_TIMER_WAIT` bigint(20) unsigned NOT NULL,
  `MAX_TIMER_WAIT` bigint(20) unsigned NOT NULL,
  `COUNT_STATEMENTS` bigint(20) unsigned NOT NULL,
  `SUM_STATEMENTS_WAIT` bigint(20) unsigned NOT NULL,
  `MIN_STATEMENTS_WAIT` bigint(20) unsigned NOT NULL,
  `AVG_STATEMENTS_WAIT` bigint(20) unsigned NOT NULL,
  `MAX_STATEMENTS_WAIT` bigint(20) unsigned NOT NULL,
  `SUM_LOCK_TIME` bigint(20) unsigned NOT NULL,
  `SUM_ERRORS` bigint(20) unsigned NOT NULL,
  `SUM_WARNINGS` bigint(20) unsigned NOT NULL,
  `SUM_ROWS_AFFECTED` bigint(20) unsigned NOT NULL,
  `SUM_ROWS_SENT` bigint(20) unsigned NOT NULL,
  `SUM_ROWS_EXAMINED` bigint(20) unsigned NOT NULL,
  `SUM_CREATED_TMP_DISK_TABLES` bigint(20) unsigned NOT NULL,
  `SUM_CREATED_TMP_TABLES` bigint(20) unsigned NOT NULL,
  `SUM_SELECT_FULL_JOIN` bigint(20) unsigned NOT NULL,
  `SUM_SELECT_FULL_RANGE_JOIN` bigint(20) unsigned NOT NULL,
  `SUM_SELECT_RANGE` bigint(20) unsigned NOT NULL,
  `SUM_SELECT_RANGE_CHECK` bigint(20) unsigned NOT NULL,
  `SUM_SELECT_SCAN` bigint(20) unsigned NOT NULL,
  `SUM_SORT_MERGE_PASSES` bigint(20) unsigned NOT NULL,
  `SUM_SORT_RANGE` bigint(20) unsigned NOT NULL,
  `SUM_SORT_ROWS` bigint(20) unsigned NOT NULL,
  `SUM_SORT_SCAN` bigint(20) unsigned NOT NULL,
  `SUM_NO_INDEX_USED` bigint(20) unsigned NOT NULL,
  `SUM_NO_GOOD_INDEX_USED` bigint(20) unsigned NOT NULL
) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8

Operations
----------

SELECT is supported.
TRUNCATE is supported, and is used to reset all summaries.

Normal privilege checks do apply: a user must be granted the proper table
privileges to perform an operation.

Semantic
--------

OBJECT_TYPE, OBJECT_SCHEMA, OBJECT_NAME is the primary key that identifies the
stored program.

COUNT_STAR, SUM/MIN/AVG/MAX TIMER_WAIT are statistics about
the stored program overall execution:
the number if times the stored program is invoked,
and the stored program execution time.

COUNT_STATEMENTS, SUM/MIN/AVG/MAX STATEMENTS are statistics about nested
statements invoked during the stored program execution.

SUM_LOCK_TIME, ..., SUM_NO_GOOD_INDEX_USED are all the stored program
statements statistics, aggregated.

Effect of truncate
------------------

Statistics are reset.

Data
----

Table events_statements_summary_by_program expose statistics for:
- EVENT
- FUNCTION
- PROCEDURE
- TRIGGER

Statistics are exposed (a row added) when the object is first used in the server.

Statistics are removed (a row removed) when the object is dropped in the server.

Statistics are aggregated (a row modified) only when the stored program
instrumentation is enabled, per table setup_objects.

Server global variable performance_schema_max_program_instances
===============================================================

This variable is global, read only.
This variable indicates the maximum number of stored program (stored procedures,
stored functions, event scheduler events, table triggers) the performance schema
keeps statistics for.

The default value is fixed (no auto tuning available),
the value itself is tentatively defined to 5000,
subject to implementation changes.

Server global variable performance_schema_max_statement_stack
=============================================================

This variable is global, read only.
This variable indicates the maximum depth of stored program nested calls the
performance schema keep statistics for.

The default value is fixed (no auto tuning available),
the value itself is tentatively defined to 10,
subject to implementation changes.

Server global status performance_schema_program_lost
====================================================

This variable is global.
It is a status variable, can be reset to 0 with FLUSH STATUS.
This variable indicates how many stored programs statistics were lost by the
performance schema instrumentation, due to insufficient space in
performance_schema_max_program_instances.

Server global status performance_schema_nested_statement_lost
=============================================================

This variable is global.
It is a status variable, can be reset to 0 with FLUSH STATUS.
This variable indicates how many stored programs statements were lost by the
performance schema instrumentation, due to insufficient space in
performance_schema_max_statement_stack.

REQUIREMENTS
============

Install
-------

Func-Req (1): A fresh MySQL installation of CURRENT-VERSION must create the
following tables:
- 1.1, TABLE performance_schema.events_statements_summary_by_program

Upgrade
-------

Func-Req (2): An upgrade from PREVIOUS-VERSION to CURRENT-VERSION must upgrade
the following tables:
- 2.1, TABLE performance_schema.setup_objects
- 2.2, TABLE performance_schema.events_statements_current
- 2.3, TABLE performance_schema.events_statements_history
- 2.4, TABLE performance_schema.events_statements_history_long

Server options and variables
----------------------------

Func-Req (3): The following server variables are defined:
- 3.1, global variable performance_schema_max_program_instances
- 3.2, global variable performance_schema_max_statement_stack
- 3.3, global status performance_schema_program_lost
- 3.4, global status performance_schema_nested_statement_lost

Behavior
--------

Func-Req (4): The content of table setup_objects control whether stored programs
instrumentation is enabled and or timed, for
- 4.1, EVENTS
- 4.2, STORED FUNCTIONS
- 4.3, STORED PROCEDURES
- 4.4, TABLE TRIGGERS

Func-Req (5): For table performance_schema.events_statements_summary_by_program:
- 5.1, TRUNCATE reset the statistics collected
- 5.2, SELECT returns the statistics collected during stored program execution


===================================================
Low level design changes for statistics collection:
===================================================

enum enum_object_type has been modified as follow:
 enum enum_object_type                                                          
 {                                                                              
   OBJECT_TYPE_TABLE= 1,                                                        
-  OBJECT_TYPE_TEMPORARY_TABLE= 2                                               
+  OBJECT_TYPE_EVENT= 2,                                                        
+  OBJECT_TYPE_FUNCTION= 3,                                                     
+  OBJECT_TYPE_PROCEDURE= 4,                                                    
+  OBJECT_TYPE_TRIGGER= 5,                                                      
+  OBJECT_TYPE_TEMPORARY_TABLE= 6                                               
 };


NEW INSTRUMENTATION INTERFACE:
------------------------------
A new Instrumentation interface for stored program is added:

struct PSI_sp_locker;                                                          
struct PSI_sp_locker_state_v1                                                  
{                                                                              
  /** Current thread. */                                                       
  struct PSI_thread *m_thread;                                                 
  /** Timer start. */                                                          
  ulonglong m_timer_start;                                                     
  /** Timer function. */                                                       
  ulonglong (*m_timer)(void);                                                  
  /** Object type. */                                                          
  uint m_object_type;                                                          
  /** Schema name. */                                                          
  const char* m_schema_name;                                                   
  uint m_schema_name_length;                                                   
  /** Object name. */                                                          
  const char* m_object_name;                                                   
  uint m_object_name_length;                                                   
  /** Is enabled. */                                                           
  my_bool m_enabled;                                                           
  /** Is timed. */                                                             
  my_bool m_timed;                                                             
};               

Four new APIs added:

/* To start collecting stats for Stored Procedure */                          
typedef void (*start_sp_v1_t)                                                  
  (struct PSI_sp_locker *locker);                    

/* To stop collecting stats for Stored Procedure.                              
typedef void (*end_sp_v1_t)                                                    
  (struct PSI_sp_locker *locker);

/* To drop a stored procedure stats once it is dropped from server. */
typedef void (*drop_sp_v1_t)                                                   
  (struct PSI_sp_locker_state_v1 *state);

/* To Set the statement parent stored program. */
typedef void (*set_statement_parent_v1_t)                                      
  (struct PSI_statement_locker *locker,                                        
   const void * head);                                                         
                                                                               


Implementation of above 4 new APIs is added in pfs.cc.
------------------------------


NEW INSTRUMENTATION HELPER FILE:
---------------------------------
A new file, mysql/psi/mysql_sp.h, for stored procedure instrumentation helper is
added. It consists of Macro definitions like:
MYSQL_START_SP
MYSQL_END_SP
MYSQL_DROP_SP

A new compilation option to disable stored Program instrumentation:
DISABLE_PSI_SP
---------------------------------


A new structure to keep SP usage information is added to pfs_stat.h
+/** Statistics for stored program usage. */                                    
+struct PFS_sp_stat                                                             
+{                                                                              
+  PFS_single_stat m_timer1_stat;                                               
+                                                                               
+  inline void reset(void)                                                      
+  { m_timer1_stat.reset(); }                                                   
+                                                                               
+  inline void aggregate_counted()                                              
+  { m_timer1_stat.aggregate_counted(); }                                       
+                                                                               
+  inline void aggregate_value(ulonglong value)                                 
+  { m_timer1_stat.aggregate_value(value); }                                    
+                                                                               
+  inline void aggregate(PFS_stage_stat *stat)                                  
+  { m_timer1_stat.aggregate(& stat->m_timer1_stat); }                          
+};


NEW FILES pfs_program.h AND pfs_program.cc:
-------------------------------------------
A new file,pfs_program.h, added to keep declaration of buffers related to Stored
Programs Instrumentation and their definitions are added in pfs_program.cc. To
collect the stats of a stored program a new structure (buffer) has been added:

struct PFS_program                                                         
{                                                                               
  /** Object type. */                                                           
  enum_object_type m_type;                                                      
                                                                                
  /** Object name. */                                                           
  char m_object_name[OBJECT_NAME_LENGTH];                                       
  int m_object_name_length;                                                     
                                                                                
  /** Object Schema name. */                                                    
  char m_schema_name[SCHEMA_NAME_LENGTH];                                       
  int m_schema_name_length;                                                     
                                                                                
  /** Sub statement stat. */                                                    
  PFS_statement_stat m_stmt_stat;                                               
                                                                                
  /** Stored program stat. */                                                   
  PFS_sp_stat m_sp_stat;                                                        
                                                                                
  /** Hash key */                                                               
  PFS_program_key m_key;                                                        
                                                                                
  /** Reset data for this record. */                                            
  void reset_data();                                                            
};                                                                              

/**                                                                             
  Hash key for a program.                                                       
*/                                                                              
struct PFS_program_key                                                          
{                                                                               
  /**                                                                           
    Hash search key.                                                            
    This has to be a string for LF_HASH,                                        
    the format is "<object_type><0x00><object_name><0x00><schema_name><0x00>"  
                         
  */                                                                            
  char m_hash_key[HASH_KEY_LENGTH];                                             
  uint m_key_length;                                                            
};

extern ulong program_lost;
extern PFS_program *program_array;

PFS_program_key is a Hash key which will be used to search a stored program in
program_array. 

An array "program_array" of PFS_program will be created to hold
statistics of each and evey stored program executed on server. This array would
be used to populate newly introduced PFS table events_statements_summary_by_program.

program_lost is a counter to keep track of SP whose stats are not recorded.

Two new functions are added in pfs_program.h.
/* To search (or create) record of a stored procedure which is used. */
PFS_program_stat*                                                               
find_or_create_program(PFS_thread *thread,                                      
                      enum_object_type object_type,                             
                      const char *object_name,                                  
                      uint object_name_length,                                  
                      const char *schema,                                       
                      uint schema_length,
                      my_bool fromSP);   

find_or_create_program will be called from end_statement and from end_sp. In
this function, we would increase lost_program counter only when this call is
from Stored Program. fromSP flag indicates if this call is from pfs_end_sp.

/* To search and drop stats of a stored procedure which is dropped from server. */
int                                                                             
find_and_drop_program(PFS_thread *thread,                                       
                      enum_object_type object_type,                             
                      const char *object_name,                                  
                      uint object_name_length,                                  
                      const char *schema_name,                                  
                      uint schema_name_length);
-------------------------------------------



CHANGES IN pfs_events_statements.h
-----------------------------------
structure PFS_events_statements has been modified to have :
 /** A statement record. */                                                     
 struct PFS_events_statements : public PFS_events                               
 {                                                                              
+  uint m_sp_type;                 (Type of stored program to which it belongs)
+  char m_schema_name[NAME_LEN];   (Schema name of stored program) 
+  uint m_schema_name_length;                    
+  char m_object_name[NAME_LEN];   (Stored program name)
+  uint m_object_name_length;                                                   
+  ulonglong m_nesting_event_id;   (its parent event id)
   ...                                
 }

+extern ulong nested_statement_lost; 

nested_statement_lost is to keep track of sub statements whose stats are lost.
-----------------------------------



static void set_statement_parent_v1(PSI_statement_locker *locker,              
                                    const void *head)
While executing a sub-statement, this function will be called to setup the
stored program information (to which this sub-statement belongs) for this
sub-statement.



-------------------------------------
COLLECTING STATS OF A STORED PROGRAM:
-------------------------------------

bool sp_head::execute_trigger/function/procedure() are the functions from where
execution of a stored program start. Hooks to start collecting stats for
Performance Schema are added

bool sp_head::execute_trigger/function/procedure()
{
...
+#ifdef HAVE_PSI_SP_INTERFACE                                                   
+  PSI_sp_locker_state state;                                                   
+  PSI_sp_locker *locker;                                                       
+                                                                               
+  /* Populate locker_state */
+
+  locker= MYSQL_START_SP(&state);                                              
+#endif                                                                         
   err_status= execute(thd, FALSE);                                             
+#ifdef HAVE_PSI_SP_INTERFACE                                                   
+  MYSQL_END_SP(locker);                                                        
+#endif
...
}
-------------------------------------


-----------------------------------
COLLECTING STATS OF SUB-STATEMENTS:
-----------------------------------

"bool sp_head::execute(THD *thd, bool merge_da_on_success)" is the function from
where execution of each sub-statement belonging to a stored program starts. So
here before executing sub-statement, we added hooks to collect stastics
information for sub-statement being executed:
bool sp_head::execute(THD *thd, bool merge_da_on_success)
{
...
+ MYSQL_START_STATEMENT()      => Wrapper to start statistics of any statement.
+ MYSQL_SET_STATEMENT_PARENT() => Wrapper to add information about sub program
to which this statement belongs.
+ execute()                    => Execution of statement
+ MYSQL_END_STATEMENT()        => Wrapper to close statistics of a statement
executed.
...
}
So after execution of every statements of a sub-program, we would have
statistics of all the sub-statements executed in it. 
-----------------------------------


Overall Flow For statistics collection:
---------------------------------------
--A Stored Program execution starts.
---Control reaches to sp_head::execute_trigger/function/procedure and statistics
collection starts. (MYSQL_START_SP)
-----For a sub-statement execution, control reaches to sp_head::execute()
------Sub-statement statistics collection starts (MYSQL_START_STATEMENT)
-------Sub-statement's SP information is populated (MYSQL_SET_STATEMENT_PARENT)
------Sub-statement is executed.
------Sub-statement statistics collection stops. (MYSQL_END_STATEMENT)
-------find_or_create_program() to collect the statistics of this sub-statement.
--------If stored program found in program_stat_array
----------update its statistics return.
--------Else
----------Add this SP to program_stat_array and update stats and return.
-----statement execution and stats collection done.
-----for another sub-statement in SP, go to step 3 again.
---Stored program execution finishes and stats collection stops. (MYSQL_END_SP)
----call find_or_create_program() to collect stats of this stored program.
--Stored Program execution finished.
---------------------------------------


LLD FOR REMOVING STATS OF A SP ONCE IT IS DROPPED FROM SERVER:
-------------------------------------------------------------
In file sql/sql_parse.cc, in function mysql_execute_command, PS hooks are added 
to make sure once SP is dropped, coressponding PS Macro is called to drop its
stats.

int                                                                             
mysql_execute_command(THD *thd)                                                 
{ 
  ...
  switch (lex->sql_command) {
  ...
  case SQLCOM_DROP_EVENT:                                                       
    if (!(res= Events::drop_event(thd,                                          
                                  lex->spname->m_db, lex->spname->m_name,       
                                  lex->drop_if_exists)))
      {                                                                         
#ifdef HAVE_PSI_SP_INTERFACE                                                    
        PSI_sp_locker_state state;               
        ...                               
        /* populate state with SP information. */                              
                                                 
        ...
        /* Drop statistics for this stored program from performance schema. */  
        MYSQL_DROP_SP(&state);                                                  
#endif                                                                          
        my_ok(thd);                                                             
      }                                                                         
    break;
  ...
  case SQLCOM_DROP_PROCEDURE:                                                   
  case SQLCOM_DROP_FUNCTION:                                                    
    {
       <same as above>
    }
    break;
  case SQLCOM_DROP_TRIGGER:                                                     
    {
      <same as above>
    }
  ...
  }
...
}

New function pfs_drop_sp_v1(), will call find_and_drop_program which eventually
drops the stats of this SP from program_stat_array. This empty entry in
program_array will be used for new Stored Procedur which could be executed in
future.

-------------------------------------------------------------


Two new variables added to structure PFS_global_param.
struct PFS_global_param                                                         
{
  ...
  /** Maximum number of programs to be captured */                              
  long m_program_sizing
  /** Maximum size of statement stack */                                        
  ulong m_statement_stack_sizing;
  ...
}


LLD FOR NESTING EVENT_ID/TYPE/LEVEL UPDATION FOR SUB STATEMENTS:
----------------------------------------------------------------
a new member m_nesting_event_level has been added to structure PFS_events.
/** An event record. */                                                         
struct PFS_events                                                               
{ 
  ...
  /** NESTING_EVENT_LEVEL */                                                    
  uint m_nesting_event_level;
  ...
}

In function pfs_get_thread_statement_locker_v1(), if this is not the top level
statement, then set its m_nesting_event_id/level/type using the previous
statement on the stack.
----------------------------------------------------------------


PERFORMANCE SCHEMA STATUS REPORTING:
------------------------------------
pfs_show_status() has been modified to include the size/count/memory usage by
new table and hash.
------------------------------------


===================================================
Low level design changes for statistics Reporting: 
===================================================
A new table's (table_event_statements_summary_by_program) DDL added to
scripts/mysql_system_tables.sql as described in HLD.

NEW FILES table_esms_by_program.h AND table_esms_by_program.cc:
---------------------------------------------------------------
To keep declaration related to new PS table, table_esms_by_program.h is added
and corresponding definitions are added in table_esms_by_program.cc.

New structure is added in table_esms_by_program.h to represent a record in
table_event_statements_summary_by_program table.
+struct row_esms_by_program                                                     
+{                                                                              
+  /** Column OBJECT_TYPE. */                                                   
+  enum_object_type m_object_type;
+  /** Column OBJECT_SCHEMA. */                                                 
+  char m_schema_name[80];                                                      
+  int m_schema_name_length;                                                    
+  /** Column OBJECT_NAME. */                                                   
+  char m_object_name[80];                                                      
+  int m_object_name_length;                                                    
+                                                                               
+  /**                                                                          
+    Columns COUNT_STAR                                                         
+            SUM_TIMER_WAIT                                                     
+            MIN_TIMER_WAIT                                                     
+            AVG_TIMER_WAIT                                                     
+            MAX_TIMER_WAIT                                                     
+  */                                                                           
+  PFS_sp_stat_row m_sp_stat;                                                   
+                                                                               
+  /** Columns COUNT_STATEMENTS,SUM_STATEMENTS_WAIT...SUM_NO_GOOD_INDEX_USED. */
+  PFS_statement_stat_row m_stmt_stat;                                          
+};

A new class is added to represent new table in PS.
+class table_esms_by_program : public PFS_engine_table                          
+{
...
+  /** Current row. */                                                          
+  row_esms_by_program m_row;
...
+}

Implementation of member functions for class table_esms_by_program is added in
table_esms_by_program.cc. Here is the snippet of make_row() function:
+void table_esms_by_program::make_row(PFS_program* program)           
+{                                                                              
+                                                                               
+  m_row_exists= false;                                                         
+                                                                               
+  /* set m_row.m_object_type/name/name_length from program. */
+
+  /* set m_row.m_schema_name/name_length from program. */
+                                                                               
+  /* Get stored program's over all stats. */                                   
+  time_normalizer *normalizer1= time_normalizer::get(statement_timer);         
+  m_row.m_sp_stat.set(normalizer1, &program->m_sp_stat);                  
+                                                                               
+  /* Get sub statements' stats. */                                            
                              
+  time_normalizer *normalizer2= time_normalizer::get(statement_timer);         
+  m_row.m_stmt_stat.set(normalizer2, & program->m_stmt_stat);             
+                                                                               
+  m_row_exists= true;                                                          
+}
---------------------------------------------------------------

CHANGES IN table_helper.h and table_helper.cc:
----------------------------------------------
Helper functions to make row from program_stat_array and populate summary table
fields are added in table_helper.h and their definitions are added in
table_helper.cc.
+/** Row fragment for stored program statistics. */                             
+struct PFS_sp_stat_row                                                         
+{                                                                              
+  PFS_stat_row m_timer1_row;                                                   
+                                                                	               
+  /** Build a row from a memory buffer. */                                     
+  inline void set(time_normalizer *normalizer, const PFS_sp_stat *stat)        
+  {                                                                            
+    m_timer1_row.set(normalizer, & stat->m_timer1_stat);                       
+  }                                                                            
+                                                                               
+  /** Set a table field from the row. */                                       
+  void set_field(uint index, Field *f);                                        
+};
----------------------------------------------

Overall Flow For statistics reporting:
=====================================================================
stored programs' stat array program_stat_array will be used to read statistics
and report back them to user in table_event_statement_summary_by_program tables.