1 /* Copyright (c) 2008, 2021, Oracle and/or its affiliates. 2 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License, version 2.0, 5 as published by the Free Software Foundation. 6 7 This program is also distributed with certain software (including 8 but not limited to OpenSSL) that is licensed under separate terms, 9 as designated in a particular file or component or in included license 10 documentation. The authors of MySQL hereby grant you an additional 11 permission to link the program and your derivative works with the 12 separately licensed software that they have included with MySQL. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License, version 2.0, for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software Foundation, 21 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ 22 23 #ifndef PFS_STAT_H 24 #define PFS_STAT_H 25 26 #include <algorithm> 27 #include "sql_const.h" 28 /* memcpy */ 29 #include "string.h" 30 31 /** 32 @file storage/perfschema/pfs_stat.h 33 Statistics (declarations). 34 */ 35 36 /** 37 @addtogroup Performance_schema_buffers 38 @{ 39 */ 40 41 /** Single statistic. */ 42 struct PFS_single_stat 43 { 44 /** Count of values. */ 45 ulonglong m_count; 46 /** Sum of values. */ 47 ulonglong m_sum; 48 /** Minimum value. */ 49 ulonglong m_min; 50 /** Maximum value. */ 51 ulonglong m_max; 52 PFS_single_statPFS_single_stat53 PFS_single_stat() 54 { 55 m_count= 0; 56 m_sum= 0; 57 m_min= ULLONG_MAX; 58 m_max= 0; 59 } 60 resetPFS_single_stat61 inline void reset(void) 62 { 63 m_count= 0; 64 m_sum= 0; 65 m_min= ULLONG_MAX; 66 m_max= 0; 67 } 68 has_timed_statsPFS_single_stat69 inline bool has_timed_stats() const 70 { 71 return (m_min <= m_max); 72 } 73 aggregatePFS_single_stat74 inline void aggregate(const PFS_single_stat *stat) 75 { 76 if (stat->m_count != 0) 77 { 78 m_count+= stat->m_count; 79 m_sum+= stat->m_sum; 80 if (unlikely(m_min > stat->m_min)) 81 m_min= stat->m_min; 82 if (unlikely(m_max < stat->m_max)) 83 m_max= stat->m_max; 84 } 85 } 86 aggregate_no_checkPFS_single_stat87 inline void aggregate_no_check(const PFS_single_stat *stat) 88 { 89 m_count+= stat->m_count; 90 m_sum+= stat->m_sum; 91 if (unlikely(m_min > stat->m_min)) 92 m_min= stat->m_min; 93 if (unlikely(m_max < stat->m_max)) 94 m_max= stat->m_max; 95 } 96 aggregate_countedPFS_single_stat97 inline void aggregate_counted() 98 { 99 m_count++; 100 } 101 aggregate_countedPFS_single_stat102 inline void aggregate_counted(ulonglong count) 103 { 104 m_count+= count; 105 } 106 aggregate_valuePFS_single_stat107 inline void aggregate_value(ulonglong value) 108 { 109 m_count++; 110 m_sum+= value; 111 if (unlikely(m_min > value)) 112 m_min= value; 113 if (unlikely(m_max < value)) 114 m_max= value; 115 } 116 aggregate_many_valuePFS_single_stat117 inline void aggregate_many_value(ulonglong value, ulonglong count) 118 { 119 m_count+= count; 120 m_sum+= value; 121 if (unlikely(m_min > value)) 122 m_min= value; 123 if (unlikely(m_max < value)) 124 m_max= value; 125 } 126 }; 127 128 /** Combined statistic. */ 129 struct PFS_byte_stat : public PFS_single_stat 130 { 131 /** Byte count statistics */ 132 ulonglong m_bytes; 133 134 /** Aggregate wait stats, event count and byte count */ aggregatePFS_byte_stat135 inline void aggregate(const PFS_byte_stat *stat) 136 { 137 if (stat->m_count != 0) 138 { 139 PFS_single_stat::aggregate_no_check(stat); 140 m_bytes+= stat->m_bytes; 141 } 142 } 143 144 /** Aggregate wait stats, event count and byte count */ aggregate_no_checkPFS_byte_stat145 inline void aggregate_no_check(const PFS_byte_stat *stat) 146 { 147 PFS_single_stat::aggregate_no_check(stat); 148 m_bytes+= stat->m_bytes; 149 } 150 151 /** Aggregate individual wait time, event count and byte count */ aggregatePFS_byte_stat152 inline void aggregate(ulonglong wait, ulonglong bytes) 153 { 154 aggregate_value(wait); 155 m_bytes+= bytes; 156 } 157 158 /** Aggregate wait stats and event count */ aggregate_waitsPFS_byte_stat159 inline void aggregate_waits(const PFS_byte_stat *stat) 160 { 161 PFS_single_stat::aggregate(stat); 162 } 163 164 /** Aggregate event count and byte count */ aggregate_countedPFS_byte_stat165 inline void aggregate_counted() 166 { 167 PFS_single_stat::aggregate_counted(); 168 } 169 170 /** Aggregate event count and byte count */ aggregate_countedPFS_byte_stat171 inline void aggregate_counted(ulonglong bytes) 172 { 173 PFS_single_stat::aggregate_counted(); 174 m_bytes+= bytes; 175 } 176 PFS_byte_statPFS_byte_stat177 PFS_byte_stat() 178 { 179 reset(); 180 } 181 resetPFS_byte_stat182 inline void reset(void) 183 { 184 PFS_single_stat::reset(); 185 m_bytes= 0; 186 } 187 }; 188 189 /** Statistics for mutex usage. */ 190 struct PFS_mutex_stat 191 { 192 /** Wait statistics. */ 193 PFS_single_stat m_wait_stat; 194 #ifdef PFS_LATER 195 /** 196 Lock statistics. 197 This statistic is not exposed in user visible tables yet. 198 */ 199 PFS_single_stat m_lock_stat; 200 #endif 201 aggregatePFS_mutex_stat202 inline void aggregate(const PFS_mutex_stat *stat) 203 { 204 m_wait_stat.aggregate(&stat->m_wait_stat); 205 #ifdef PFS_LATER 206 m_lock_stat.aggregate(&stat->m_lock_stat); 207 #endif 208 } 209 resetPFS_mutex_stat210 inline void reset(void) 211 { 212 m_wait_stat.reset(); 213 #ifdef PFS_LATER 214 m_lock_stat.reset(); 215 #endif 216 } 217 }; 218 219 /** Statistics for rwlock usage. */ 220 struct PFS_rwlock_stat 221 { 222 /** Wait statistics. */ 223 PFS_single_stat m_wait_stat; 224 #ifdef PFS_LATER 225 /** 226 RWLock read lock usage statistics. 227 This statistic is not exposed in user visible tables yet. 228 */ 229 PFS_single_stat m_read_lock_stat; 230 /** 231 RWLock write lock usage statistics. 232 This statistic is not exposed in user visible tables yet. 233 */ 234 PFS_single_stat m_write_lock_stat; 235 #endif 236 aggregatePFS_rwlock_stat237 inline void aggregate(const PFS_rwlock_stat *stat) 238 { 239 m_wait_stat.aggregate(&stat->m_wait_stat); 240 #ifdef PFS_LATER 241 m_read_lock_stat.aggregate(&stat->m_read_lock_stat); 242 m_write_lock_stat.aggregate(&stat->m_write_lock_stat); 243 #endif 244 } 245 resetPFS_rwlock_stat246 inline void reset(void) 247 { 248 m_wait_stat.reset(); 249 #ifdef PFS_LATER 250 m_read_lock_stat.reset(); 251 m_write_lock_stat.reset(); 252 #endif 253 } 254 }; 255 256 /** Statistics for COND usage. */ 257 struct PFS_cond_stat 258 { 259 /** Wait statistics. */ 260 PFS_single_stat m_wait_stat; 261 #ifdef PFS_LATER 262 /** 263 Number of times a condition was signalled. 264 This statistic is not exposed in user visible tables yet. 265 */ 266 ulonglong m_signal_count; 267 /** 268 Number of times a condition was broadcast. 269 This statistic is not exposed in user visible tables yet. 270 */ 271 ulonglong m_broadcast_count; 272 #endif 273 aggregatePFS_cond_stat274 inline void aggregate(const PFS_cond_stat *stat) 275 { 276 m_wait_stat.aggregate(&stat->m_wait_stat); 277 #ifdef PFS_LATER 278 m_signal_count+= stat->m_signal_count; 279 m_broadcast_count+= stat->m_broadcast_count; 280 #endif 281 } 282 resetPFS_cond_stat283 inline void reset(void) 284 { 285 m_wait_stat.reset(); 286 #ifdef PFS_LATER 287 m_signal_count= 0; 288 m_broadcast_count= 0; 289 #endif 290 } 291 }; 292 293 /** Statistics for FILE IO. Used for both waits and byte counts. */ 294 struct PFS_file_io_stat 295 { 296 /** READ statistics */ 297 PFS_byte_stat m_read; 298 /** WRITE statistics */ 299 PFS_byte_stat m_write; 300 /** Miscellaneous statistics */ 301 PFS_byte_stat m_misc; 302 resetPFS_file_io_stat303 inline void reset(void) 304 { 305 m_read.reset(); 306 m_write.reset(); 307 m_misc.reset(); 308 } 309 aggregatePFS_file_io_stat310 inline void aggregate(const PFS_file_io_stat *stat) 311 { 312 m_read.aggregate(&stat->m_read); 313 m_write.aggregate(&stat->m_write); 314 m_misc.aggregate(&stat->m_misc); 315 } 316 317 /* Sum waits and byte counts */ sumPFS_file_io_stat318 inline void sum(PFS_byte_stat *stat) 319 { 320 stat->aggregate(&m_read); 321 stat->aggregate(&m_write); 322 stat->aggregate(&m_misc); 323 } 324 325 /* Sum waits only */ sum_waitsPFS_file_io_stat326 inline void sum_waits(PFS_single_stat *stat) 327 { 328 stat->aggregate(&m_read); 329 stat->aggregate(&m_write); 330 stat->aggregate(&m_misc); 331 } 332 }; 333 334 /** Statistics for FILE usage. */ 335 struct PFS_file_stat 336 { 337 /** Number of current open handles. */ 338 ulong m_open_count; 339 /** File IO statistics. */ 340 PFS_file_io_stat m_io_stat; 341 aggregatePFS_file_stat342 inline void aggregate(const PFS_file_stat *stat) 343 { 344 m_io_stat.aggregate(&stat->m_io_stat); 345 } 346 347 /** Reset file statistics. */ resetPFS_file_stat348 inline void reset(void) 349 { 350 m_io_stat.reset(); 351 } 352 }; 353 354 /** Statistics for stage usage. */ 355 struct PFS_stage_stat 356 { 357 PFS_single_stat m_timer1_stat; 358 resetPFS_stage_stat359 inline void reset(void) 360 { m_timer1_stat.reset(); } 361 aggregate_countedPFS_stage_stat362 inline void aggregate_counted() 363 { m_timer1_stat.aggregate_counted(); } 364 aggregate_valuePFS_stage_stat365 inline void aggregate_value(ulonglong value) 366 { m_timer1_stat.aggregate_value(value); } 367 aggregatePFS_stage_stat368 inline void aggregate(const PFS_stage_stat *stat) 369 { m_timer1_stat.aggregate(& stat->m_timer1_stat); } 370 }; 371 372 /** Statistics for stored program usage. */ 373 struct PFS_sp_stat 374 { 375 PFS_single_stat m_timer1_stat; 376 resetPFS_sp_stat377 inline void reset(void) 378 { m_timer1_stat.reset(); } 379 aggregate_countedPFS_sp_stat380 inline void aggregate_counted() 381 { m_timer1_stat.aggregate_counted(); } 382 aggregate_valuePFS_sp_stat383 inline void aggregate_value(ulonglong value) 384 { m_timer1_stat.aggregate_value(value); } 385 aggregatePFS_sp_stat386 inline void aggregate(const PFS_stage_stat *stat) 387 { m_timer1_stat.aggregate(& stat->m_timer1_stat); } 388 }; 389 390 /** Statistics for prepared statement usage. */ 391 struct PFS_prepared_stmt_stat 392 { 393 PFS_single_stat m_timer1_stat; 394 resetPFS_prepared_stmt_stat395 inline void reset(void) 396 { m_timer1_stat.reset(); } 397 aggregate_countedPFS_prepared_stmt_stat398 inline void aggregate_counted() 399 { m_timer1_stat.aggregate_counted(); } 400 aggregate_valuePFS_prepared_stmt_stat401 inline void aggregate_value(ulonglong value) 402 { m_timer1_stat.aggregate_value(value); } 403 aggregatePFS_prepared_stmt_stat404 inline void aggregate(PFS_stage_stat *stat) 405 { m_timer1_stat.aggregate(& stat->m_timer1_stat); } 406 }; 407 408 /** 409 Statistics for statement usage. 410 This structure uses lazy initialization, 411 controlled by member @c m_timer1_stat.m_count. 412 */ 413 struct PFS_statement_stat 414 { 415 PFS_single_stat m_timer1_stat; 416 ulonglong m_error_count; 417 ulonglong m_warning_count; 418 ulonglong m_rows_affected; 419 ulonglong m_lock_time; 420 ulonglong m_rows_sent; 421 ulonglong m_rows_examined; 422 ulonglong m_created_tmp_disk_tables; 423 ulonglong m_created_tmp_tables; 424 ulonglong m_select_full_join; 425 ulonglong m_select_full_range_join; 426 ulonglong m_select_range; 427 ulonglong m_select_range_check; 428 ulonglong m_select_scan; 429 ulonglong m_sort_merge_passes; 430 ulonglong m_sort_range; 431 ulonglong m_sort_rows; 432 ulonglong m_sort_scan; 433 ulonglong m_no_index_used; 434 ulonglong m_no_good_index_used; 435 PFS_statement_statPFS_statement_stat436 PFS_statement_stat() 437 { 438 reset(); 439 } 440 resetPFS_statement_stat441 inline void reset() 442 { 443 m_timer1_stat.m_count= 0; 444 } 445 mark_usedPFS_statement_stat446 inline void mark_used() 447 { 448 delayed_reset(); 449 } 450 451 private: delayed_resetPFS_statement_stat452 inline void delayed_reset(void) 453 { 454 if (m_timer1_stat.m_count == 0) 455 { 456 m_timer1_stat.reset(); 457 m_error_count= 0; 458 m_warning_count= 0; 459 m_rows_affected= 0; 460 m_lock_time= 0; 461 m_rows_sent= 0; 462 m_rows_examined= 0; 463 m_created_tmp_disk_tables= 0; 464 m_created_tmp_tables= 0; 465 m_select_full_join= 0; 466 m_select_full_range_join= 0; 467 m_select_range= 0; 468 m_select_range_check= 0; 469 m_select_scan= 0; 470 m_sort_merge_passes= 0; 471 m_sort_range= 0; 472 m_sort_rows= 0; 473 m_sort_scan= 0; 474 m_no_index_used= 0; 475 m_no_good_index_used= 0; 476 } 477 } 478 479 public: aggregate_countedPFS_statement_stat480 inline void aggregate_counted() 481 { 482 delayed_reset(); 483 m_timer1_stat.aggregate_counted(); 484 } 485 aggregate_valuePFS_statement_stat486 inline void aggregate_value(ulonglong value) 487 { 488 delayed_reset(); 489 m_timer1_stat.aggregate_value(value); 490 } 491 aggregatePFS_statement_stat492 inline void aggregate(const PFS_statement_stat *stat) 493 { 494 if (stat->m_timer1_stat.m_count != 0) 495 { 496 delayed_reset(); 497 m_timer1_stat.aggregate_no_check(& stat->m_timer1_stat); 498 499 m_error_count+= stat->m_error_count; 500 m_warning_count+= stat->m_warning_count; 501 m_rows_affected+= stat->m_rows_affected; 502 m_lock_time+= stat->m_lock_time; 503 m_rows_sent+= stat->m_rows_sent; 504 m_rows_examined+= stat->m_rows_examined; 505 m_created_tmp_disk_tables+= stat->m_created_tmp_disk_tables; 506 m_created_tmp_tables+= stat->m_created_tmp_tables; 507 m_select_full_join+= stat->m_select_full_join; 508 m_select_full_range_join+= stat->m_select_full_range_join; 509 m_select_range+= stat->m_select_range; 510 m_select_range_check+= stat->m_select_range_check; 511 m_select_scan+= stat->m_select_scan; 512 m_sort_merge_passes+= stat->m_sort_merge_passes; 513 m_sort_range+= stat->m_sort_range; 514 m_sort_rows+= stat->m_sort_rows; 515 m_sort_scan+= stat->m_sort_scan; 516 m_no_index_used+= stat->m_no_index_used; 517 m_no_good_index_used+= stat->m_no_good_index_used; 518 } 519 } 520 }; 521 522 /** Statistics for transaction usage. */ 523 struct PFS_transaction_stat 524 { 525 PFS_single_stat m_read_write_stat; 526 PFS_single_stat m_read_only_stat; 527 528 ulonglong m_savepoint_count; 529 ulonglong m_rollback_to_savepoint_count; 530 ulonglong m_release_savepoint_count; 531 PFS_transaction_statPFS_transaction_stat532 PFS_transaction_stat() 533 { 534 m_savepoint_count= 0; 535 m_rollback_to_savepoint_count= 0; 536 m_release_savepoint_count= 0; 537 } 538 countPFS_transaction_stat539 ulonglong count(void) 540 { 541 return (m_read_write_stat.m_count + m_read_only_stat.m_count); 542 } 543 resetPFS_transaction_stat544 inline void reset(void) 545 { 546 m_read_write_stat.reset(); 547 m_read_only_stat.reset(); 548 m_savepoint_count= 0; 549 m_rollback_to_savepoint_count= 0; 550 m_release_savepoint_count= 0; 551 } 552 aggregatePFS_transaction_stat553 inline void aggregate(const PFS_transaction_stat *stat) 554 { 555 m_read_write_stat.aggregate(&stat->m_read_write_stat); 556 m_read_only_stat.aggregate(&stat->m_read_only_stat); 557 m_savepoint_count+= stat->m_savepoint_count; 558 m_rollback_to_savepoint_count+= stat->m_rollback_to_savepoint_count; 559 m_release_savepoint_count+= stat->m_release_savepoint_count; 560 } 561 }; 562 563 /** Single table io statistic. */ 564 struct PFS_table_io_stat 565 { 566 bool m_has_data; 567 /** FETCH statistics */ 568 PFS_single_stat m_fetch; 569 /** INSERT statistics */ 570 PFS_single_stat m_insert; 571 /** UPDATE statistics */ 572 PFS_single_stat m_update; 573 /** DELETE statistics */ 574 PFS_single_stat m_delete; 575 PFS_table_io_statPFS_table_io_stat576 PFS_table_io_stat() 577 { 578 m_has_data= false; 579 } 580 resetPFS_table_io_stat581 inline void reset(void) 582 { 583 m_has_data= false; 584 m_fetch.reset(); 585 m_insert.reset(); 586 m_update.reset(); 587 m_delete.reset(); 588 } 589 aggregatePFS_table_io_stat590 inline void aggregate(const PFS_table_io_stat *stat) 591 { 592 if (stat->m_has_data) 593 { 594 m_has_data= true; 595 m_fetch.aggregate(&stat->m_fetch); 596 m_insert.aggregate(&stat->m_insert); 597 m_update.aggregate(&stat->m_update); 598 m_delete.aggregate(&stat->m_delete); 599 } 600 } 601 sumPFS_table_io_stat602 inline void sum(PFS_single_stat *result) 603 { 604 if (m_has_data) 605 { 606 result->aggregate(& m_fetch); 607 result->aggregate(& m_insert); 608 result->aggregate(& m_update); 609 result->aggregate(& m_delete); 610 } 611 } 612 }; 613 614 enum PFS_TL_LOCK_TYPE 615 { 616 /* Locks from enum thr_lock */ 617 PFS_TL_READ= 0, 618 PFS_TL_READ_WITH_SHARED_LOCKS= 1, 619 PFS_TL_READ_HIGH_PRIORITY= 2, 620 PFS_TL_READ_NO_INSERT= 3, 621 PFS_TL_WRITE_ALLOW_WRITE= 4, 622 PFS_TL_WRITE_CONCURRENT_INSERT= 5, 623 PFS_TL_WRITE_LOW_PRIORITY= 6, 624 PFS_TL_WRITE= 7, 625 626 /* Locks for handler::ha_external_lock() */ 627 PFS_TL_READ_EXTERNAL= 8, 628 PFS_TL_WRITE_EXTERNAL= 9, 629 630 PFS_TL_NONE= 99 631 }; 632 633 #define COUNT_PFS_TL_LOCK_TYPE 10 634 635 /** Statistics for table locks. */ 636 struct PFS_table_lock_stat 637 { 638 PFS_single_stat m_stat[COUNT_PFS_TL_LOCK_TYPE]; 639 resetPFS_table_lock_stat640 inline void reset(void) 641 { 642 PFS_single_stat *pfs= & m_stat[0]; 643 PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE]; 644 for ( ; pfs < pfs_last ; pfs++) 645 pfs->reset(); 646 } 647 aggregatePFS_table_lock_stat648 inline void aggregate(const PFS_table_lock_stat *stat) 649 { 650 PFS_single_stat *pfs= & m_stat[0]; 651 PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE]; 652 const PFS_single_stat *pfs_from= & stat->m_stat[0]; 653 for ( ; pfs < pfs_last ; pfs++, pfs_from++) 654 pfs->aggregate(pfs_from); 655 } 656 sumPFS_table_lock_stat657 inline void sum(PFS_single_stat *result) 658 { 659 PFS_single_stat *pfs= & m_stat[0]; 660 PFS_single_stat *pfs_last= & m_stat[COUNT_PFS_TL_LOCK_TYPE]; 661 for ( ; pfs < pfs_last ; pfs++) 662 result->aggregate(pfs); 663 } 664 }; 665 666 /** Statistics for TABLE usage. */ 667 struct PFS_table_stat 668 { 669 /** 670 Statistics, per index. 671 Each index stat is in [0, MAX_INDEXES-1], 672 stats when using no index are in [MAX_INDEXES]. 673 */ 674 PFS_table_io_stat m_index_stat[MAX_INDEXES + 1]; 675 676 /** 677 Statistics, per lock type. 678 */ 679 PFS_table_lock_stat m_lock_stat; 680 681 /** Reset table io statistic. */ reset_ioPFS_table_stat682 inline void reset_io(void) 683 { 684 PFS_table_io_stat *stat= & m_index_stat[0]; 685 PFS_table_io_stat *stat_last= & m_index_stat[MAX_INDEXES + 1]; 686 for ( ; stat < stat_last ; stat++) 687 stat->reset(); 688 } 689 690 /** Reset table lock statistic. */ reset_lockPFS_table_stat691 inline void reset_lock(void) 692 { 693 m_lock_stat.reset(); 694 } 695 696 /** Reset table statistic. */ resetPFS_table_stat697 inline void reset(void) 698 { 699 reset_io(); 700 reset_lock(); 701 } 702 fast_reset_ioPFS_table_stat703 inline void fast_reset_io(void) 704 { 705 memcpy(& m_index_stat, & g_reset_template.m_index_stat, sizeof(m_index_stat)); 706 } 707 fast_reset_lockPFS_table_stat708 inline void fast_reset_lock(void) 709 { 710 memcpy(& m_lock_stat, & g_reset_template.m_lock_stat, sizeof(m_lock_stat)); 711 } 712 fast_resetPFS_table_stat713 inline void fast_reset(void) 714 { 715 memcpy(this, & g_reset_template, sizeof(*this)); 716 } 717 aggregate_ioPFS_table_stat718 inline void aggregate_io(const PFS_table_stat *stat, uint key_count) 719 { 720 PFS_table_io_stat *to_stat; 721 PFS_table_io_stat *to_stat_last; 722 const PFS_table_io_stat *from_stat; 723 724 assert(key_count <= MAX_INDEXES); 725 726 /* Aggregate stats for each index, if any */ 727 to_stat= & m_index_stat[0]; 728 to_stat_last= to_stat + key_count; 729 from_stat= & stat->m_index_stat[0]; 730 for ( ; to_stat < to_stat_last ; from_stat++, to_stat++) 731 to_stat->aggregate(from_stat); 732 733 /* Aggregate stats for the table */ 734 to_stat= & m_index_stat[MAX_INDEXES]; 735 from_stat= & stat->m_index_stat[MAX_INDEXES]; 736 to_stat->aggregate(from_stat); 737 } 738 aggregate_lockPFS_table_stat739 inline void aggregate_lock(const PFS_table_stat *stat) 740 { 741 m_lock_stat.aggregate(& stat->m_lock_stat); 742 } 743 aggregatePFS_table_stat744 inline void aggregate(const PFS_table_stat *stat, uint key_count) 745 { 746 aggregate_io(stat, key_count); 747 aggregate_lock(stat); 748 } 749 sum_ioPFS_table_stat750 inline void sum_io(PFS_single_stat *result, uint key_count) 751 { 752 PFS_table_io_stat *stat; 753 PFS_table_io_stat *stat_last; 754 755 assert(key_count <= MAX_INDEXES); 756 757 /* Sum stats for each index, if any */ 758 stat= & m_index_stat[0]; 759 stat_last= stat + key_count; 760 for ( ; stat < stat_last ; stat++) 761 stat->sum(result); 762 763 /* Sum stats for the table */ 764 m_index_stat[MAX_INDEXES].sum(result); 765 } 766 sum_lockPFS_table_stat767 inline void sum_lock(PFS_single_stat *result) 768 { 769 m_lock_stat.sum(result); 770 } 771 sumPFS_table_stat772 inline void sum(PFS_single_stat *result, uint key_count) 773 { 774 sum_io(result, key_count); 775 sum_lock(result); 776 } 777 778 static struct PFS_table_stat g_reset_template; 779 }; 780 781 /** Statistics for SOCKET IO. Used for both waits and byte counts. */ 782 struct PFS_socket_io_stat 783 { 784 /** READ statistics */ 785 PFS_byte_stat m_read; 786 /** WRITE statistics */ 787 PFS_byte_stat m_write; 788 /** Miscellaneous statistics */ 789 PFS_byte_stat m_misc; 790 resetPFS_socket_io_stat791 inline void reset(void) 792 { 793 m_read.reset(); 794 m_write.reset(); 795 m_misc.reset(); 796 } 797 aggregatePFS_socket_io_stat798 inline void aggregate(const PFS_socket_io_stat *stat) 799 { 800 m_read.aggregate(&stat->m_read); 801 m_write.aggregate(&stat->m_write); 802 m_misc.aggregate(&stat->m_misc); 803 } 804 805 /* Sum waits and byte counts */ sumPFS_socket_io_stat806 inline void sum(PFS_byte_stat *stat) 807 { 808 stat->aggregate(&m_read); 809 stat->aggregate(&m_write); 810 stat->aggregate(&m_misc); 811 } 812 813 /* Sum waits only */ sum_waitsPFS_socket_io_stat814 inline void sum_waits(PFS_single_stat *stat) 815 { 816 stat->aggregate(&m_read); 817 stat->aggregate(&m_write); 818 stat->aggregate(&m_misc); 819 } 820 }; 821 822 /** Statistics for SOCKET usage. */ 823 struct PFS_socket_stat 824 { 825 /** Socket timing and byte count statistics per operation */ 826 PFS_socket_io_stat m_io_stat; 827 828 /** Reset socket statistics. */ resetPFS_socket_stat829 inline void reset(void) 830 { 831 m_io_stat.reset(); 832 } 833 }; 834 835 struct PFS_memory_stat_delta 836 { 837 size_t m_alloc_count_delta; 838 size_t m_free_count_delta; 839 size_t m_alloc_size_delta; 840 size_t m_free_size_delta; 841 resetPFS_memory_stat_delta842 void reset() 843 { 844 m_alloc_count_delta= 0; 845 m_free_count_delta= 0; 846 m_alloc_size_delta= 0; 847 m_free_size_delta= 0; 848 } 849 }; 850 851 /** 852 Memory statistics. 853 Conceptually, the following statistics are maintained: 854 - CURRENT_COUNT_USED, 855 - LOW_COUNT_USED, 856 - HIGH_COUNT_USED 857 - CURRENT_SIZE_USED, 858 - LOW_SIZE_USED, 859 - HIGH_SIZE_USED 860 Now, the implementation keeps different counters, 861 which are easier (less overhead) to maintain while 862 collecting statistics. 863 Invariants are as follows: 864 CURRENT_COUNT_USED = @c m_alloc_count - @c m_free_count 865 LOW_COUNT_USED + @c m_free_count_capacity = CURRENT_COUNT_USED 866 CURRENT_COUNT_USED + @c m_alloc_count_capacity = HIGH_COUNT_USED 867 CURRENT_SIZE_USED = @c m_alloc_size - @c m_free_size 868 LOW_SIZE_USED + @c m_free_size_capacity = CURRENT_SIZE_USED 869 CURRENT_SIZE_USED + @c m_alloc_size_capacity = HIGH_SIZE_USED 870 871 */ 872 struct PFS_memory_stat 873 { 874 bool m_used; 875 size_t m_alloc_count; 876 size_t m_free_count; 877 size_t m_alloc_size; 878 size_t m_free_size; 879 880 size_t m_alloc_count_capacity; 881 size_t m_free_count_capacity; 882 size_t m_alloc_size_capacity; 883 size_t m_free_size_capacity; 884 resetPFS_memory_stat885 inline void reset(void) 886 { 887 m_used= false; 888 m_alloc_count= 0; 889 m_free_count= 0; 890 m_alloc_size= 0; 891 m_free_size= 0; 892 893 m_alloc_count_capacity= 0; 894 m_free_count_capacity= 0; 895 m_alloc_size_capacity= 0; 896 m_free_size_capacity= 0; 897 } 898 rebasePFS_memory_stat899 inline void rebase(void) 900 { 901 if (! m_used) 902 return; 903 904 size_t base; 905 906 base= std::min<size_t>(m_alloc_count, m_free_count); 907 m_alloc_count-= base; 908 m_free_count-= base; 909 910 base= std::min<size_t>(m_alloc_size, m_free_size); 911 m_alloc_size-= base; 912 m_free_size-= base; 913 914 m_alloc_count_capacity= 0; 915 m_free_count_capacity= 0; 916 m_alloc_size_capacity= 0; 917 m_free_size_capacity= 0; 918 } 919 partial_aggregate_toPFS_memory_stat920 inline void partial_aggregate_to(PFS_memory_stat *stat) 921 { 922 if (! m_used) 923 return; 924 925 size_t base; 926 927 stat->m_used= true; 928 929 base= std::min<size_t>(m_alloc_count, m_free_count); 930 if (base != 0) 931 { 932 stat->m_alloc_count+= base; 933 stat->m_free_count+= base; 934 m_alloc_count-= base; 935 m_free_count-= base; 936 } 937 938 base= std::min<size_t>(m_alloc_size, m_free_size); 939 if (base != 0) 940 { 941 stat->m_alloc_size+= base; 942 stat->m_free_size+= base; 943 m_alloc_size-= base; 944 m_free_size-= base; 945 } 946 947 stat->m_alloc_count_capacity+= m_alloc_count_capacity; 948 stat->m_free_count_capacity+= m_free_count_capacity; 949 stat->m_alloc_size_capacity+= m_alloc_size_capacity; 950 stat->m_free_size_capacity+= m_free_size_capacity; 951 952 m_alloc_count_capacity= 0; 953 m_free_count_capacity= 0; 954 m_alloc_size_capacity= 0; 955 m_free_size_capacity= 0; 956 } 957 full_aggregate_toPFS_memory_stat958 inline void full_aggregate_to(PFS_memory_stat *stat) const 959 { 960 if (! m_used) 961 return; 962 963 stat->m_used= true; 964 965 stat->m_alloc_count+= m_alloc_count; 966 stat->m_free_count+= m_free_count; 967 stat->m_alloc_size+= m_alloc_size; 968 stat->m_free_size+= m_free_size; 969 970 stat->m_alloc_count_capacity+= m_alloc_count_capacity; 971 stat->m_free_count_capacity+= m_free_count_capacity; 972 stat->m_alloc_size_capacity+= m_alloc_size_capacity; 973 stat->m_free_size_capacity+= m_free_size_capacity; 974 } 975 partial_aggregate_toPFS_memory_stat976 inline void partial_aggregate_to(PFS_memory_stat *stat1, PFS_memory_stat *stat2) 977 { 978 if (! m_used) 979 return; 980 981 size_t base; 982 983 stat1->m_used= true; 984 stat2->m_used= true; 985 986 base= std::min<size_t>(m_alloc_count, m_free_count); 987 if (base != 0) 988 { 989 stat1->m_alloc_count+= base; 990 stat2->m_alloc_count+= base; 991 stat1->m_free_count+= base; 992 stat2->m_free_count+= base; 993 m_alloc_count-= base; 994 m_free_count-= base; 995 } 996 997 base= std::min<size_t>(m_alloc_size, m_free_size); 998 if (base != 0) 999 { 1000 stat1->m_alloc_size+= base; 1001 stat2->m_alloc_size+= base; 1002 stat1->m_free_size+= base; 1003 stat2->m_free_size+= base; 1004 m_alloc_size-= base; 1005 m_free_size-= base; 1006 } 1007 1008 stat1->m_alloc_count_capacity+= m_alloc_count_capacity; 1009 stat2->m_alloc_count_capacity+= m_alloc_count_capacity; 1010 stat1->m_free_count_capacity+= m_free_count_capacity; 1011 stat2->m_free_count_capacity+= m_free_count_capacity; 1012 stat1->m_alloc_size_capacity+= m_alloc_size_capacity; 1013 stat2->m_alloc_size_capacity+= m_alloc_size_capacity; 1014 stat1->m_free_size_capacity+= m_free_size_capacity; 1015 stat2->m_free_size_capacity+= m_free_size_capacity; 1016 1017 m_alloc_count_capacity= 0; 1018 m_free_count_capacity= 0; 1019 m_alloc_size_capacity= 0; 1020 m_free_size_capacity= 0; 1021 } 1022 full_aggregate_toPFS_memory_stat1023 inline void full_aggregate_to(PFS_memory_stat *stat1, PFS_memory_stat *stat2) const 1024 { 1025 if (! m_used) 1026 return; 1027 1028 stat1->m_used= true; 1029 stat2->m_used= true; 1030 1031 stat1->m_alloc_count+= m_alloc_count; 1032 stat2->m_alloc_count+= m_alloc_count; 1033 stat1->m_free_count+= m_free_count; 1034 stat2->m_free_count+= m_free_count; 1035 stat1->m_alloc_size+= m_alloc_size; 1036 stat2->m_alloc_size+= m_alloc_size; 1037 stat1->m_free_size+= m_free_size; 1038 stat2->m_free_size+= m_free_size; 1039 1040 stat1->m_alloc_count_capacity+= m_alloc_count_capacity; 1041 stat2->m_alloc_count_capacity+= m_alloc_count_capacity; 1042 stat1->m_free_count_capacity+= m_free_count_capacity; 1043 stat2->m_free_count_capacity+= m_free_count_capacity; 1044 stat1->m_alloc_size_capacity+= m_alloc_size_capacity; 1045 stat2->m_alloc_size_capacity+= m_alloc_size_capacity; 1046 stat1->m_free_size_capacity+= m_free_size_capacity; 1047 stat2->m_free_size_capacity+= m_free_size_capacity; 1048 } 1049 count_builtin_allocPFS_memory_stat1050 void count_builtin_alloc(size_t size) 1051 { 1052 m_used= true; 1053 1054 m_alloc_count++; 1055 m_free_count_capacity++; 1056 m_alloc_size+= size; 1057 m_free_size_capacity+= size; 1058 1059 if (m_alloc_count_capacity >= 1) 1060 { 1061 m_alloc_count_capacity--; 1062 } 1063 1064 if (m_alloc_size_capacity >= size) 1065 { 1066 m_alloc_size_capacity-= size; 1067 } 1068 1069 return; 1070 } 1071 count_builtin_freePFS_memory_stat1072 void count_builtin_free(size_t size) 1073 { 1074 m_used= true; 1075 1076 m_free_count++; 1077 m_alloc_count_capacity++; 1078 m_free_size+= size; 1079 m_alloc_size_capacity+= size; 1080 1081 if (m_free_count_capacity >= 1) 1082 { 1083 m_free_count_capacity--; 1084 } 1085 1086 if (m_free_size_capacity >= size) 1087 { 1088 m_free_size_capacity-= size; 1089 } 1090 1091 return; 1092 } 1093 count_allocPFS_memory_stat1094 inline PFS_memory_stat_delta *count_alloc(size_t size, 1095 PFS_memory_stat_delta *delta) 1096 { 1097 m_used= true; 1098 1099 m_alloc_count++; 1100 m_free_count_capacity++; 1101 m_alloc_size+= size; 1102 m_free_size_capacity+= size; 1103 1104 if ((m_alloc_count_capacity >= 1) && 1105 (m_alloc_size_capacity >= size)) 1106 { 1107 m_alloc_count_capacity--; 1108 m_alloc_size_capacity-= size; 1109 return NULL; 1110 } 1111 1112 delta->reset(); 1113 1114 if (m_alloc_count_capacity >= 1) 1115 { 1116 m_alloc_count_capacity--; 1117 } 1118 else 1119 { 1120 delta->m_alloc_count_delta= 1; 1121 } 1122 1123 if (m_alloc_size_capacity >= size) 1124 { 1125 m_alloc_size_capacity-= size; 1126 } 1127 else 1128 { 1129 delta->m_alloc_size_delta= size - m_alloc_size_capacity; 1130 m_alloc_size_capacity= 0; 1131 } 1132 1133 return delta; 1134 } 1135 count_reallocPFS_memory_stat1136 inline PFS_memory_stat_delta *count_realloc(size_t old_size, size_t new_size, 1137 PFS_memory_stat_delta *delta) 1138 { 1139 m_used= true; 1140 1141 size_t size_delta= new_size - old_size; 1142 m_alloc_count++; 1143 m_alloc_size+= new_size; 1144 m_free_count++; 1145 m_free_size+= old_size; 1146 1147 if (new_size == old_size) 1148 { 1149 return NULL; 1150 } 1151 1152 if (new_size > old_size) 1153 { 1154 /* Growing */ 1155 size_delta= new_size - old_size; 1156 m_free_size_capacity+= size_delta; 1157 1158 if (m_alloc_size_capacity >= size_delta) 1159 { 1160 m_alloc_size_capacity-= size_delta; 1161 return NULL; 1162 } 1163 1164 delta->reset(); 1165 delta->m_alloc_size_delta= size_delta - m_alloc_size_capacity; 1166 m_alloc_size_capacity= 0; 1167 } 1168 else 1169 { 1170 /* Shrinking */ 1171 size_delta= old_size - new_size; 1172 m_alloc_size_capacity+= size_delta; 1173 1174 if (m_free_size_capacity >= size_delta) 1175 { 1176 m_free_size_capacity-= size_delta; 1177 return NULL; 1178 } 1179 1180 delta->reset(); 1181 delta->m_free_size_delta= size_delta - m_free_size_capacity; 1182 m_free_size_capacity= 0; 1183 } 1184 1185 return delta; 1186 } 1187 count_freePFS_memory_stat1188 inline PFS_memory_stat_delta *count_free(size_t size, PFS_memory_stat_delta *delta) 1189 { 1190 m_used= true; 1191 1192 m_free_count++; 1193 m_alloc_count_capacity++; 1194 m_free_size+= size; 1195 m_alloc_size_capacity+= size; 1196 1197 if ((m_free_count_capacity >= 1) && 1198 (m_free_size_capacity >= size)) 1199 { 1200 m_free_count_capacity--; 1201 m_free_size_capacity-= size; 1202 return NULL; 1203 } 1204 1205 delta->reset(); 1206 1207 if (m_free_count_capacity >= 1) 1208 { 1209 m_free_count_capacity--; 1210 } 1211 else 1212 { 1213 delta->m_free_count_delta= 1; 1214 } 1215 1216 if (m_free_size_capacity >= size) 1217 { 1218 m_free_size_capacity-= size; 1219 } 1220 else 1221 { 1222 delta->m_free_size_delta= size - m_free_size_capacity; 1223 m_free_size_capacity= 0; 1224 } 1225 1226 return delta; 1227 } 1228 apply_deltaPFS_memory_stat1229 inline PFS_memory_stat_delta *apply_delta(const PFS_memory_stat_delta *delta, 1230 PFS_memory_stat_delta *delta_buffer) 1231 { 1232 size_t val; 1233 size_t remaining_alloc_count; 1234 size_t remaining_alloc_size; 1235 size_t remaining_free_count; 1236 size_t remaining_free_size; 1237 bool has_remaining= false; 1238 1239 m_used= true; 1240 1241 val= delta->m_alloc_count_delta; 1242 if (val <= m_alloc_count_capacity) 1243 { 1244 m_alloc_count_capacity-= val; 1245 remaining_alloc_count= 0; 1246 } 1247 else 1248 { 1249 remaining_alloc_count= val - m_alloc_count_capacity; 1250 m_alloc_count_capacity= 0; 1251 has_remaining= true; 1252 } 1253 1254 val= delta->m_alloc_size_delta; 1255 if (val <= m_alloc_size_capacity) 1256 { 1257 m_alloc_size_capacity-= val; 1258 remaining_alloc_size= 0; 1259 } 1260 else 1261 { 1262 remaining_alloc_size= val - m_alloc_size_capacity; 1263 m_alloc_size_capacity= 0; 1264 has_remaining= true; 1265 } 1266 1267 val= delta->m_free_count_delta; 1268 if (val <= m_free_count_capacity) 1269 { 1270 m_free_count_capacity-= val; 1271 remaining_free_count= 0; 1272 } 1273 else 1274 { 1275 remaining_free_count= val - m_free_count_capacity; 1276 m_free_count_capacity= 0; 1277 has_remaining= true; 1278 } 1279 1280 val= delta->m_free_size_delta; 1281 if (val <= m_free_size_capacity) 1282 { 1283 m_free_size_capacity-= val; 1284 remaining_free_size= 0; 1285 } 1286 else 1287 { 1288 remaining_free_size= val - m_free_size_capacity; 1289 m_free_size_capacity= 0; 1290 has_remaining= true; 1291 } 1292 1293 if (! has_remaining) 1294 return NULL; 1295 1296 delta_buffer->m_alloc_count_delta= remaining_alloc_count; 1297 delta_buffer->m_alloc_size_delta= remaining_alloc_size; 1298 delta_buffer->m_free_count_delta= remaining_free_count; 1299 delta_buffer->m_free_size_delta= remaining_free_size; 1300 return delta_buffer; 1301 } 1302 }; 1303 1304 #define PFS_MEMORY_STAT_INITIALIZER { false, 0, 0, 0, 0, 0, 0, 0, 0} 1305 1306 /** Connections statistics. */ 1307 struct PFS_connection_stat 1308 { PFS_connection_statPFS_connection_stat1309 PFS_connection_stat() 1310 : m_current_connections(0), 1311 m_total_connections(0) 1312 {} 1313 1314 ulonglong m_current_connections; 1315 ulonglong m_total_connections; 1316 aggregate_activePFS_connection_stat1317 inline void aggregate_active(ulonglong active) 1318 { 1319 m_current_connections+= active; 1320 m_total_connections+= active; 1321 } 1322 aggregate_disconnectedPFS_connection_stat1323 inline void aggregate_disconnected(ulonglong disconnected) 1324 { 1325 m_total_connections+= disconnected; 1326 } 1327 }; 1328 1329 /** @} */ 1330 #endif 1331 1332