Skip to content

Commit 0d55a07

Browse files
committed
Bug#17507853 PREVENT FALSE SHARING OF CPU CACHE LINE FOR SENSITIVE COUNTERS
This fix is a code cleanup to avoid risks of performance degradations. In the performance schema code, several internal counters are highly sensitive, because they are used very often, and used with atomic operations. For these counters, it is critical that the counter is allocated on a CPU cache line, and that no other variable is allocated in the same memory area, which can end up in the same CPU cache line. This fix introduce PFS_cacheline_uint32 and PFS_cacheline_uint64, to enforce this property. Al internal counters related to allocation internal objects have been changed to use PFS_cacheline_uint32/64. Whether CPU cache line collision did happened in the past, causing performance degradations, is unknown, so this fix may not improve current performance. What this fix does however, is to make sure that cache line collisions are now impossible, to prevent any regressions when using: - different compilers - different compiler options - different CPUs Also, the allocation algorithm for PFS_account, PFS_user and PFS_host have been changed to follow the mainline code. PFS_scan has been removed, this way of performing allocations is no longer needed.
1 parent 2842462 commit 0d55a07

20 files changed

+279
-354
lines changed

storage/perfschema/pfs_account.cc

+75-73
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@
3636
@{
3737
*/
3838

39-
ulong account_max;
40-
ulong account_lost;
39+
ulong account_max= 0;
40+
ulong account_lost= 0;
41+
bool account_full;
4142

4243
PFS_account *account_array= NULL;
4344

@@ -59,6 +60,8 @@ int init_account(const PFS_global_param *param)
5960
uint index;
6061

6162
account_max= param->m_account_sizing;
63+
account_lost= 0;
64+
account_full= false;
6265

6366
account_array= NULL;
6467
account_instr_class_waits_array= NULL;
@@ -225,11 +228,7 @@ find_or_create_account(PFS_thread *thread,
225228
const char *username, uint username_length,
226229
const char *hostname, uint hostname_length)
227230
{
228-
if (account_max == 0)
229-
{
230-
account_lost++;
231-
return NULL;
232-
}
231+
static PFS_ALIGNED PFS_cacheline_uint32 monotonic;
233232

234233
LF_PINS *pins= get_account_hash_pins(thread);
235234
if (unlikely(pins == NULL))
@@ -243,16 +242,18 @@ find_or_create_account(PFS_thread *thread,
243242
hostname, hostname_length);
244243

245244
PFS_account **entry;
245+
PFS_account *pfs;
246246
uint retry_count= 0;
247247
const uint retry_max= 3;
248+
uint index;
249+
uint attempts= 0;
248250

249251
search:
250252
entry= reinterpret_cast<PFS_account**>
251253
(lf_hash_search(&account_hash, pins,
252254
key.m_hash_key, key.m_key_length));
253255
if (entry && (entry != MY_ERRPTR))
254256
{
255-
PFS_account *pfs;
256257
pfs= *entry;
257258
pfs->inc_refcount();
258259
lf_hash_search_unpin(pins);
@@ -261,88 +262,88 @@ find_or_create_account(PFS_thread *thread,
261262

262263
lf_hash_search_unpin(pins);
263264

264-
PFS_scan scan;
265-
uint random= randomized_index(username, account_max);
265+
if (account_full)
266+
{
267+
account_lost++;
268+
return NULL;
269+
}
266270

267-
for (scan.init(random, account_max);
268-
scan.has_pass();
269-
scan.next_pass())
271+
while (++attempts <= account_max)
270272
{
271-
PFS_account *pfs= account_array + scan.first();
272-
PFS_account *pfs_last= account_array + scan.last();
273-
for ( ; pfs < pfs_last; pfs++)
273+
index= PFS_atomic::add_u32(& monotonic.m_u32, 1) % account_max;
274+
pfs= account_array + index;
275+
276+
if (pfs->m_lock.is_free())
274277
{
275-
if (pfs->m_lock.is_free())
278+
if (pfs->m_lock.free_to_dirty())
276279
{
277-
if (pfs->m_lock.free_to_dirty())
280+
pfs->m_key= key;
281+
if (username_length > 0)
282+
pfs->m_username= &pfs->m_key.m_hash_key[0];
283+
else
284+
pfs->m_username= NULL;
285+
pfs->m_username_length= username_length;
286+
287+
if (hostname_length > 0)
288+
pfs->m_hostname= &pfs->m_key.m_hash_key[username_length + 1];
289+
else
290+
pfs->m_hostname= NULL;
291+
pfs->m_hostname_length= hostname_length;
292+
293+
pfs->m_user= find_or_create_user(thread, username, username_length);
294+
pfs->m_host= find_or_create_host(thread, hostname, hostname_length);
295+
296+
pfs->init_refcount();
297+
pfs->reset_stats();
298+
pfs->m_disconnected_count= 0;
299+
300+
if (username_length > 0 && hostname_length > 0)
278301
{
279-
pfs->m_key= key;
280-
if (username_length > 0)
281-
pfs->m_username= &pfs->m_key.m_hash_key[0];
282-
else
283-
pfs->m_username= NULL;
284-
pfs->m_username_length= username_length;
285-
286-
if (hostname_length > 0)
287-
pfs->m_hostname= &pfs->m_key.m_hash_key[username_length + 1];
288-
else
289-
pfs->m_hostname= NULL;
290-
pfs->m_hostname_length= hostname_length;
291-
292-
pfs->m_user= find_or_create_user(thread, username, username_length);
293-
pfs->m_host= find_or_create_host(thread, hostname, hostname_length);
294-
295-
pfs->init_refcount();
296-
pfs->reset_stats();
297-
pfs->m_disconnected_count= 0;
298-
299-
if (username_length > 0 && hostname_length > 0)
300-
{
301-
lookup_setup_actor(thread, username, username_length, hostname, hostname_length,
302-
& pfs->m_enabled);
303-
}
304-
else
305-
pfs->m_enabled= true;
302+
lookup_setup_actor(thread, username, username_length, hostname, hostname_length,
303+
& pfs->m_enabled);
304+
}
305+
else
306+
pfs->m_enabled= true;
306307

307-
int res;
308-
res= lf_hash_insert(&account_hash, pins, &pfs);
309-
if (likely(res == 0))
310-
{
311-
pfs->m_lock.dirty_to_allocated();
312-
return pfs;
313-
}
308+
int res;
309+
res= lf_hash_insert(&account_hash, pins, &pfs);
310+
if (likely(res == 0))
311+
{
312+
pfs->m_lock.dirty_to_allocated();
313+
return pfs;
314+
}
314315

315-
if (pfs->m_user)
316-
{
317-
pfs->m_user->release();
318-
pfs->m_user= NULL;
319-
}
320-
if (pfs->m_host)
321-
{
322-
pfs->m_host->release();
323-
pfs->m_host= NULL;
324-
}
316+
if (pfs->m_user)
317+
{
318+
pfs->m_user->release();
319+
pfs->m_user= NULL;
320+
}
321+
if (pfs->m_host)
322+
{
323+
pfs->m_host->release();
324+
pfs->m_host= NULL;
325+
}
325326

326-
pfs->m_lock.dirty_to_free();
327+
pfs->m_lock.dirty_to_free();
327328

328-
if (res > 0)
329+
if (res > 0)
330+
{
331+
if (++retry_count > retry_max)
329332
{
330-
if (++retry_count > retry_max)
331-
{
332-
account_lost++;
333-
return NULL;
334-
}
335-
goto search;
333+
account_lost++;
334+
return NULL;
336335
}
337-
338-
account_lost++;
339-
return NULL;
336+
goto search;
340337
}
338+
339+
account_lost++;
340+
return NULL;
341341
}
342342
}
343343
}
344344

345345
account_lost++;
346+
account_full= true;
346347
return NULL;
347348
}
348349

@@ -651,6 +652,7 @@ void purge_account(PFS_thread *thread, PFS_account *account)
651652
account->m_host= NULL;
652653
}
653654
account->m_lock.allocated_to_free();
655+
account_full= false;
654656
}
655657
}
656658

