Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fix for CONC-196: Avoid unnecessary extra loops in alloc_root() funct…
…ion.

Added performance test which requires employees database.
  • Loading branch information
9EOR9 committed Aug 3, 2016
1 parent ba1308b commit ac60780
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 13 deletions.
37 changes: 25 additions & 12 deletions libmariadb/my_alloc.c
Expand Up @@ -23,10 +23,12 @@

void init_alloc_root(MEM_ROOT *mem_root, size_t block_size, size_t pre_alloc_size)
{
mem_root->free=mem_root->used=0;
mem_root->free= mem_root->used= mem_root->pre_alloc= 0;
mem_root->min_malloc=32;
mem_root->block_size=block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)-8;
mem_root->block_size= (block_size-MALLOC_OVERHEAD-sizeof(USED_MEM)+8);
mem_root->error_handler=0;
mem_root->block_num= 4;
mem_root->first_block_usage= 0;
#if !(defined(HAVE_purify) && defined(EXTRA_DEBUG))
if (pre_alloc_size)
{
Expand Down Expand Up @@ -60,30 +62,40 @@ gptr alloc_root(MEM_ROOT *mem_root, size_t Size)
#else
size_t get_size,max_left;
gptr point;
reg1 USED_MEM *next;
reg1 USED_MEM *next= 0;
reg2 USED_MEM **prev;

Size= ALIGN_SIZE(Size);
prev= &mem_root->free;
max_left=0;
for (next= *prev ; next && next->left < Size ; next= next->next)

if ((*(prev= &mem_root->free)))
{
if (next->left > max_left)
max_left=next->left;
prev= &next->next;
if ((*prev)->left < Size &&
mem_root->first_block_usage++ >= 16 &&
(*prev)->left < 4096)
{
next= *prev;
*prev= next->next;
next->next= mem_root->used;
mem_root->used= next;
mem_root->first_block_usage= 0;
}
for (next= *prev; next && next->left < Size; next= next->next)
prev= &next->next;
}

if (! next)
{ /* Time to alloc new block */
get_size= Size+ALIGN_SIZE(sizeof(USED_MEM));
if (max_left*4 < mem_root->block_size && get_size < mem_root->block_size)
get_size=mem_root->block_size; /* Normal alloc */
get_size= MAX(Size+ALIGN_SIZE(sizeof(USED_MEM)),
(mem_root->block_size & ~1) * (mem_root->block_num >> 2));

if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME | MY_ZEROFILL))))
if (!(next = (USED_MEM*) my_malloc(get_size,MYF(MY_WME))))
{
if (mem_root->error_handler)
(*mem_root->error_handler)();
return((gptr) 0); /* purecov: inspected */
}
mem_root->block_num++;
next->next= *prev;
next->size= get_size;
next->left= get_size-ALIGN_SIZE(sizeof(USED_MEM));
Expand All @@ -95,6 +107,7 @@ gptr alloc_root(MEM_ROOT *mem_root, size_t Size)
*prev=next->next; /* Remove block from list */
next->next=mem_root->used;
mem_root->used=next;
mem_root->first_block_usage= 0;
}
return(point);
#endif
Expand Down
2 changes: 1 addition & 1 deletion unittest/libmariadb/CMakeLists.txt
Expand Up @@ -21,7 +21,7 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
${CMAKE_SOURCE_DIR}/unittest/mytap)
ADD_DEFINITIONS(-DLIBMARIADB)

SET(API_TESTS "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
SET(API_TESTS "performance" "async" "basic-t" "fetch" "charset" "logs" "cursor" "errors" "view" "ps" "ps_bugs"
"sp" "result" "connection" "misc" "ps_new" "sqlite3" "thread" "dyncol")

# Get finger print from server certificate
Expand Down
94 changes: 94 additions & 0 deletions unittest/libmariadb/performance.c
@@ -0,0 +1,94 @@
/*
Copyright (c) 2016 MariaDB Corporation AB
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 the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the 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.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/


/**
Some basic tests of the client API.
*/

#include "my_test.h"
#include "ma_common.h"

void show_time(struct timeval t1)
{
struct timeval t2;
double elapsed;
gettimeofday(&t2, NULL);
elapsed = ((t2.tv_sec - t1.tv_sec)* 1000.0 + (t2.tv_usec - t1.tv_usec) / 1000.0) / 1000;
diag("elapsed: %5.2f", elapsed);
}

static int perf1(MYSQL *mysql)
{
int rc;
MYSQL_STMT *stmt;
struct timeval t1;
char *stmtstr= "SELECT s.emp_no, s.salary, e.emp_no, e.first_name, e.last_name, e.gender FROM salaries s, employees e WHERE s.emp_no = e.emp_no";

rc= mysql_select_db(mysql, "employees");
if (rc)
{
diag("Employees database not installed");
return SKIP;
}

stmt= mysql_stmt_init(mysql);

diag("prepare");
gettimeofday(&t1, NULL);
rc= mysql_stmt_prepare(stmt, stmtstr, strlen(stmtstr));
check_stmt_rc(rc, stmt);
show_time(t1);

diag("execute");
gettimeofday(&t1, NULL);
rc= mysql_stmt_execute(stmt);
check_stmt_rc(rc, stmt);
show_time(t1);

diag("store");
gettimeofday(&t1, NULL);
rc= mysql_stmt_store_result(stmt);
check_stmt_rc(rc, stmt);
show_time(t1);

diag("fetch");
gettimeofday(&t1, NULL);
while (!mysql_stmt_fetch(stmt));
show_time(t1);

mysql_stmt_close(stmt);
return OK;
}

struct my_tests_st my_tests[] = {
{"perf1", perf1, TEST_CONNECTION_NEW, 0, NULL, NULL},
{NULL, NULL, 0, 0, NULL, NULL}
};


int main(int argc, char **argv)
{
if (argc > 1)
get_options(argc, argv);

get_envvars();

run_tests(my_tests);

return(exit_status());
}

0 comments on commit ac60780

Please sign in to comment.