diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc
index 9c3c9580ec9..7deb9cb99f4 100644
--- a/sql/sql_explain.cc
+++ b/sql/sql_explain.cc
@@ -25,6 +25,7 @@
 #include "opt_range.h"
 #include "sql_expression_cache.h"
 #include "item_subselect.h"
+#include <asm/unistd.h>
 
 #include <stack>
 
@@ -54,6 +55,52 @@ Explain_query::Explain_query(THD *thd_arg, MEM_ROOT *root) :
   operations(0)
 {
   optimization_time_tracker.start_tracking(stmt_thd);
+  clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_start);
+  struct rusage rusage_st;
+  getrusage(RUSAGE_THREAD, &rusage_st);
+  tv_utime_start= rusage_st.ru_utime;
+
+#ifdef _LINUX_PERF_EVENT_H
+   memset(&perf_event_attribute, 0, sizeof(perf_event_attribute));
+   perf_event_attribute.type = PERF_TYPE_HARDWARE;
+   perf_event_attribute.size = sizeof(perf_event_attribute);
+   perf_event_attribute.config = PERF_COUNT_HW_INSTRUCTIONS;
+   perf_event_attribute.disabled = 1;
+   perf_event_attribute.exclude_kernel = 1;
+   perf_event_attribute.exclude_hv = 1;
+
+   /*
+    int perf_event_open(struct perf_event_attr *hw,
+                        pid_t pid,
+                        int cpu,
+                        int grp,
+                        int flags)
+
+    hw    describes event and sampling configuration
+    pid   target thread, 0=self, -1=cpu-wide mode
+    cpu   CPU to monitor (can be used in per-thread mode)
+    flags provision to extend the number of parameters
+    grp   file descriptor of group leader even
+   */
+   perf_fd= syscall(__NR_perf_event_open, &perf_event_attribute, 0, -1, -1, 0);
+
+   if (perf_fd > 0)
+   {
+     // SIGIO must go to thread where the event occurred
+     struct f_owner_ex fown;
+
+     fown.type= F_OWNER_TID;
+     fown.pid= thd_arg->os_thread_id;
+     fcntl(perf_fd, F_SETOWN_EX, &fown);
+     ioctl(perf_fd, PERF_EVENT_IOC_RESET, 0);
+     ioctl(perf_fd, PERF_EVENT_IOC_ENABLE, 0);
+   }
+   else
+   {
+     sql_perror( "syscall perf_event_open failed" );
+     DBUG_ASSERT(0);
+   }
+#endif
 }
 
 static void print_json_array(Json_writer *writer,
@@ -81,6 +128,10 @@ Explain_query::~Explain_query()
     delete unions.at(i);
   for (i= 0 ; i < selects.elements(); i++)
     delete selects.at(i);
+
+#ifdef _LINUX_PERF_EVENT_H
+  close(perf_fd);
+#endif
 }
 
 
@@ -301,11 +352,32 @@ void Explain_query::print_query_optimization_json(Json_writer *writer)
 {
   if (optimization_time_tracker.has_timed_statistics())
   {
+    long long count_hw_instructions;
     // if more timers are added, move the query_optimization member 
     // outside the if statement
     writer->add_member("query_optimization").start_object();
     writer->add_member("r_total_time_ms").
             add_double(optimization_time_tracker.get_time_ms());
+
+    struct timespec ts_end;
+    clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts_end);
+    writer->add_member("r_clock_thread_cputime_ms").
+            add_double((ts_end.tv_sec - ts_start.tv_sec) * 1000. + 
+                       (ts_end.tv_nsec- ts_start.tv_nsec) / (1000. * 1000));
+
+    struct rusage rusage_st;
+    getrusage(RUSAGE_THREAD, &rusage_st);
+    struct timeval tv_utime_end= rusage_st.ru_utime;
+    writer->add_member("r_rusage_utime_ms").
+            add_double((tv_utime_end.tv_sec  - tv_utime_start.tv_sec) * 1000. + 
+                       (tv_utime_end.tv_usec - tv_utime_start.tv_usec) / 1000.);
+
+#ifdef _LINUX_PERF_EVENT_H
+    ioctl(perf_fd, PERF_EVENT_IOC_DISABLE, 0);
+    read(perf_fd, &count_hw_instructions, sizeof(count_hw_instructions));
+    writer->add_member("r_count_hw_instructions").add_ll(count_hw_instructions);
+#endif
+
     writer->end_object(); 
   }
 }
diff --git a/sql/sql_explain.h b/sql/sql_explain.h
index b1d8226ea01..ea58d4102ea 100644
--- a/sql/sql_explain.h
+++ b/sql/sql_explain.h
@@ -53,6 +53,10 @@ it into the slow query log.
 #ifndef SQL_EXPLAIN_INCLUDED
 #define SQL_EXPLAIN_INCLUDED
 
+#if __has_include(<linux/perf_event.h>)
+#  include <linux/perf_event.h>
+#endif
+
 class String_list: public List<char>
 {
 public:
@@ -556,6 +560,13 @@ class Explain_query : public Sql_alloc
 #endif
 
   Exec_time_tracker optimization_time_tracker;
+public:
+  struct timespec ts_start;
+  struct timeval  tv_utime_start;
+#ifdef _LINUX_PERF_EVENT_H
+  struct perf_event_attr perf_event_attribute;
+  int perf_fd;
+#endif
 };
 
 
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index 863f03698a4..9820889e4aa 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -249,7 +249,7 @@ void PROF_MEASUREMENT::collect()
 {
   time_usecs= my_interval_timer() / 1e3;  /* ns to us */
 #ifdef HAVE_GETRUSAGE
-  getrusage(RUSAGE_SELF, &rusage);
+  getrusage(RUSAGE_THREAD, &rusage);
 #elif defined(_WIN32)
   FILETIME ftDummy;
   // NOTE: Get{Process|Thread}Times has a granularity of the clock interval,
