77#include "cache.h"
88#include "parse-options.h"
99#include "fsmonitor-ipc.h"
10+ #include "thread-utils.h"
11+ #include "trace2.h"
1012
1113#ifndef HAVE_FSMONITOR_DAEMON_BACKEND
1214int cmd__fsmonitor_client (int argc , const char * * argv )
@@ -79,20 +81,121 @@ static int do_send_flush(void)
7981 return 0 ;
8082}
8183
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+ * Return an error if any of the _send_query requests failed.
173+ * We don't care about thread create/join errors.
174+ */
175+ return sum_errors > 0 ;
176+ }
177+
82178int cmd__fsmonitor_client (int argc , const char * * argv )
83179{
84180 const char * subcmd ;
85181 const char * token = NULL ;
182+ int nr_threads = 1 ;
183+ int nr_requests = 1 ;
86184
87185 const char * const fsmonitor_client_usage [] = {
88186 "test-tool fsmonitor-client query [<token>]" ,
89187 "test-tool fsmonitor-client flush" ,
188+ "test-tool fsmonitor-client hammer [<token>] [<threads>] [<requests>]" ,
90189 NULL ,
91190 };
92191
93192 struct option options [] = {
94193 OPT_STRING (0 , "token" , & token , "token" ,
95194 "command token to send to the server" ),
195+
196+ OPT_INTEGER (0 , "threads" , & nr_threads , "number of client threads" ),
197+ OPT_INTEGER (0 , "requests" , & nr_requests , "number of requests per thread" ),
198+
96199 OPT_END ()
97200 };
98201
@@ -111,6 +214,9 @@ int cmd__fsmonitor_client(int argc, const char **argv)
111214 if (!strcmp (subcmd , "flush" ))
112215 return !!do_send_flush ();
113216
217+ if (!strcmp (subcmd , "hammer" ))
218+ return !!do_hammer (token , nr_threads , nr_requests );
219+
114220 die ("Unhandled subcommand: '%s'" , subcmd );
115221}
116222#endif
0 commit comments