Bug #73168 locking/unlocking overhead for THD::LOCK_thd_data

Submitted: 2 Jul 2014 4:14 Modified: 2 Jul 2014 11:15
Reporter: liu hickey (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S5 (Performance)
Version:5.6/5.7 OS:Any
Assigned to: CPU Architecture:Any
Tags: LOCK_thd_data, set_query

[2 Jul 2014 4:14] liu hickey
Description:
For LOCK_thd_data mutex, it's major used to protect thd->query and thd->query_length, accessed from other SHOW related threads:

  /**
    Protects THD data accessed from other threads:
    - thd->query and thd->query_length (used by SHOW ENGINE
      INNODB STATUS and SHOW PROCESSLIST
    - thd->mysys_var (used by KILL statement and shutdown).
    Is locked when THD is deleted.
  */
  mysql_mutex_t LOCK_thd_data;

While seen from the PS, it's called too much for normal workload, and major in THD::set_query_xx():

root@performance_schema 05:35:59>select e.EVENT_NAME, e.SOURCE, e.OPERATION, count(*) as cnt from events_waits_current e join threads t using(thread_id) where type='foreground' and processlist_id not in (1, @@pseudo_thread_id) group by e.EVENT_NAME, e.SOURCE, e.OPERATION order by cnt desc;
+-----------------------------------------+-------------------+-------------+------+
| EVENT_NAME | SOURCE | OPERATION | cnt |
+-----------------------------------------+-------------------+-------------+------+
| wait/synch/mutex/sql/THD::LOCK_thd_data | sql_class.cc:4662 | lock | 3992 |
| wait/io/file/innodb/innodb_log_file | fil0fil.cc:5895 | sync | 2 |
| wait/io/table/sql/handler | handler.cc:7347 | insert | 2 |
| wait/synch/mutex/sql/THD::LOCK_thd_data | sql_base.cc:1492 | lock | 1 |
| wait/lock/table/sql/handler | thr_lock.c:556 | read normal | 1 |
| wait/io/table/sql/handler | handler.cc:2868 | fetch | 1 |
| wait/io/table/sql/handler | handler.cc:2833 | fetch | 1 |
+-----------------------------------------+-------------------+-------------+------+

I added some counter stats for THD::set_query_xxx() and found THD::set_query() is executed  87173.2 per second!

$gdb -p 113129 -ex " set pagination 0" -ex "print nq" -ex "print nqi" -ex "print ni" -batch && sleep 5 && gdb -p 113129 -ex " set pagination 0" -ex "print nq" -ex "print nqi" -ex "print ni" -batch

$1 = 4972652
$2 = 0
$3 = 2486397

$1 = 5408518
$2 = 0
$3 = 2704340

After remove the locking/unlocking in THD::set_query_xxx(), and re-run the load,  this mutex has gone in PS:

root@performance_schema 07:14:16>select e.EVENT_NAME, e.SOURCE, e.OPERATION, count(*) as cnt from events_waits_current e join threads t using(thread_id) where type='foreground' and processlist_id not in (1, @@pseudo_thread_id) group by e.EVENT_NAME, e.SOURCE, e.OPERATION order by cnt desc;
+-------------------------------------+-------------------+-------------------+------+
| EVENT_NAME | SOURCE | OPERATION | cnt |
+-------------------------------------+-------------------+-------------------+------+
| idle | mysqld.cc:952 | idle | 3415 |
| wait/io/file/sql/binlog | mf_iocache.c:1788 | write | 525 |
| wait/io/file/innodb/innodb_log_file | fil0fil.cc:5701 | write | 34 |
| wait/io/table/sql/handler | handler.cc:2833 | fetch | 8 |
| wait/io/table/sql/handler | handler.cc:2868 | fetch | 8 |
| wait/io/table/sql/handler | handler.cc:7347 | insert | 5 |
| wait/lock/table/sql/handler | thr_lock.c:556 | write allow write | 3 |
| wait/io/table/sql/handler | handler.cc:2992 | fetch | 1 |
| wait/io/file/sql/binlog | binlog.cc:6655 | sync | 1 |
+-------------------------------------+-------------------+-------------------+------+
9 rows in set (2.14 sec)

How to repeat:
PS monitor

Suggested fix:
As the THD::set_query_xxx() is only conflicts with mysqld_list_processes(SHOW PROCESSLIST) and fill_schema_processlist (SHOW ENGINE INNODB STATUS), we can benefit with less overhead if replace mutex with lock-free atomic operations.
[2 Jul 2014 11:15] MySQL Verification Team
Hello Liu,

Thank you for the report.
I observed this while using sysbench

// 5.6.20 with defaults settings
// mysqld with --performance_schema_instrument='wait/synch/mutex/%=on'
** set up proper consumers

// Sysbench

[root@cluster-repo mysql-advanced-5.6.20]# sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=dbtest --mysql-user=root --mysql-socket=/tmp/72720M/72720M.sock prepare
sysbench 0.4.12:  multi-threaded system evaluation benchmark

No DB drivers specified, using mysql
Creating table 'sbtest'...
Creating 1000000 records in table 'sbtest'...
[root@cluster-repo mysql-advanced-5.6.20]# sysbench --test=oltp --oltp-test-mode=complex --oltp-read-only=off --oltp-table-size=1000000 --num-threads=900 --max-time=360 --max-requests=0 --mysql-db=dbtest --mysql-user=root --mysql-socket=/tmp/72720M/72720M.sock run
sysbench 0.4.12:  multi-threaded system evaluation benchmark

No DB drivers specified, using mysql
Running the test with following options:
Number of threads: 900

Doing OLTP test.
Running mixed OLTP test
Using Special distribution (12 iterations,  1 pct of values are returned in 75 pct cases)
Using "BEGIN" for starting transactions
Using auto_inc on the id column
Threads started!

// 
mysql> select version();
+---------------------------------------+
| version()                             |
+---------------------------------------+
| 5.6.20-enterprise-commercial-advanced |
+---------------------------------------+
1 row in set (0.00 sec)

mysql> use performance_schema;select e.EVENT_NAME, e.SOURCE, e.OPERATION, count(*) as cnt from events_waits_current e join threads t using(thread_id) where type='foreground' and processlist_id not in (1, @@pseudo_thread_id) group by e.EVENT_NAME, e.SOURCE, e.OPERATION order by cnt desc;
Database changed
+-----------------------------------------+-------------------+-----------+-----+
| EVENT_NAME                              | SOURCE            | OPERATION | cnt |
+-----------------------------------------+-------------------+-----------+-----+
| wait/synch/mutex/sql/THD::LOCK_thd_data | sql_class.cc:4467 | lock      | 250 |
| idle                                    | mysqld.cc:935     | idle      |  89 |
| wait/synch/mutex/sql/LOCK_open          | sql_base.cc:2936  | lock      |  36 |
| wait/synch/mutex/sql/THD::LOCK_thd_data | sql_class.h:3983  | lock      |   4 |
| wait/synch/mutex/innodb/dict_sys_mutex  | dict0dict.cc:1026 | lock      |   3 |
| wait/io/table/sql/handler               | handler.cc:2788   | fetch     |   1 |
+-----------------------------------------+-------------------+-----------+-----+
6 rows in set (0.08 sec)

Thanks,
Umesh
[25 Feb 2015 10:51] MySQL Verification Team
Hello Liu,

Could you please provide more details about real performance impact? Do you have any test case/ real time stats which confirms the performance impact etc? 

Thanks,
Umesh

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.040 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.