Commit e04de978 authored by Marc Alff's avatar Marc Alff

Bug#52502 Performance schema does not start with large mutex_instance buffers

Backport from mysql-next-mr (5.6) to mysql-trunk (5.5)
parent 36e80ced
...@@ -31,27 +31,50 @@ void pfs_free(void *ptr); ...@@ -31,27 +31,50 @@ void pfs_free(void *ptr);
inline uint randomized_index(const void *ptr, uint max_size) 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)) if (unlikely(max_size == 0))
return 0; return 0;
/* /*
ptr is typically an aligned structure, ptr is typically an aligned structure, and can be in an array.
so the last bits are not really random, but this has no effect. - The last bits are not random because of alignment,
Apply a factor A*x to spread so we divide by 8.
close values of ptr further apart (which helps with arrays), - The high bits are mostly constant, especially with 64 bits architectures,
and to spread values way beyond a typical max_size. but we keep most of them anyway, by doing computation in intptr.
Then, apply a modulo to end within [0, max_size - 1]. The high bits are significant depending on where the data is
A is big prime numbers, to avoid resonating with max_size, stored (the data segment, the stack, the heap, ...).
to have a uniform distribution in [0, max_size - 1]. - To spread consecutive cells in an array further, we multiply by
The value of A is chosen so that index(ptr) and index(ptr + N) (for arrays) a factor A. This factor should not be too high, which would cause
are likely to be not similar for typical values of max_size an overflow and cause loss of randomness (droping the top high bits).
(50, 100, 1000, etc). The factor is a prime number, to help spread the distribution.
In other words, (sizeof(T)*A % max_size) should not be a small number, - To add more noise, and to be more robust if the calling code is
to avoid that with 'T array[max_size]', index(array[i]) passing a constant value instead of a random identity,
and index(array[i + 1]) end up pointing in the same area in [0, max_size - 1]. 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> value= (reinterpret_cast<intptr> (ptr)) >> 3;
(((reinterpret_cast<intptr> (ptr)) * 2166179) % max_size); 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, ...); void pfs_print_error(const char *format, ...);
......
/* 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 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 it under the terms of the GNU General Public License as published by
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software Foundation,
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/** /**
@file storage/perfschema/pfs_instr.cc @file storage/perfschema/pfs_instr.cc
...@@ -21,8 +21,8 @@ ...@@ -21,8 +21,8 @@
#include <string.h> #include <string.h>
#include "my_global.h" #include "my_global.h"
#include "sql_priv.h"
#include "my_sys.h" #include "my_sys.h"
#include "pfs.h"
#include "pfs_stat.h" #include "pfs_stat.h"
#include "pfs_instr.h" #include "pfs_instr.h"
#include "pfs_global.h" #include "pfs_global.h"
...@@ -411,6 +411,8 @@ void cleanup_instruments(void) ...@@ -411,6 +411,8 @@ void cleanup_instruments(void)
thread_instr_class_waits_array= NULL; thread_instr_class_waits_array= NULL;
} }
extern "C"
{
static uchar *filename_hash_get_key(const uchar *entry, size_t *length, static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
my_bool) my_bool)
{ {
...@@ -425,6 +427,7 @@ static uchar *filename_hash_get_key(const uchar *entry, size_t *length, ...@@ -425,6 +427,7 @@ static uchar *filename_hash_get_key(const uchar *entry, size_t *length,
result= file->m_filename; result= file->m_filename;
return const_cast<uchar*> (reinterpret_cast<const uchar*> (result)); return const_cast<uchar*> (reinterpret_cast<const uchar*> (result));
} }
}
/** /**
Initialize the file name hash. Initialize the file name hash.
...@@ -451,6 +454,75 @@ void cleanup_file_hash(void) ...@@ -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. Create instrumentation for a mutex instance.
@param klass the mutex class @param klass the mutex class
...@@ -459,17 +531,15 @@ void cleanup_file_hash(void) ...@@ -459,17 +531,15 @@ void cleanup_file_hash(void)
*/ */
PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity) PFS_mutex* create_mutex(PFS_mutex_class *klass, const void *identity)
{ {
int pass; PFS_scan scan;
uint i= randomized_index(identity, mutex_max); uint random= randomized_index(identity, mutex_max);
/* for (scan.init(random, mutex_max);
Pass 1: [random, mutex_max - 1] scan.has_pass();
Pass 2: [0, mutex_max - 1] scan.next_pass())
*/
for (pass= 1; pass <= 2; i=0, pass++)
{ {
PFS_mutex *pfs= mutex_array + i; PFS_mutex *pfs= mutex_array + scan.first();
PFS_mutex *pfs_last= mutex_array + mutex_max; PFS_mutex *pfs_last= mutex_array + scan.last();
for ( ; pfs < pfs_last; pfs++) for ( ; pfs < pfs_last; pfs++)
{ {
if (pfs->m_lock.is_free()) if (pfs->m_lock.is_free())
...@@ -517,17 +587,15 @@ void destroy_mutex(PFS_mutex *pfs) ...@@ -517,17 +587,15 @@ void destroy_mutex(PFS_mutex *pfs)
*/ */
PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity) PFS_rwlock* create_rwlock(PFS_rwlock_class *klass, const void *identity)
{ {
int pass; PFS_scan scan;
uint i= randomized_index(identity, rwlock_max); uint random= randomized_index(identity, rwlock_max);
/* for (scan.init(random, rwlock_max);
Pass 1: [random, rwlock_max - 1] scan.has_pass();
Pass 2: [0, rwlock_max - 1] scan.next_pass())
*/
for (pass= 1; pass <= 2; i=0, pass++)
{ {
PFS_rwlock *pfs= rwlock_array + i; PFS_rwlock *pfs= rwlock_array + scan.first();
PFS_rwlock *pfs_last= rwlock_array + rwlock_max; PFS_rwlock *pfs_last= rwlock_array + scan.last();
for ( ; pfs < pfs_last; pfs++) for ( ; pfs < pfs_last; pfs++)
{ {
if (pfs->m_lock.is_free()) if (pfs->m_lock.is_free())
...@@ -581,17 +649,15 @@ void destroy_rwlock(PFS_rwlock *pfs) ...@@ -581,17 +649,15 @@ void destroy_rwlock(PFS_rwlock *pfs)
*/ */
PFS_cond* create_cond(PFS_cond_class *klass, const void *identity) PFS_cond* create_cond(PFS_cond_class *klass, const void *identity)
{ {
int pass; PFS_scan scan;
uint i= randomized_index(identity, cond_max); uint random= randomized_index(identity, cond_max);
/* for (scan.init(random, cond_max);
Pass 1: [random, cond_max - 1] scan.has_pass();
Pass 2: [0, cond_max - 1] scan.next_pass())
*/
for (pass= 1; pass <= 2; i=0, pass++)
{ {
PFS_cond *pfs= cond_array + i; PFS_cond *pfs= cond_array + scan.first();
PFS_cond *pfs_last= cond_array + cond_max; PFS_cond *pfs_last= cond_array + scan.last();
for ( ; pfs < pfs_last; pfs++) for ( ; pfs < pfs_last; pfs++)
{ {
if (pfs->m_lock.is_free()) if (pfs->m_lock.is_free())
...@@ -639,17 +705,15 @@ void destroy_cond(PFS_cond *pfs) ...@@ -639,17 +705,15 @@ void destroy_cond(PFS_cond *pfs)
PFS_thread* create_thread(PFS_thread_class *klass, const void *identity, PFS_thread* create_thread(PFS_thread_class *klass, const void *identity,
ulong thread_id) ulong thread_id)
{ {
int pass; PFS_scan scan;
uint i= randomized_index(identity, thread_max); uint random= randomized_index(identity, thread_max);
/* for (scan.init(random, thread_max);
Pass 1: [random, thread_max - 1] scan.has_pass();
Pass 2: [0, thread_max - 1] scan.next_pass())
*/
for (pass= 1; pass <= 2; i=0, pass++)
{ {
PFS_thread *pfs= thread_array + i; PFS_thread *pfs= thread_array + scan.first();
PFS_thread *pfs_last= thread_array + thread_max; PFS_thread *pfs_last= thread_array + scan.last();
for ( ; pfs < pfs_last; pfs++) for ( ; pfs < pfs_last; pfs++)
{ {
if (pfs->m_lock.is_free()) if (pfs->m_lock.is_free())
...@@ -733,7 +797,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, ...@@ -733,7 +797,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass,
const char *filename, uint len) const char *filename, uint len)
{ {
PFS_file *pfs; PFS_file *pfs;
int pass; PFS_scan scan;
if (! filename_hash_inited) if (! filename_hash_inited)
{ {
...@@ -806,17 +870,14 @@ search: ...@@ -806,17 +870,14 @@ search:
} }
/* filename is not constant, just using it for noise on create */ /* 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);
/* for (scan.init(random, file_max);
Pass 1: [random, file_max - 1] scan.has_pass();
Pass 2: [0, file_max - 1] scan.next_pass())
*/
for (pass= 1; pass <= 2; i=0, pass++)
{ {
pfs= file_array + i; pfs= file_array + scan.first();
PFS_file *pfs_last= file_array + file_max; PFS_file *pfs_last= file_array + scan.last();
for ( ; pfs < pfs_last; pfs++) for ( ; pfs < pfs_last; pfs++)
{ {
if (pfs->m_lock.is_free()) if (pfs->m_lock.is_free())
...@@ -901,17 +962,15 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs) ...@@ -901,17 +962,15 @@ void destroy_file(PFS_thread *thread, PFS_file *pfs)
*/ */
PFS_table* create_table(PFS_table_share *share, const void *identity) PFS_table* create_table(PFS_table_share *share, const void *identity)
{ {
int pass; PFS_scan scan;
uint i= randomized_index(identity, table_max); uint random= randomized_index(identity, table_max);
/* for (scan.init(random, table_max);
Pass 1: [random, table_max - 1] scan.has_pass();
Pass 2: [0, table_max - 1] scan.next_pass())
*/
for (pass= 1; pass <= 2; i=0, pass++)
{ {
PFS_table *pfs= table_array + i; PFS_table *pfs= table_array + scan.first();
PFS_table *pfs_last= table_array + table_max; PFS_table *pfs_last= table_array + scan.last();
for ( ; pfs < pfs_last; pfs++) for ( ; pfs < pfs_last; pfs++)
{ {
if (pfs->m_lock.is_free()) if (pfs->m_lock.is_free())
......
/* 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 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 it under the terms of the GNU General Public License as published by
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software Foundation,
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
#ifndef PFS_INSTR_H #ifndef PFS_INSTR_H
#define PFS_INSTR_H #define PFS_INSTR_H
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
Performance schema instruments (declarations). Performance schema instruments (declarations).
*/ */
#include <sql_priv.h>
#include "pfs_lock.h" #include "pfs_lock.h"
#include "pfs_instr_class.h" #include "pfs_instr_class.h"
#include "pfs_events_waits.h" #include "pfs_events_waits.h"
...@@ -136,6 +135,48 @@ struct PFS_table : public PFS_instr ...@@ -136,6 +135,48 @@ struct PFS_table : public PFS_instr
*/ */
#define LOCKER_STACK_SIZE 3 #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. */ /** Instrumented thread implementation. @see PSI_thread. */
struct PFS_thread struct PFS_thread
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment