Whamcloud - gitweb
LU-4629 utils: fix rsources leak
[fs/lustre-release.git] / lustre / utils / loadgen.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/loadgen.c
37  *
38  * See how many local OSCs we can start whaling on a OST
39  * We're doing direct ioctls instead of going though a system() call to lctl
40  * to avoid the bash overhead.
41  * Adds an osc / echo client pair in each thread and starts echo transactions.
42  *
43  * Author: Nathan Rutman <nathan@clusterfs.com>
44  */
45
46 #include <pthread.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <unistd.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <signal.h>
53 #include <fcntl.h>
54 #include <errno.h>
55 #include <string.h>
56 #include <sys/wait.h>
57 #include <time.h>
58 #include <sys/time.h>
59
60 #include <lnet/lnetctl.h>
61 #include <libcfs/libcfsutil.h>
62 #include "obdctl.h"
63
64 static char cmdname[512];
65 static char target[64] = "";
66 char nid[64] = "";
67 static int sig_received = 0;
68 static int o_verbose = 4; /* 0-5 */
69 static int my_oss = 0;
70 static int my_ecs = 0;
71
72 static int jt_quit(int argc, char **argv) {
73         Parser_quit(argc, argv);
74         return 0;
75 }
76
77 static int loadgen_usage(int argc, char **argv)
78 {
79         if (argc == 1) {
80                 fprintf(stderr,
81         "This is a test program used to simulate large numbers of\n"
82         "clients.  The echo obds are used, so the obdecho module must\n"
83         "be loaded.\n"
84         "Typical usage would be:\n"
85         "  loadgen> dev lustre-OST0000       set the target device\n"
86         "  loadgen> start 20                 start 20 echo clients\n"
87         "  loadgen> wr 10 5                  have 10 clients do the brw_write\n"
88         "                                      test 5 times each\n"
89                         );
90         }
91         return (Parser_help(argc, argv));
92 }
93
94 static int loadgen_verbose(int argc, char **argv);
95 static int loadgen_target(int argc, char **argv);
96 static int loadgen_start_echosrv(int argc, char **argv);
97 static int loadgen_start_clients(int argc, char **argv);
98 static int loadgen_wait(int argc, char **argv);
99 static int loadgen_write(int argc, char **argv);
100
101 command_t cmdlist[] = {
102         {"device", loadgen_target, 0,
103          "set target ost name (e.g. lustre-OST0000)\n"
104          "usage: device <name> [<nid>]"},
105         {"dl", jt_obd_list, 0, "show all devices\n"
106          "usage: dl"},
107         {"echosrv", loadgen_start_echosrv, 0, "start an echo server\n"},
108         {"start", loadgen_start_clients, 0, "set up echo clients\n"
109          "usage: start_clients <num>"},
110         {"verbose", loadgen_verbose, 0, "set verbosity level 0-5\n"
111          "usage: verbose <level>"},
112         {"wait", loadgen_wait, 0,
113          "wait for all threads to finish\n"},
114         {"write", loadgen_write, 0,
115          "start a test_brw write test on X clients for Y iterations\n"
116          "usage: write <num_clients> <num_iter> [<delay>]"},
117
118         /* User interface commands */
119         {"help", loadgen_usage, 0, "help"},
120         {"exit", jt_quit, 0, "quit"},
121         {"quit", jt_quit, 0, "quit"},
122         { 0, 0, 0, NULL }
123 };
124
125
126 /* Command flags */
127 #define C_STOP           0x0001
128 #define C_CREATE_EVERY   0x0002  /* destroy and recreate every time */
129 #define C_READ           0x0004
130 #define C_WRITE          0x0008
131
132 struct command_t {
133         int           c_flags;
134         int           c_rpt;
135         int           c_delay;
136 };
137
138 struct kid_t {
139         struct command_t k_cmd;
140         struct kid_t    *k_next;
141         pthread_t        k_pthread;
142         __u64            k_objid;
143         int              k_id;
144         int              k_dev;
145 };
146
147 static int live_threads = 0;
148 static struct kid_t *kid_list = NULL;
149 pthread_mutex_t m_list = PTHREAD_MUTEX_INITIALIZER;
150
151 static struct kid_t *push_kid(int tnum)
152 {
153         struct kid_t *kid;
154         kid = (struct kid_t *)calloc(1, sizeof(struct kid_t));
155         if (kid == NULL) {
156                 fprintf(stderr, "malloc failure\n");
157                 return NULL;
158         }
159         kid->k_pthread = pthread_self();
160         pthread_mutex_lock(&m_list);
161         kid->k_next = kid_list;
162         kid->k_id = tnum;
163         kid_list = kid;
164         live_threads++;
165         pthread_mutex_unlock(&m_list);
166         return kid;
167 }
168
169 int trigger_count = 0;
170 int waiting_count = 0;
171 int timer_on = 0;
172 int all_done = 1;
173 struct timeval trigger_start;
174 struct command_t trigger_cmd;
175 pthread_mutex_t m_trigger = PTHREAD_MUTEX_INITIALIZER;
176 pthread_cond_t cv_trigger = PTHREAD_COND_INITIALIZER;
177
178 unsigned long long write_bytes;
179 pthread_mutex_t m_count = PTHREAD_MUTEX_INITIALIZER;
180
181 static void trigger(int command, int threads, int repeat, int delay)
182 {
183
184         pthread_mutex_lock(&m_trigger);
185         trigger_cmd.c_flags = command;
186         trigger_cmd.c_rpt = repeat;
187         trigger_cmd.c_delay = delay;
188         trigger_count = threads;
189         if (o_verbose > 4)
190                 printf("trigger %d cmd c=%d f=%x\n", trigger_count,
191                        trigger_cmd.c_rpt, trigger_cmd.c_flags);
192         gettimeofday(&trigger_start, NULL);
193         timer_on = 1;
194         pthread_mutex_lock(&m_count);
195         write_bytes = 0;
196         pthread_mutex_unlock(&m_count);
197
198         pthread_cond_broadcast(&cv_trigger);
199         pthread_mutex_unlock(&m_trigger);
200 }
201
202 static __inline__ void stop_all(int unused)
203 {
204         sig_received++;
205 }
206
207 static void kill_kids(void)
208 {
209         struct kid_t *tmp = kid_list;
210
211         stop_all(SIGINT);
212         trigger(C_STOP, 0, 0, 0);
213         while(tmp) {
214                 pthread_kill(tmp->k_pthread, SIGTERM);
215                 tmp = tmp->k_next;
216         }
217 }
218
219 static void sig_master(int unused)
220 {
221         stop_all(SIGINT);
222         //jt_quit(0, NULL);
223 }
224
225 static int wait_for_threads()
226 {
227         struct kid_t *tmp = kid_list;
228         int rc = 0, status;
229         void *statusp;
230
231         printf("waiting for %d children\n", live_threads);
232
233         while(tmp) {
234                 rc = pthread_join(tmp->k_pthread, &statusp);
235                 status = (long)statusp;
236                 if (o_verbose > 2)
237                         printf("%d: joined, rc = %d, status = %d\n",
238                                tmp->k_id, rc, status);
239                 kid_list = tmp->k_next;
240                 free(tmp);
241                 tmp = kid_list;
242                 live_threads--;
243         }
244
245         if (o_verbose > 0)
246                 printf("%s done, rc = %d\n", cmdname, rc);
247         return rc;
248 }
249
250 static int write_proc(char *proc_path, char *value)
251 {
252         int fd, rc;
253
254         fd = open(proc_path, O_WRONLY);
255         if (fd == -1) {
256                 fprintf(stderr, "open('%s') failed: %s\n",
257                         proc_path, strerror(errno));
258                 rc = errno;
259         } else {
260                 rc = write(fd, value, strlen(value));
261                 if (rc < 0) {
262                         fprintf(stderr, "write('%s') failed: %s\n",
263                                 proc_path, strerror(errno));
264                 }
265                 close(fd);
266         }
267         return rc;
268 }
269
270 static int read_proc(char *proc_path,  unsigned long long *value)
271 {
272         int fd, rc;
273         char buf[50];
274
275         fd = open(proc_path, O_RDONLY);
276         if (fd == -1) {
277                 fprintf(stderr, "open('%s') failed: %s\n",
278                         proc_path, strerror(errno));
279                 return (errno);
280         }
281
282         rc = read(fd, buf, sizeof(buf));
283         close(fd);
284         if (errno == EOPNOTSUPP) {
285                 /* probably an echo server */
286                 return rc;
287         }
288         if (rc <= 0) {
289                 fprintf(stderr, "read('%s') failed: %s (%d)\n",
290                         proc_path, strerror(errno), errno);
291                 return rc;
292         }
293         *value = strtoull(buf, NULL, 10);
294         return 0;
295 }
296
297 static int grant_estimate(int thread)
298 {
299         unsigned long long avail, grant;
300         char proc_path[50];
301         int rc;
302         static int ran = 0;
303
304         /* I don't really care about protecting this with a mutex */
305         if (ran)
306                 return 0;
307
308         if (o_verbose < 2)
309                 return 0;
310
311         /* Divide /proc/fs/lustre/osc/o_0001/kbytesavail
312            by /proc/fs/lustre/osc/o_0001/cur_grant_bytes to find max clients */
313         sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/kbytesavail", thread);
314         rc = read_proc(proc_path, &avail);
315         if (rc)
316                 return rc;
317         sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/cur_grant_bytes", thread);
318         rc = read_proc(proc_path, &grant);
319         if (rc)
320                 return rc;
321         if (grant == 0) {
322                 return -EINVAL;
323         }
324         printf("Estimate %llu clients before we run out of grant space "
325                "(%lluK / %llu)\n", (avail << 10)  / grant, avail, grant);
326         ran++;
327         return 0;
328 }
329
330 /* We hold a thread mutex around create/cleanup because cur_dev is not
331    shared-memory safe */
332 pthread_mutex_t m_config = PTHREAD_MUTEX_INITIALIZER;
333
334 static int cleanup(char *obdname, int quiet)
335 {
336         char *args[3];
337         int rc;
338
339         pthread_mutex_lock(&m_config);
340
341         args[0] = cmdname;
342         args[1] = obdname;
343         rc = jt_lcfg_device(2, args);
344         if (rc && !quiet)
345                 fprintf(stderr, "%s: can't configure '%s' (%d)\n",
346                         cmdname, obdname, rc);
347         args[1] = "force";
348         rc = jt_obd_cleanup(2, args);
349         if (rc && !quiet)
350                 fprintf(stderr, "%s: can't cleanup '%s' (%d)\n",
351                         cmdname, obdname, rc);
352         rc = jt_obd_detach(1, args);
353         if (rc && !quiet)
354                 fprintf(stderr, "%s: can't detach '%s' (%d)\n",
355                         cmdname, obdname, rc);
356
357         pthread_mutex_unlock(&m_config);
358         return rc;
359 }
360
361 static int echocli_setup(char *oname, char *ename, int *dev)
362 {
363         char *args[5];
364         char proc_path[50];
365         int rc;
366
367         pthread_mutex_lock(&m_config);
368
369         args[0] = cmdname;
370
371         /* OSC */
372         /* attach "osc" oscname oscuuid */
373         args[1] = "osc";
374         args[2] = args[3] = oname;
375         rc = jt_lcfg_attach(4, args);
376         if (rc) {
377                 fprintf(stderr, "%s: can't attach osc '%s' (%d)\n",
378                         cmdname, oname, rc);
379                 /* Assume we want e.g. an old one cleaned anyhow. */
380                 goto clean;
381         }
382         /* setup ostname "OSS_UUID" */
383         args[1] = target;
384         args[2] = "OSS_UUID";
385         rc = jt_lcfg_setup(3, args);
386         if (rc) {
387                 fprintf(stderr, "%s: can't setup osc '%s' (%d)\n",
388                         cmdname, oname, rc);
389                 goto clean;
390         }
391
392         /* Large grants cause ENOSPC to be reported, even though
393            there's space left.  We can reduce the grant size by
394            minimizing these */
395         sprintf(proc_path, "/proc/fs/lustre/osc/%s/max_dirty_mb", oname);
396         rc = write_proc(proc_path, "1");
397         sprintf(proc_path, "/proc/fs/lustre/osc/%s/max_rpcs_in_flight", oname);
398         rc = write_proc(proc_path, "1");
399
400         /* ECHO CLI */
401         /* attach "echo_client" echoname echouuid */
402         args[1] = "echo_client";
403         args[2] = args[3] = ename;
404         rc = jt_lcfg_attach(4, args);
405         if (rc) {
406                 fprintf(stderr, "%s: can't attach '%s' (%d)\n",
407                         cmdname, ename, rc);
408                 if (rc == ENODEV)
409                         fprintf(stderr, "%s: is the obdecho module loaded?\n",
410                                 cmdname);
411                 goto clean;
412         }
413         /* setup oscname */
414         args[1] = oname;
415         rc = jt_lcfg_setup(2, args);
416         if (rc) {
417                 fprintf(stderr, "%s: can't setup '%s' (%d)\n",
418                         cmdname, ename, rc);
419                 goto clean;
420         }
421
422         args[1] = ename;
423         rc = jt_obd_device(2, args);
424         if (rc) {
425                 fprintf(stderr, "%s: can't set device '%s' (%d)\n",
426                         cmdname, ename, rc);
427                 goto clean;
428         }
429
430         if (!rc)
431                 *dev = jt_obd_get_device();
432         pthread_mutex_unlock(&m_config);
433         return rc;
434
435 clean:
436         pthread_mutex_unlock(&m_config);
437         cleanup(ename, 1);
438         cleanup(oname, 1);
439         return rc;
440 }
441
442 /* We can't use the libptlctl library fns because they are not shared-memory
443    safe with respect to the ioctl device (cur_dev) */
444 static int obj_ioctl(int cmd, struct obd_ioctl_data *data, int unpack)
445 {
446         char *buf = NULL;
447         int rc;
448
449         //IOC_PACK(cmdname, data);
450         if (obd_ioctl_pack(data, &buf, sizeof(*data))) {
451                 fprintf(stderr, "dev %d invalid ioctl\n", data->ioc_dev);
452                 rc = EINVAL;
453                 goto out;
454         }
455
456         rc = l_ioctl(OBD_DEV_ID, cmd, buf);
457
458         if (unpack) {
459                 //IOC_UNPACK(argv[0], data);
460                 if (obd_ioctl_unpack(data, buf, sizeof(*data))) {
461                         fprintf(stderr, "dev %d invalid reply\n", data->ioc_dev);
462                         rc = EINVAL;
463                         goto out;
464                 }
465         }
466
467 out:
468         if (buf)
469                 free(buf);
470         return rc;
471 }
472
473 /* See jt_obd_create */
474 static int obj_create(struct kid_t *kid)
475 {
476         struct obd_ioctl_data data;
477         int rc;
478
479         memset(&data, 0, sizeof(data));
480         data.ioc_dev = kid->k_dev;
481         data.ioc_obdo1.o_mode = 0100644;
482         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
483         ostid_set_id(&data.ioc_obdo1.o_oi, 1);
484         data.ioc_obdo1.o_uid = 0;
485         data.ioc_obdo1.o_gid = 0;
486         data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
487                         OBD_MD_FLID | OBD_MD_FLUID | OBD_MD_FLGID;
488
489         rc = obj_ioctl(OBD_IOC_CREATE, &data, 1);
490         if (rc) {
491                 fprintf(stderr, "%d: create (%d) %s\n",
492                         kid->k_id, rc, strerror(errno));
493                 return rc;
494         }
495
496         if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
497                 fprintf(stderr, "%d: create oid not valid "LPX64"\n",
498                         kid->k_id, data.ioc_obdo1.o_valid);
499                 return rc;
500         }
501
502         kid->k_objid = ostid_id(&data.ioc_obdo1.o_oi);
503
504         if (o_verbose > 4)
505                 printf("%d: cr "LPX64"\n", kid->k_id, kid->k_objid);
506
507         return rc;
508 }
509
510 /* See jt_obd_destroy */
511 static int obj_delete(struct kid_t *kid)
512 {
513         struct obd_ioctl_data data;
514         int rc;
515
516         if (o_verbose > 4)
517                 printf("%d: del "LPX64"\n", kid->k_id, kid->k_objid);
518
519         memset(&data, 0, sizeof(data));
520         data.ioc_dev = kid->k_dev;
521         ostid_set_id(&data.ioc_obdo1.o_oi, kid->k_objid);
522         data.ioc_obdo1.o_mode = S_IFREG | 0644;
523         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
524
525         rc = obj_ioctl(OBD_IOC_DESTROY, &data, 1);
526         if (rc)
527                 fprintf(stderr, "%s-%d: can't destroy obj "LPX64" (%d)\n",
528                         cmdname, kid->k_id, kid->k_objid, rc);
529
530         kid->k_objid = 0;
531         return rc;
532 }
533
534 #define difftime(a, b)                                  \
535         ((a)->tv_sec - (b)->tv_sec +                    \
536          ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
537
538 /* See jt_obd_test_brw */
539 static int obj_write(struct kid_t *kid)
540 {
541         struct obd_ioctl_data data;
542         struct timeval start;
543         __u64 count, len;
544         int rc = 0, i, pages = 0;
545
546         if (o_verbose > 4)
547                 printf("%d: wr "LPX64"\n", kid->k_id, kid->k_objid);
548
549         count = 10;
550         pages = 32;
551         len = pages * getpagesize();
552
553         memset(&data, 0, sizeof(data));
554         data.ioc_dev = kid->k_dev;
555         /* communicate the 'type' of brw test and batching to echo_client.
556          * don't start.  we'd love to refactor this lctl->echo_client
557          * interface */
558         data.ioc_pbuf1 = (void *)1;
559         data.ioc_plen1 = 1;
560
561         ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
562         ostid_set_id(&data.ioc_obdo1.o_oi, kid->k_objid);
563         data.ioc_obdo1.o_mode = S_IFREG;
564         data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
565                                  OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
566         data.ioc_obdo1.o_flags = OBD_FL_DEBUG_CHECK;
567         data.ioc_count = len;
568         data.ioc_offset = 0;
569
570         gettimeofday(&start, NULL);
571
572         for (i = 1; i <= count; i++) {
573                 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
574                 rc = obj_ioctl(OBD_IOC_BRW_WRITE, &data, 0);
575                 if (rc) {
576                         fprintf(stderr, "%d: write %s\n", kid->k_id,
577                                 strerror(rc = errno));
578                         break;
579                 }
580
581                 data.ioc_offset += len;
582         }
583
584         if (!rc) {
585                 struct timeval end;
586                 double diff;
587
588                 gettimeofday(&end, NULL);
589                 diff = difftime(&end, &start);
590
591                 --i;
592
593                 pthread_mutex_lock(&m_count);
594                 write_bytes += i * len;
595                 pthread_mutex_unlock(&m_count);
596
597                 if (o_verbose > 4)
598                         printf("%d: wrote %dx%d pages in %.3fs (%.3f MB/s): %s",
599                                kid->k_id, i, pages, diff,
600                                ((double)i * len) / (diff * 1048576.0),
601                                ctime(&end.tv_sec));
602         }
603
604         if (rc)
605                 fprintf(stderr, "%s-%d: err test_brw obj "LPX64" (%d)\n",
606                         cmdname, kid->k_id, kid->k_objid, rc);
607         return rc;
608 }
609
610 static int do_work(struct kid_t *kid)
611 {
612         int rc = 0, err, iter = 0;
613
614         if (!(kid->k_cmd.c_flags & C_CREATE_EVERY))
615                 rc = obj_create(kid);
616
617         for (iter = 0; iter < kid->k_cmd.c_rpt; iter++) {
618                 if (rc || sig_received)
619                         break;
620
621                 if (kid->k_cmd.c_flags & C_CREATE_EVERY) {
622                         rc = obj_create(kid);
623                         if (rc)
624                                 break;
625                 }
626
627                 if (kid->k_cmd.c_flags & C_WRITE) {
628                         rc = obj_write(kid);
629                         grant_estimate(kid->k_id);
630                 }
631
632                 if (kid->k_cmd.c_flags & C_CREATE_EVERY) {
633                         err = obj_delete(kid);
634                         if (!rc) rc = err;
635                 }
636
637                 if ((o_verbose > 3) && (iter % 10 == 0))
638                         printf("%d: i%d\n", kid->k_id, iter);
639                 if (!rc)
640                         sleep(kid->k_cmd.c_delay);
641         }
642
643         if (!(kid->k_cmd.c_flags & C_CREATE_EVERY)) {
644                 err = obj_delete(kid);
645                 if (!rc) rc = err;
646         }
647
648         if (o_verbose > 2)
649                 printf("%d: done (%d)\n", kid->k_id, rc);
650
651         return rc;
652 }
653
654 static void report_perf()
655 {
656         struct timeval end;
657         double diff;
658
659         gettimeofday(&end, NULL);
660         diff = difftime(&end, &trigger_start);
661         if (o_verbose > 2) {
662                 pthread_mutex_lock(&m_count);
663                 printf("wrote %lluMB in %.3fs (%.3f MB/s)\n",
664                        write_bytes >> 20, diff,
665                        (write_bytes >> 20) / diff);
666                 pthread_mutex_unlock(&m_count);
667         }
668 }
669
670 static void *run_one_child(void *threadvp)
671 {
672         struct kid_t *kid;
673         char oname[10], ename[10];
674         int thread = (long)threadvp, dev = 0;
675         int rc = 0, err;
676
677         if (o_verbose > 2)
678                 printf("%s: running thread #%d\n", cmdname, thread);
679
680         sprintf(oname, "o%.5d", thread);
681         sprintf(ename, "e%.5d", thread);
682         rc = echocli_setup(oname, ename, &dev);
683         if (rc) {
684                 fprintf(stderr, "%s: can't setup '%s/%s' (%d)\n",
685                         cmdname, oname, ename, rc);
686                 pthread_exit((void *)(long)rc);
687         }
688
689         kid = push_kid(thread);
690         if (!kid) {
691                 rc = -ENOMEM;
692                 goto out;
693         }
694         kid->k_dev = dev;
695
696         while(!(rc || sig_received)) {
697                 pthread_mutex_lock(&m_trigger);
698                 pthread_mutex_lock(&m_list);
699                 waiting_count++;
700                 if ((waiting_count == live_threads) && timer_on) {
701                         report_perf();
702                         timer_on = 0;
703                         all_done = 1;
704                 }
705                 pthread_mutex_unlock(&m_list);
706                 pthread_cond_wait(&cv_trigger, &m_trigger);
707                 waiting_count--;
708                 all_done = 0;
709
710                 /* First trigger_count threads will do the work, the rest
711                    will block again */
712                 if (trigger_count) {
713                         if (o_verbose > 4)
714                                 printf("%d: trigger %d cmd %x\n",
715                                        kid->k_id, trigger_count,
716                                        trigger_cmd.c_flags);
717                         trigger_count--;
718                         memcpy(&kid->k_cmd, &trigger_cmd, sizeof(trigger_cmd));
719                         pthread_mutex_unlock(&m_trigger);
720                         rc = do_work(kid);
721                 } else {
722                         pthread_mutex_unlock(&m_trigger);
723                 }
724         }
725
726         if (o_verbose > 1)
727                 printf("%s: thread #%d done (%d)\n", cmdname, thread, rc);
728
729         if (rc)
730                 stop_all(SIGINT);
731
732 out:
733         err = cleanup(ename, 0);
734         if (!rc) rc = err;
735         err = cleanup(oname, 0);
736         if (!rc) rc = err;
737
738         pthread_exit((void *)(long)rc);
739 }
740
741 /* 
742  * PTHREAD_STACK_MIN is 16K minimal stack for threads. This
743  * is stack consumed by one thread, which executes NULL procedure.
744  * We need some more here and 20k stack for one client thread
745  * is enough to not overflow. In same time it does not consume
746  * a lot of memory for large number of threads.
747  *
748  * 20K virtual clients will only consume 320M + 400M. Still to
749  * create this number of virtual clients we need to fix 8192
750  * OBDs limit.
751  */
752 #define CLIENT_THREAD_STACK_SIZE (PTHREAD_STACK_MIN + (20 * 1024))
753
754 static int loadgen_start_clients(int argc, char **argv)
755 {
756         int rc = 0, i, numt;
757         struct timespec ts = {0, 1000*1000*100}; /* .1 sec */
758         pthread_attr_t attr;
759
760         if (argc != 2)
761                 return CMD_HELP;
762
763         numt = strtoul(argv[1], NULL, 0);
764         if (numt < 1)
765                 return CMD_HELP;
766
767         if (!target[0]) {
768                 fprintf(stderr, "%s: target OST is not defined, use 'device' "
769                         "command\n", cmdname);
770                 return -EINVAL;
771         }
772
773         rc = pthread_attr_init(&attr);
774         if (rc) {
775                 fprintf(stderr, "%s: pthread_attr_init:(%d) %s\n",
776                         cmdname, rc, strerror(errno));
777                 return -errno;
778         }
779         pthread_attr_setstacksize (&attr, CLIENT_THREAD_STACK_SIZE);
780         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
781
782         numt += live_threads;
783         i = live_threads;
784         printf("start %d to %d\n", i, numt);
785         while(!rc && !sig_received && (i < numt)) {
786                 pthread_t thread;
787
788                 i++;
789                 rc = pthread_create(&thread, &attr, run_one_child,
790                                     (void *)(long)i);
791                 if (rc) {
792                         fprintf(stderr, "%s: pthread: #%d - (%d) %s\n",
793                                 cmdname, i, rc, strerror(rc));
794                         break;
795                 }
796
797                 /* give them slightly different start times */
798                 nanosleep(&ts, NULL);
799         }
800
801         pthread_attr_destroy(&attr);
802
803         return -rc;
804 }
805
806 static int loadgen_target(int argc, char **argv)
807 {
808         char *args[3];
809         __u64 nidx = 0;
810         int rc = 0;
811
812         if (argc < 2 || argc > 3)
813                 return CMD_HELP;
814
815         args[0] = cmdname;
816
817         if (argc == 3) {
818                 nidx = libcfs_str2nid(argv[2]);
819                 if (nidx == LNET_NID_ANY) {
820                         fprintf(stderr, "%s: invalid nid '%s'\n",
821                                 cmdname, argv[2]);
822                         return -EINVAL;
823                 }
824         } else {
825                 /* Local device should be in list */
826                 args[1] = argv[1];
827                 rc = jt_obd_device(2, args);
828                 if (rc) {
829                         fprintf(stderr, "%s: local device '%s' doesn't "
830                                 "seem to exist. You must use obdfilter device "
831                                 "names like 'lustre-OST0000'.  Use 'dl' to "
832                                 "list all devices.\n",
833                                 cmdname, argv[1]);
834                         return -EINVAL;
835                 }
836
837                 /* Use the first local nid */
838                 args[1] = (char *)(&nidx);
839                 args[1][0] = 1; /* hack to get back first nid */
840                 rc = jt_ptl_list_nids(2, args);
841                 if (rc) {
842                         fprintf(stderr, "%s: can't get local nid (%d)\n",
843                                 cmdname, rc);
844                         return rc;
845                 }
846         }
847         if (strcmp(nid, libcfs_nid2str(nidx)) != 0) {
848                 /* if new, do an add_uuid */
849                 sprintf(nid, "%s", libcfs_nid2str(nidx));
850
851                 /* Fixme change the uuid for every new one */
852                 args[1] = "OSS_UUID";
853                 args[2] = nid;
854                 rc = jt_lcfg_add_uuid(3, args);
855                 if (rc) {
856                         fprintf(stderr, "%s: can't add uuid '%s' (%d)\n",
857                                 cmdname, args[2], rc);
858                         return rc;
859                 }
860         }
861
862         snprintf(target, sizeof(target), "%s", argv[1]);
863         printf("Target OST name is '%s'\n", target);
864
865         return rc;
866 }
867
868 static int loadgen_verbose(int argc, char **argv)
869 {
870         if (argc != 2)
871                 return CMD_HELP;
872         o_verbose = atoi(argv[1]);
873         printf("verbosity set to %d\n", o_verbose);
874         return 0;
875 }
876
877 static int loadgen_write(int argc, char **argv)
878 {
879         int threads;
880
881         if (argc < 3 || argc > 4)
882                 return CMD_HELP;
883         threads = atoi(argv[1]);
884         pthread_mutex_lock(&m_list);
885         if (threads > live_threads) {
886                 pthread_mutex_unlock(&m_list);
887                 fprintf(stderr, "requested %d threads but only %d are running. "
888                         "Use 'start' to start some more.\n",
889                         threads, live_threads);
890                 return -EOVERFLOW;
891         } else {
892                 pthread_mutex_unlock(&m_list);
893         }
894         trigger(C_WRITE, threads, atoi(argv[2]),
895                 (argc == 4) ? atoi(argv[3]) : 0);
896         return 0;
897 }
898
899 char ecsname[] = "echosrv";
900 static int loadgen_stop_echosrv(int argc, char **argv)
901 {
902         int verbose = (argc != 9);
903         if (my_oss) {
904                 char name[]="OSS";
905                 cleanup(name, verbose);
906                 my_oss = 0;
907         }
908         if (my_ecs || (argc == 9)) {
909                 cleanup(ecsname, verbose);
910                 my_ecs = 0;
911         }
912         return 0;
913 }
914
915 static int loadgen_start_echosrv(int argc, char **argv)
916 {
917         char *args[5];
918         int rc;
919
920         pthread_mutex_lock(&m_config);
921
922         args[0] = cmdname;
923
924         /* attach obdecho echosrv echosrv_UUID */
925         args[1] = "obdecho";
926         args[2] = args[3] = ecsname;
927         rc = jt_lcfg_attach(4, args);
928         if (rc) {
929                 fprintf(stderr, "%s: can't attach echo server (%d)\n",
930                         cmdname, rc);
931                 /* Assume we want e.g. an old one cleaned anyhow. */
932                 goto clean;
933         }
934         my_ecs = 1;
935
936         /* setup */
937         rc = jt_lcfg_setup(1, args);
938         if (rc) {
939                 fprintf(stderr, "%s: can't setup echo server (%d)\n",
940                         cmdname, rc);
941                 goto clean;
942         }
943
944         /* Create an OSS to handle the communications */
945         /* attach ost OSS OSS_UUID */
946         args[1] = "ost";
947         args[2] = args[3] = "OSS";
948
949         rc = jt_lcfg_attach(4, args);
950         if (rc == EEXIST) {
951                 /* Already set up for somebody else, that's fine. */
952                 printf("OSS already set up, no problem.\n");
953                 pthread_mutex_unlock(&m_config);
954                 return 0;
955         }
956         if (rc) {
957                 fprintf(stderr, "%s: can't attach OSS (%d)\n",
958                         cmdname, rc);
959                 goto clean;
960         }
961         my_oss = 1;
962
963         /* setup */
964         rc = jt_lcfg_setup(1, args);
965         if (rc) {
966                 fprintf(stderr, "%s: can't setup OSS (%d)\n",
967                         cmdname, rc);
968                 goto clean;
969         }
970
971         pthread_mutex_unlock(&m_config);
972         return rc;
973
974 clean:
975         pthread_mutex_unlock(&m_config);
976         loadgen_stop_echosrv(9, argv);
977         return rc;
978 }
979
980 static int loadgen_wait(int argc, char **argv)
981 {
982         /* Give scripts a chance to start some threads */
983         sleep(1);
984         while (!all_done) {
985                 sleep(1);
986         }
987         return 0;
988 }
989
990 static int loadgen_init(int argc, char **argv)
991 {
992         char *args[4];
993         int rc;
994
995         sprintf(cmdname, "%s", argv[0]);
996
997         signal(SIGTERM, sig_master);
998         signal(SIGINT, sig_master);
999
1000         /* Test to make sure obdecho module is loaded */
1001         args[0] = cmdname;
1002         args[1] = "echo_client";
1003         args[2] = args[3] = "ecc_test";
1004         rc = jt_lcfg_attach(4, args);
1005         if (rc) {
1006                 fprintf(stderr, "%s: can't attach echo client (%d)\n",
1007                         cmdname, rc);
1008                 if (rc == ENODEV)
1009                         fprintf(stderr, "%s: is the obdecho module loaded?\n",
1010                                 cmdname);
1011         } else {
1012                 args[1] = args[2];
1013                 jt_obd_detach(1, args);
1014         }
1015
1016         return rc;
1017 }
1018
1019 static int loadgen_exit()
1020 {
1021         int rc;
1022
1023         printf("stopping %d children\n", live_threads);
1024         kill_kids();
1025         rc = wait_for_threads();
1026
1027         loadgen_stop_echosrv(0, NULL);
1028
1029         return rc;
1030 }
1031
1032 /* libptlctl interface */
1033 static int loadgen_main(int argc, char **argv)
1034 {
1035         int rc;
1036
1037         setlinebuf(stdout);
1038         /* without this threaded errors cause segfault */
1039         setlinebuf(stderr);
1040
1041         if ((rc = ptl_initialize(argc, argv)) < 0)
1042                 exit(rc);
1043         if ((rc = obd_initialize(argc, argv)) < 0)
1044                 exit(rc);
1045         if ((rc = dbg_initialize(argc, argv)) < 0)
1046                 exit(rc);
1047
1048         Parser_init("loadgen> ", cmdlist);
1049
1050         rc = loadgen_init(argc, argv);
1051         if (rc)
1052                 goto out;
1053
1054         if (argc > 1) {
1055                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1056         } else {
1057                 rc = Parser_commands();
1058         }
1059
1060         rc = loadgen_exit();
1061
1062 out:
1063         obd_finalize(argc, argv);
1064         return rc < 0 ? -rc : rc;
1065 }
1066
1067 #ifndef LIBLUSTRE_TEST
1068 int main (int argc, char **argv)
1069 {
1070         int rc;
1071         rc = loadgen_main(argc, argv);
1072         pthread_exit((void *)(long)rc);
1073
1074         return rc;
1075 }
1076 #endif