mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
Bug#52502 Performance schema does not start with large mutex_instance buffers
Backport from mysql-next-mr (5.6) to mysql-trunk (5.5)
This commit is contained in:
parent
36e80ced63
commit
e04de9783a
3 changed files with 202 additions and 79 deletions
|
@ -31,27 +31,50 @@ void pfs_free(void *ptr);
|
|||
|
||||
inline uint randomized_index(const void *ptr, uint max_size)
|
||||
{
|
||||
static uint seed1= 0;
|
||||
static uint seed2= 0;
|
||||
uint result;
|
||||
register intptr value;
|
||||
|
||||
if (unlikely(max_size == 0))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
ptr is typically an aligned structure,
|
||||
so the last bits are not really random, but this has no effect.
|
||||
Apply a factor A*x to spread
|
||||
close values of ptr further apart (which helps with arrays),
|
||||
and to spread values way beyond a typical max_size.
|
||||
Then, apply a modulo to end within [0, max_size - 1].
|
||||
A is big prime numbers, to avoid resonating with max_size,
|
||||
to have a uniform distribution in [0, max_size - 1].
|
||||
The value of A is chosen so that index(ptr) and index(ptr + N) (for arrays)
|
||||
are likely to be not similar for typical values of max_size
|
||||
(50, 100, 1000, etc).
|
||||
In other words, (sizeof(T)*A % max_size) should not be a small number,
|
||||
to avoid that with 'T array[max_size]', index(array[i])
|
||||
and index(array[i + 1]) end up pointing in the same area in [0, max_size - 1].
|
||||
ptr is typically an aligned structure, and can be in an array.
|
||||
- The last bits are not random because of alignment,
|
||||
so we divide by 8.
|
||||
- The high bits are mostly constant, especially with 64 bits architectures,
|
||||
but we keep most of them anyway, by doing computation in intptr.
|
||||
The high bits are significant depending on where the data is
|
||||
stored (the data segment, the stack, the heap, ...).
|
||||
- To spread consecutive cells in an array further, we multiply by
|
||||
a factor A. This factor should not be too high, which would cause
|
||||
an overflow and cause loss of randomness (droping the top high bits).
|
||||
The factor is a prime number, to help spread the distribution.
|
||||
- To add more noise, and to be more robust if the calling code is
|
||||
passing a constant value instead of a random identity,
|
||||
we add the previous results, for hysteresys, with a degree 2 polynom,
|
||||
X^2 + X + 1.
|
||||
- Last, a modulo is applied to be within the [0, max_size - 1] range.
|
||||
Note that seed1 and seed2 are static, and are *not* thread safe,
|
||||
which is even better.
|
||||
Effect with arrays: T array[N]
|
||||
- ptr(i) = & array[i] = & array[0] + i * sizeof(T)
|
||||
- ptr(i+1) = ptr(i) + sizeof(T).
|
||||
What we want here, is to have index(i) and index(i+1) fall into
|
||||
very different areas in [0, max_size - 1], to avoid locality.
|
||||
*/
|
||||
return static_cast<uint>
|
||||
(((reinterpret_cast<intptr> (ptr)) * 2166179) % max_size);
|
||||
value= (reinterpret_cast<intptr> (ptr)) >> 3;
|
||||
value*= 1789;
|
||||
value+= seed2 + seed1 + 1;
|
||||
|
||||
result= (static_cast<uint> (value)) % max_size;
|
||||
|
||||
seed2= seed1*seed1;
|
||||
seed1= result;
|
||||
|
||||
DBUG_ASSERT(result < max_size);
|
||||
return result;
|
||||
}
|
||||
|
||||
void pfs_print_error(const char *format, ...);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2008-2009 Sun Microsystems, Inc
|
||||
/* Copyright (c) 2008, 2010 Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -10,8 +10,8 @@
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
||||
|
||||
/**
|
||||
@file storage/perfschema/pfs_instr.cc
|
||||
|
@ -21,8 +21,8 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "my_global.h"
|
||||
#include "sql_priv.h"
|
||||
#include "my_sys.h"
|
||||
#include "pfs.h"
|
||||
#include "pfs_stat.h"
|
||||
#include "pfs_instr.h"
|
||||
#include "pfs_global.h"
|
||||
|
@ -411,6 +411,8 @@ void cleanup_instruments(void)
|
|||
thread_instr_class_waits_array= NULL;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
|
||||
my_bool)
|
||||
{
|
||||
|
@ -425,6 +427,7 @@ static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
|
|||
result= file->m_filename;
|
||||
return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Initialize the file name hash.
|
||||
|
@ -451,6 +454,75 @@ void cleanup_file_hash(void)
|
|||
}
|
||||
}
|
||||
|
||||
void PFS_scan::init(uint random, uint max_size)
|
||||
{
|
||||
m_pass= 0;
|
||||
|
||||
if (max_size == 0)
|
||||
{
|
||||
/* Degenerated case, no buffer */
|
||||
m_pass_max= 0;
|
||||
return;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(random < max_size);
|
||||
|
||||
if (PFS_MAX_ALLOC_RETRY < max_size)
|
||||
{
|
||||
/*
|
||||
The buffer is big compared to PFS_MAX_ALLOC_RETRY,
|
||||
scan it only partially.
|
||||
*/
|
||||
if (random + PFS_MAX_ALLOC_RETRY < max_size)
|
||||
{
|
||||
/*
|
||||
Pass 1: [random, random + PFS_MAX_ALLOC_RETRY - 1]
|
||||
Pass 2: not used.
|
||||
*/
|
||||
m_pass_max= 1;
|
||||
m_first[0]= random;
|
||||
m_last[0]= random + PFS_MAX_ALLOC_RETRY;
|
||||
m_first[1]= 0;
|
||||
m_last[1]= 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Pass 1: [random, max_size - 1]
|
||||
Pass 2: [0, ...]
|
||||
The combined length of pass 1 and 2 is PFS_MAX_ALLOC_RETRY.
|
||||
*/
|
||||
m_pass_max= 2;
|
||||
m_first[0]= random;
|
||||
m_last[0]= max_size;
|
||||
m_first[1]= 0;
|
||||
m_last[1]= PFS_MAX_ALLOC_RETRY - (max_size - random);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
The buffer is small compared to PFS_MAX_ALLOC_RETRY,
|
||||
scan it in full in two passes.
|
||||
Pass 1: [random, max_size - 1]
|
||||
Pass 2: [0, random - 1]
|
||||
*/
|
||||
m_pass_max= 2;
|
||||
m_first[0]= random;
|
||||
m_last[0]= max_size;
|
||||
m_first[1]= 0;
|
||||
m_last[1]= random;
|
||||
}
|
||||
|
||||
DBUG_ASSERT(m_first[0] < max_size);
|
||||
DBUG_ASSERT(m_first[1] < max_size);
|
||||
DBUG_ASSERT(m_last[1] <= max_size);
|
||||
DBUG_ASSERT(m_last[1] <= max_size);
|
||||
/* The combined length of all passes should not exceed PFS_MAX_ALLOC_RETRY. */
|
||||
DBUG_ASSERT((m_last[0] - m_first[0]) +
|
||||
(m_last[1] - m_first[1]) <= PFS_MAX_ALLOC_RETRY);
|
||||
}
|
||||
|
||||
/**
|
||||
Create instrumentation for a mutex instance.
|
||||
@param klass the mutex class
|
||||
|
@ -459,17 +531,15 @@ void cleanup_file_hash(void)
|
|||
*/
|
||||
PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity)
|
||||
{
|
||||
int pass;
|
||||
uint i= randomized_index(identity, mutex_max);
|
||||
PFS_scan scan;
|
||||
uint random= randomized_index(identity, mutex_max);
|
||||
|
||||
/*
|
||||
Pass 1: [random, mutex_max - 1]
|
||||
Pass 2: [0, mutex_max - 1]
|
||||
*/
|
||||
for (pass= 1; pass <= 2; i=0, pass++)
|
||||
for (scan.init(random, mutex_max);
|
||||
scan.has_pass();
|
||||
scan.next_pass())
|
||||
{
|
||||
PFS_mutex *pfs= mutex_array + i;
|
||||
PFS_mutex *pfs_last= mutex_array + mutex_max;
|
||||
PFS_mutex *pfs= mutex_array + scan.first();
|
||||
PFS_mutex *pfs_last= mutex_array + scan.last();
|
||||
for ( ; pfs < pfs_last; pfs++)
|
||||
{
|
||||
if (pfs->m_lock.is_free())
|
||||
|
@ -517,17 +587,15 @@ void destroy_mutex(PFS_mutex *pfs)
|
|||
*/
|
||||
PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity)
|
||||
{
|
||||
int pass;
|
||||
uint i= randomized_index(identity, rwlock_max);
|
||||
PFS_scan scan;
|
||||
uint random= randomized_index(identity, rwlock_max);
|
||||
|
||||
/*
|
||||
Pass 1: [random, rwlock_max - 1]
|
||||
Pass 2: [0, rwlock_max - 1]
|
||||
*/
|
||||
for (pass= 1; pass <= 2; i=0, pass++)
|
||||
for (scan.init(random, rwlock_max);
|
||||
scan.has_pass();
|
||||
scan.next_pass())
|
||||
{
|
||||
PFS_rwlock *pfs= rwlock_array + i;
|
||||
PFS_rwlock *pfs_last= rwlock_array + rwlock_max;
|
||||
PFS_rwlock *pfs= rwlock_array + scan.first();
|
||||
PFS_rwlock *pfs_last= rwlock_array + scan.last();
|
||||
for ( ; pfs < pfs_last; pfs++)
|
||||
{
|
||||
if (pfs->m_lock.is_free())
|
||||
|
@ -581,17 +649,15 @@ void destroy_rwlock(PFS_rwlock *pfs)
|
|||
*/
|
||||
PFS_cond* create_cond(PFS_cond_class *klass, const void *identity)
|
||||
{
|
||||
int pass;
|
||||
uint i= randomized_index(identity, cond_max);
|
||||
PFS_scan scan;
|
||||
uint random= randomized_index(identity, cond_max);
|
||||
|
||||
/*
|
||||
Pass 1: [random, cond_max - 1]
|
||||
Pass 2: [0, cond_max - 1]
|
||||
*/
|
||||
for (pass= 1; pass <= 2; i=0, pass++)
|
||||
for (scan.init(random, cond_max);
|
||||
scan.has_pass();
|
||||
scan.next_pass())
|
||||
{
|
||||
PFS_cond *pfs= cond_array + i;
|
||||
PFS_cond *pfs_last= cond_array + cond_max;
|
||||
PFS_cond *pfs= cond_array + scan.first();
|
||||
PFS_cond *pfs_last= cond_array + scan.last();
|
||||
for ( ; pfs < pfs_last; pfs++)
|
||||
{
|
||||
if (pfs->m_lock.is_free())
|
||||
|
@ -639,17 +705,15 @@ void destroy_cond(PFS_cond *pfs)
|
|||
PFS_thread* create_thread(PFS_thread_class *klass, const void *identity,
|
||||
ulong thread_id)
|
||||
{
|
||||
int pass;
|
||||
uint i= randomized_index(identity, thread_max);
|
||||
PFS_scan scan;
|
||||
uint random= randomized_index(identity, thread_max);
|
||||
|
||||
/*
|
||||
Pass 1: [random, thread_max - 1]
|
||||
Pass 2: [0, thread_max - 1]
|
||||
*/
|
||||
for (pass= 1; pass <= 2; i=0, pass++)
|
||||
for (scan.init(random, thread_max);
|
||||
scan.has_pass();
|
||||
scan.next_pass())
|
||||
{
|
||||
PFS_thread *pfs= thread_array + i;
|
||||
PFS_thread *pfs_last= thread_array + thread_max;
|
||||
PFS_thread *pfs= thread_array + scan.first();
|
||||
PFS_thread *pfs_last= thread_array + scan.last();
|
||||
for ( ; pfs < pfs_last; pfs++)
|
||||
{
|
||||
if (pfs->m_lock.is_free())
|
||||
|
@ -733,7 +797,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
|
|||
const char *filename, uint len)
|
||||
{
|
||||
PFS_file *pfs;
|
||||
int pass;
|
||||
PFS_scan scan;
|
||||
|
||||
if (! filename_hash_inited)
|
||||
{
|
||||
|
@ -806,17 +870,14 @@ search:
|
|||
}
|
||||
|
||||
/* filename is not constant, just using it for noise on create */
|
||||
uint i= randomized_index(filename, file_max);
|
||||
uint random= randomized_index(filename, file_max);
|
||||
|
||||
/*
|
||||
Pass 1: [random, file_max - 1]
|
||||
Pass 2: [0, file_max - 1]
|
||||
*/
|
||||
for (pass= 1; pass <= 2; i=0, pass++)
|
||||
for (scan.init(random, file_max);
|
||||
scan.has_pass();
|
||||
scan.next_pass())
|
||||
{
|
||||
pfs= file_array + i;
|
||||
PFS_file *pfs_last= file_array + file_max;
|
||||
|
||||
pfs= file_array + scan.first();
|
||||
PFS_file *pfs_last= file_array + scan.last();
|
||||
for ( ; pfs < pfs_last; pfs++)
|
||||
{
|
||||
if (pfs->m_lock.is_free())
|
||||
|
@ -901,17 +962,15 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs)
|
|||
*/
|
||||
PFS_table* create_table(PFS_table_share *share, const void *identity)
|
||||
{
|
||||
int pass;
|
||||
uint i= randomized_index(identity, table_max);
|
||||
PFS_scan scan;
|
||||
uint random= randomized_index(identity, table_max);
|
||||
|
||||
/*
|
||||
Pass 1: [random, table_max - 1]
|
||||
Pass 2: [0, table_max - 1]
|
||||
*/
|
||||
for (pass= 1; pass <= 2; i=0, pass++)
|
||||
for (scan.init(random, table_max);
|
||||
scan.has_pass();
|
||||
scan.next_pass())
|
||||
{
|
||||
PFS_table *pfs= table_array + i;
|
||||
PFS_table *pfs_last= table_array + table_max;
|
||||
PFS_table *pfs= table_array + scan.first();
|
||||
PFS_table *pfs_last= table_array + scan.last();
|
||||
for ( ; pfs < pfs_last; pfs++)
|
||||
{
|
||||
if (pfs->m_lock.is_free())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2008-2009 Sun Microsystems, Inc
|
||||
/* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -10,8 +10,8 @@
|
|||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
along with this program; if not, write to the Free Software Foundation,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
|
||||
|
||||
#ifndef PFS_INSTR_H
|
||||
#define PFS_INSTR_H
|
||||
|
@ -21,7 +21,6 @@
|
|||
Performance schema instruments (declarations).
|
||||
*/
|
||||
|
||||
#include <sql_priv.h>
|
||||
#include "pfs_lock.h"
|
||||
#include "pfs_instr_class.h"
|
||||
#include "pfs_events_waits.h"
|
||||
|
@ -136,6 +135,48 @@ struct PFS_table : public PFS_instr
|
|||
*/
|
||||
#define LOCKER_STACK_SIZE 3
|
||||
|
||||
/**
|
||||
@def PFS_MAX_ALLOC_RETRY
|
||||
Maximum number of times the code attempts to allocate an item
|
||||
from internal buffers, before giving up.
|
||||
*/
|
||||
#define PFS_MAX_ALLOC_RETRY 1000
|
||||
|
||||
#define PFS_MAX_SCAN_PASS 2
|
||||
|
||||
/**
|
||||
Helper to scan circular buffers.
|
||||
Given a buffer of size [0, max_size - 1],
|
||||
and a random starting point in the buffer,
|
||||
this helper returns up to two [first, last -1] intervals that:
|
||||
- fit into the [0, max_size - 1] range,
|
||||
- have a maximum combined length of at most PFS_MAX_ALLOC_RETRY.
|
||||
*/
|
||||
struct PFS_scan
|
||||
{
|
||||
public:
|
||||
void init(uint random, uint max_size);
|
||||
|
||||
bool has_pass() const
|
||||
{ return (m_pass < m_pass_max); }
|
||||
|
||||
void next_pass()
|
||||
{ m_pass++; }
|
||||
|
||||
uint first() const
|
||||
{ return m_first[m_pass]; }
|
||||
|
||||
uint last() const
|
||||
{ return m_last[m_pass]; }
|
||||
|
||||
private:
|
||||
uint m_pass;
|
||||
uint m_pass_max;
|
||||
uint m_first[PFS_MAX_SCAN_PASS];
|
||||
uint m_last[PFS_MAX_SCAN_PASS];
|
||||
};
|
||||
|
||||
|
||||
/** Instrumented thread implementation. @see PSI_thread. */
|
||||
struct PFS_thread
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue