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