1 /* Copyright (C) 2004 MySQL AB
2    Copyright (C) 2004-2016 Alexey Kopytov <akopytov@gmail.com>
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 # include "config.h"
21 #endif
22 
23 #ifdef _WIN32
24 # include "sb_win.h"
25 #endif
26 
27 #ifdef HAVE_PTHREAD_H
28 # include <pthread.h>
29 #endif
30 
31 #include "sysbench.h"
32 #include "sb_ck_pr.h"
33 #include "sb_rand.h"
34 
35 typedef struct
36 {
37   pthread_mutex_t mutex;
38   char            pad[256];
39 } thread_lock;
40 
41 
42 /* Mutex test arguments */
43 static sb_arg_t mutex_args[] =
44 {
45   SB_OPT("mutex-num", "total size of mutex array", "4096", INT),
46   SB_OPT("mutex-locks", "number of mutex locks to do per thread", "50000", INT),
47   SB_OPT("mutex-loops", "number of empty loops to do outside mutex lock",
48          "10000", INT),
49 
50   SB_OPT_END
51 };
52 
53 /* Mutex test operations */
54 static int mutex_init(void);
55 static void mutex_print_mode(void);
56 static sb_event_t mutex_next_event(int);
57 static int mutex_execute_event(sb_event_t *, int);
58 static int mutex_done(void);
59 
60 static sb_test_t mutex_test =
61 {
62   .sname = "mutex",
63   .lname = "Mutex performance test",
64   .ops = {
65      .init = mutex_init,
66      .print_mode = mutex_print_mode,
67      .next_event = mutex_next_event,
68      .execute_event = mutex_execute_event,
69      .done = mutex_done
70   },
71   .args = mutex_args
72 };
73 
74 
75 static thread_lock *thread_locks;
76 static unsigned int mutex_num;
77 static unsigned int mutex_loops;
78 static unsigned int mutex_locks;
79 static unsigned int global_var;
80 
81 static TLS int tls_counter;
82 
register_test_mutex(sb_list_t * tests)83 int register_test_mutex(sb_list_t *tests)
84 {
85   SB_LIST_ADD_TAIL(&mutex_test.listitem, tests);
86 
87   return 0;
88 }
89 
90 
mutex_init(void)91 int mutex_init(void)
92 {
93   unsigned int i;
94 
95   mutex_num = sb_get_value_int("mutex-num");
96   mutex_loops = sb_get_value_int("mutex-loops");
97   mutex_locks = sb_get_value_int("mutex-locks");
98 
99   thread_locks = (thread_lock *)malloc(mutex_num * sizeof(thread_lock));
100   if (thread_locks == NULL)
101   {
102     log_text(LOG_FATAL, "Memory allocation failure!");
103     return 1;
104   }
105 
106   for (i = 0; i < mutex_num; i++)
107     pthread_mutex_init(&thread_locks[i].mutex, NULL);
108 
109   return 0;
110 }
111 
112 
mutex_done(void)113 int mutex_done(void)
114 {
115   unsigned int i;
116 
117   for(i=0; i < mutex_num; i++)
118     pthread_mutex_destroy(&thread_locks[i].mutex);
119   free(thread_locks);
120 
121   return 0;
122 }
123 
124 
mutex_next_event(int thread_id)125 sb_event_t mutex_next_event(int thread_id)
126 {
127   sb_event_t         sb_req;
128   sb_mutex_request_t   *mutex_req = &sb_req.u.mutex_request;
129 
130   (void) thread_id; /* unused */
131 
132   /* Perform only one request per thread */
133   if (tls_counter++ > 0)
134     sb_req.type = SB_REQ_TYPE_NULL;
135   else
136   {
137     sb_req.type = SB_REQ_TYPE_MUTEX;
138     mutex_req->nlocks = mutex_locks;
139     mutex_req->nloops = mutex_loops;
140   }
141 
142   return sb_req;
143 }
144 
145 
mutex_execute_event(sb_event_t * sb_req,int thread_id)146 int mutex_execute_event(sb_event_t *sb_req, int thread_id)
147 {
148   unsigned int         i;
149   unsigned int         current_lock;
150   sb_mutex_request_t   *mutex_req = &sb_req->u.mutex_request;
151 
152   (void) thread_id; /* unused */
153 
154   do
155   {
156     current_lock = sb_rand_uniform(0, mutex_num - 1);
157 
158     for (i = 0; i < mutex_req->nloops; i++)
159       ck_pr_barrier();
160 
161     pthread_mutex_lock(&thread_locks[current_lock].mutex);
162     global_var++;
163     pthread_mutex_unlock(&thread_locks[current_lock].mutex);
164     mutex_req->nlocks--;
165   }
166   while (mutex_req->nlocks > 0);
167 
168   return 0;
169 }
170 
171 
mutex_print_mode(void)172 void mutex_print_mode(void)
173 {
174   log_text(LOG_INFO, "Doing mutex performance test");
175 }
176 
177