7
7
#include "cache.h"
8
8
#include "parse-options.h"
9
9
#include "fsmonitor-ipc.h"
10
+ #include "thread-utils.h"
11
+ #include "trace2.h"
10
12
11
13
#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
12
14
int cmd__fsmonitor_client (int argc , const char * * argv )
@@ -79,20 +81,120 @@ static int do_send_flush(void)
79
81
return 0 ;
80
82
}
81
83
84
+ struct hammer_thread_data
85
+ {
86
+ pthread_t pthread_id ;
87
+ int thread_nr ;
88
+
89
+ int nr_requests ;
90
+ const char * token ;
91
+
92
+ int sum_successful ;
93
+ int sum_errors ;
94
+ };
95
+
96
+ static void * hammer_thread_proc (void * _hammer_thread_data )
97
+ {
98
+ struct hammer_thread_data * data = _hammer_thread_data ;
99
+ struct strbuf answer = STRBUF_INIT ;
100
+ int k ;
101
+ int ret ;
102
+
103
+ trace2_thread_start ("hammer" );
104
+
105
+ for (k = 0 ; k < data -> nr_requests ; k ++ ) {
106
+ strbuf_reset (& answer );
107
+
108
+ ret = fsmonitor_ipc__send_query (data -> token , & answer );
109
+ if (ret < 0 )
110
+ data -> sum_errors ++ ;
111
+ else
112
+ data -> sum_successful ++ ;
113
+ }
114
+
115
+ strbuf_release (& answer );
116
+ trace2_thread_exit ();
117
+ return NULL ;
118
+ }
119
+
120
+ /*
121
+ * Start a pool of client threads that will each send a series of
122
+ * commands to the daemon.
123
+ *
124
+ * The goal is to overload the daemon with a sustained series of
125
+ * concurrent requests.
126
+ */
127
+ static int do_hammer (const char * token , int nr_threads , int nr_requests )
128
+ {
129
+ struct hammer_thread_data * data = NULL ;
130
+ int k ;
131
+ int sum_join_errors = 0 ;
132
+ int sum_commands = 0 ;
133
+ int sum_errors = 0 ;
134
+
135
+ if (!token || !* token )
136
+ token = get_token_from_index ();
137
+ if (nr_threads < 1 )
138
+ nr_threads = 1 ;
139
+ if (nr_requests < 1 )
140
+ nr_requests = 1 ;
141
+
142
+ CALLOC_ARRAY (data , nr_threads );
143
+
144
+ for (k = 0 ; k < nr_threads ; k ++ ) {
145
+ struct hammer_thread_data * p = & data [k ];
146
+ p -> thread_nr = k ;
147
+ p -> nr_requests = nr_requests ;
148
+ p -> token = token ;
149
+
150
+ if (pthread_create (& p -> pthread_id , NULL , hammer_thread_proc , p )) {
151
+ warning ("failed to create thread[%d] skipping remainder" , k );
152
+ nr_threads = k ;
153
+ break ;
154
+ }
155
+ }
156
+
157
+ for (k = 0 ; k < nr_threads ; k ++ ) {
158
+ struct hammer_thread_data * p = & data [k ];
159
+
160
+ if (pthread_join (p -> pthread_id , NULL ))
161
+ sum_join_errors ++ ;
162
+ sum_commands += p -> sum_successful ;
163
+ sum_errors += p -> sum_errors ;
164
+ }
165
+
166
+ fprintf (stderr , "HAMMER: [threads %d][requests %d] [ok %d][err %d][join %d]\n" ,
167
+ nr_threads , nr_requests , sum_commands , sum_errors , sum_join_errors );
168
+
169
+ free (data );
170
+
171
+ /*
172
+ * TODO Decide if/when to return an error or call die().
173
+ */
174
+ return 0 ;
175
+ }
176
+
82
177
int cmd__fsmonitor_client (int argc , const char * * argv )
83
178
{
84
179
const char * subcmd ;
85
180
const char * token = NULL ;
181
+ int nr_threads = 1 ;
182
+ int nr_requests = 1 ;
86
183
87
184
const char * const fsmonitor_client_usage [] = {
88
185
N_ ("test-helper fsmonitor-client query [<token>]" ),
89
186
N_ ("test-helper fsmonitor-client flush" ),
187
+ N_ ("test-helper fsmonitor-client hammer [<token>] [<threads>] [<requests>]" ),
90
188
NULL ,
91
189
};
92
190
93
191
struct option options [] = {
94
192
OPT_STRING (0 , "token" , & token , N_ ("token" ),
95
193
N_ ("command token to send to the server" )),
194
+
195
+ OPT_INTEGER (0 , "threads" , & nr_threads , N_ ("number of client threads" )),
196
+ OPT_INTEGER (0 , "requests" , & nr_requests , N_ ("number of requests per thread" )),
197
+
96
198
OPT_END ()
97
199
};
98
200
@@ -116,6 +218,9 @@ int cmd__fsmonitor_client(int argc, const char **argv)
116
218
if (!strcmp (subcmd , "flush" ))
117
219
return !!do_send_flush ();
118
220
221
+ if (!strcmp (subcmd , "hammer" ))
222
+ return !!do_hammer (token , nr_threads , nr_requests );
223
+
119
224
die ("Unhandled subcommand: '%s'" , subcmd );
120
225
}
121
226
#endif
0 commit comments