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