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