storage/perfschema/pfs_digest.cc

+10-7
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ bool flag_statements_digest= true;
6969
Current index in Stat array where new record is to be inserted.
7070
index 0 is reserved for "all else" case when entire array is full.
7171
*/
72-
volatile uint32 digest_index= 1;
72+
static PFS_ALIGNED PFS_cacheline_uint32 digest_index;
73+
bool digest_full= false;
7374

7475
LF_HASH digest_hash;
7576
static bool digest_hash_inited= false;
@@ -88,6 +89,8 @@ int init_digest(const PFS_global_param *param)
8889
*/
8990
digest_max= param->m_digest_sizing;
9091
digest_lost= 0;
92+
digest_index.m_u32= 1;
93+
digest_full= false;
9194

9295
if (digest_max == 0)
9396
return 0;
@@ -228,10 +231,9 @@ find_or_create_digest(PFS_thread *thread,
228231

229232
lf_hash_search_unpin(pins);
230233

231-
/* Dirty read of digest_index */
232-
if (digest_index == 0)
234+
if (digest_full)
233235
{
234-
/* digest_stat array is full. Add stat at index 0 and return. */
236+
/* digest_stat array is full. Add stat at index 0 and return. */
235237
pfs= &statements_digest_stat_array[0];
236238

237239
if (pfs->m_first_seen == 0)
@@ -240,11 +242,11 @@ find_or_create_digest(PFS_thread *thread,
240242
return & pfs->m_stat;
241243
}
242244

243-
safe_index= PFS_atomic::add_u32(& digest_index, 1);
245+
safe_index= PFS_atomic::add_u32(& digest_index.m_u32, 1);
244246
if (safe_index >= digest_max)
245247
{
246248
/* The digest array is now full. */
247-
digest_index= 0;
249+
digest_full= true;
248250
pfs= &statements_digest_stat_array[0];
249251

250252
if (pfs->m_first_seen == 0)
@@ -352,7 +354,8 @@ void reset_esms_by_digest()
352354
Reset index which indicates where the next calculated digest information
353355
to be inserted in statements_digest_stat_array.
354356
*/
355-
digest_index= 1;
357+
digest_index.m_u32= 1;
358+
digest_full= false;
356359
}
357360

358361
/*

storage/perfschema/pfs_events_stages.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ PFS_ALIGNED bool flag_events_stages_history_long= false;
4141
/** True if EVENTS_STAGES_HISTORY_LONG circular buffer is full. */
4242
PFS_ALIGNED bool events_stages_history_long_full= false;
4343
/** Index in EVENTS_STAGES_HISTORY_LONG circular buffer. */
44-
PFS_ALIGNED volatile uint32 events_stages_history_long_index= 0;
44+
PFS_ALIGNED PFS_cacheline_uint32 events_stages_history_long_index;
4545
/** EVENTS_STAGES_HISTORY_LONG circular buffer. */
4646
PFS_ALIGNED PFS_events_stages *events_stages_history_long_array= NULL;
4747

@@ -53,7 +53,7 @@ int init_events_stages_history_long(uint events_stages_history_long_sizing)
5353
{
5454
events_stages_history_long_size= events_stages_history_long_sizing;
5555
events_stages_history_long_full= false;
56-
PFS_atomic::store_u32(&events_stages_history_long_index, 0);
56+
PFS_atomic::store_u32(&events_stages_history_long_index.m_u32, 0);
5757

5858
if (events_stages_history_long_size == 0)
5959
return 0;
@@ -122,7 +122,7 @@ void insert_events_stages_history_long(PFS_events_stages *stage)
122122

123123
DBUG_ASSERT(events_stages_history_long_array != NULL);
124124

125-
uint index= PFS_atomic::add_u32(&events_stages_history_long_index, 1);
125+
uint index= PFS_atomic::add_u32(&events_stages_history_long_index.m_u32, 1);
126126

127127
index= index % events_stages_history_long_size;
128128
if (index == 0)
@@ -165,7 +165,7 @@ void reset_events_stages_history(void)
165165
/** Reset table EVENTS_STAGES_HISTORY_LONG data. */
166166
void reset_events_stages_history_long(void)
167167
{
168-
PFS_atomic::store_u32(&events_stages_history_long_index, 0);
168+
PFS_atomic::store_u32(&events_stages_history_long_index.m_u32, 0);
169169
events_stages_history_long_full= false;
170170

171171
PFS_events_stages *pfs= events_stages_history_long_array;

storage/perfschema/pfs_events_stages.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -42,7 +42,7 @@ extern bool flag_events_stages_history;
4242
extern bool flag_events_stages_history_long;
4343

4444
extern bool events_stages_history_long_full;
45-
extern volatile uint32 events_stages_history_long_index;
45+
extern PFS_ALIGNED PFS_cacheline_uint32 events_stages_history_long_index;
4646
extern PFS_events_stages *events_stages_history_long_array;
4747
extern ulong events_stages_history_long_size;
4848

storage/perfschema/pfs_events_statements.cc

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ PFS_ALIGNED bool flag_events_statements_history_long= false;
4141
/** True if EVENTS_STATEMENTS_HISTORY_LONG circular buffer is full. */
4242
PFS_ALIGNED bool events_statements_history_long_full= false;
4343
/** Index in EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
44-
PFS_ALIGNED volatile uint32 events_statements_history_long_index= 0;
44+
PFS_ALIGNED PFS_cacheline_uint32 events_statements_history_long_index;
4545
/** EVENTS_STATEMENTS_HISTORY_LONG circular buffer. */
4646
PFS_ALIGNED PFS_events_statements *events_statements_history_long_array= NULL;
4747

@@ -53,7 +53,7 @@ int init_events_statements_history_long(uint events_statements_history_long_sizi
5353
{
5454
events_statements_history_long_size= events_statements_history_long_sizing;
5555
events_statements_history_long_full= false;
56-
PFS_atomic::store_u32(&events_statements_history_long_index, 0);
56+
PFS_atomic::store_u32(&events_statements_history_long_index.m_u32, 0);
5757

5858
if (events_statements_history_long_size == 0)
5959
return 0;
@@ -122,7 +122,7 @@ void insert_events_statements_history_long(PFS_events_statements *statement)
122122

123123
DBUG_ASSERT(events_statements_history_long_array != NULL);
124124

125-
uint index= PFS_atomic::add_u32(&events_statements_history_long_index, 1);
125+
uint index= PFS_atomic::add_u32(&events_statements_history_long_index.m_u32, 1);
126126

127127
index= index % events_statements_history_long_size;
128128
if (index == 0)
@@ -169,7 +169,7 @@ void reset_events_statements_history(void)
169169
/** Reset table EVENTS_STATEMENTS_HISTORY_LONG data. */
170170
void reset_events_statements_history_long(void)
171171
{
172-
PFS_atomic::store_u32(&events_statements_history_long_index, 0);
172+
PFS_atomic::store_u32(&events_statements_history_long_index.m_u32, 0);
173173
events_statements_history_long_full= false;
174174

175175
PFS_events_statements *pfs= events_statements_history_long_array;

storage/perfschema/pfs_events_statements.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ extern bool flag_events_statements_history;
108108
extern bool flag_events_statements_history_long;
109109

110110
extern bool events_statements_history_long_full;
111-
extern volatile uint32 events_statements_history_long_index;
111+
extern PFS_ALIGNED PFS_cacheline_uint32 events_statements_history_long_index;
112112
extern PFS_events_statements *events_statements_history_long_array;
113113
extern ulong events_statements_history_long_size;
114114

0 commit comments

Comments
 (0)