Whamcloud - gitweb
LU-4629 lov: fix sscanf format specification
[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[16], ename[16];
675         int thread = (long)threadvp;
676         int dev = 0;
677         int err;
678         int rc;
679
680         if (o_verbose > 2)
681                 printf("%s: running thread #%d\n", cmdname, thread);
682
683         rc = snprintf(oname, sizeof(oname), "o%.5d", thread);
684         if (rc != 1) {
685                 rc = -EFAULT;
686                 goto out_exit;
687         }
688         rc = snprintf(ename, sizeof(ename), "e%.5d", thread);
689         if (rc != 1) {
690                 rc = -EFAULT;
691                 goto out_exit;
692         }
693         rc = echocli_setup(oname, ename, &dev);
694         if (rc) {
695                 fprintf(stderr, "%s: can't setup '%s/%s' (%d)\n",
696                         cmdname, oname, ename, rc);
697                 goto out_exit;
698         }
699
700         kid = push_kid(thread);
701         if (!kid) {
702                 rc = -ENOMEM;
703                 goto out;
704         }
705         kid->k_dev = dev;
706
707         while(!(rc || sig_received)) {
708                 pthread_mutex_lock(&m_trigger);
709                 pthread_mutex_lock(&m_list);
710                 waiting_count++;
711                 if ((waiting_count == live_threads) && timer_on) {
712                         report_perf();
713                         timer_on = 0;
714                         all_done = 1;
715                 }
716                 pthread_mutex_unlock(&m_list);
717                 pthread_cond_wait(&cv_trigger, &m_trigger);
718                 waiting_count--;
719                 all_done = 0;
720
721                 /* First trigger_count threads will do the work, the rest
722                    will block again */
723                 if (trigger_count) {
724                         if (o_verbose > 4)
725                                 printf("%d: trigger %d cmd %x\n",
726                                        kid->k_id, trigger_count,
727                                        trigger_cmd.c_flags);
728                         trigger_count--;
729                         memcpy(&kid->k_cmd, &trigger_cmd, sizeof(trigger_cmd));
730                         pthread_mutex_unlock(&m_trigger);
731                         rc = do_work(kid);
732                 } else {
733                         pthread_mutex_unlock(&m_trigger);
734                 }
735         }
736
737         if (o_verbose > 1)
738                 printf("%s: thread #%d done (%d)\n", cmdname, thread, rc);
739
740         if (rc)
741                 stop_all(SIGINT);
742
743 out:
744         err = cleanup(ename, 0);
745         if (!rc) rc = err;
746         err = cleanup(oname, 0);
747         if (!rc) rc = err;
748
749 out_exit:
750         pthread_exit((void *)(long)rc);
751 }
752
753 /* 
754  * PTHREAD_STACK_MIN is 16K minimal stack for threads. This
755  * is stack consumed by one thread, which executes NULL procedure.
756  * We need some more here and 20k stack for one client thread
757  * is enough to not overflow. In same time it does not consume
758  * a lot of memory for large number of threads.
759  *
760  * 20K virtual clients will only consume 320M + 400M. Still to
761  * create this number of virtual clients we need to fix 8192
762  * OBDs limit.
763  */
764 #define CLIENT_THREAD_STACK_SIZE (PTHREAD_STACK_MIN + (20 * 1024))
765
766 static int loadgen_start_clients(int argc, char **argv)
767 {
768         int rc = 0, i, numt;
769         struct timespec ts = {0, 1000*1000*100}; /* .1 sec */
770         pthread_attr_t attr;
771
772         if (argc != 2)
773                 return CMD_HELP;
774
775         numt = strtoul(argv[1], NULL, 0);
776         if (numt < 1)
777                 return CMD_HELP;
778
779         if (!target[0]) {
780                 fprintf(stderr, "%s: target OST is not defined, use 'device' "
781                         "command\n", cmdname);
782                 return -EINVAL;
783         }
784
785         rc = pthread_attr_init(&attr);
786         if (rc) {
787                 fprintf(stderr, "%s: pthread_attr_init:(%d) %s\n",
788                         cmdname, rc, strerror(errno));
789                 return -errno;
790         }
791         pthread_attr_setstacksize (&attr, CLIENT_THREAD_STACK_SIZE);
792         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
793
794         numt += live_threads;
795         i = live_threads;
796         printf("start %d to %d\n", i, numt);
797         while(!rc && !sig_received && (i < numt)) {
798                 pthread_t thread;
799
800                 i++;
801                 rc = pthread_create(&thread, &attr, run_one_child,
802                                     (void *)(long)i);
803                 if (rc) {
804                         fprintf(stderr, "%s: pthread: #%d - (%d) %s\n",
805                                 cmdname, i, rc, strerror(rc));
806                         break;
807                 }
808
809                 /* give them slightly different start times */
810                 nanosleep(&ts, NULL);
811         }
812
813         pthread_attr_destroy(&attr);
814
815         return -rc;
816 }
817
818 static int loadgen_target(int argc, char **argv)
819 {
820         char *args[3];
821         __u64 nidx = 0;
822         int rc = 0;
823
824         if (argc < 2 || argc > 3)
825                 return CMD_HELP;
826
827         args[0] = cmdname;
828
829         if (argc == 3) {
830                 nidx = libcfs_str2nid(argv[2]);
831                 if (nidx == LNET_NID_ANY) {
832                         fprintf(stderr, "%s: invalid nid '%s'\n",
833                                 cmdname, argv[2]);
834                         return -EINVAL;
835                 }
836         } else {
837                 /* Local device should be in list */
838                 args[1] = argv[1];
839                 rc = jt_obd_device(2, args);
840                 if (rc) {
841                         fprintf(stderr, "%s: local device '%s' doesn't "
842                                 "seem to exist. You must use obdfilter device "
843                                 "names like 'lustre-OST0000'.  Use 'dl' to "
844                                 "list all devices.\n",
845                                 cmdname, argv[1]);
846                         return -EINVAL;
847                 }
848
849                 /* Use the first local nid */
850                 args[1] = (char *)(&nidx);
851                 args[1][0] = 1; /* hack to get back first nid */
852                 rc = jt_ptl_list_nids(2, args);
853                 if (rc) {
854                         fprintf(stderr, "%s: can't get local nid (%d)\n",
855                                 cmdname, rc);
856                         return rc;
857                 }
858         }
859         if (strcmp(nid, libcfs_nid2str(nidx)) != 0) {
860                 /* if new, do an add_uuid */
861                 sprintf(nid, "%s", libcfs_nid2str(nidx));
862
863                 /* Fixme change the uuid for every new one */
864                 args[1] = "OSS_UUID";
865                 args[2] = nid;
866                 rc = jt_lcfg_add_uuid(3, args);
867                 if (rc) {
868                         fprintf(stderr, "%s: can't add uuid '%s' (%d)\n",
869                                 cmdname, args[2], rc);
870                         return rc;
871                 }
872         }
873
874         snprintf(target, sizeof(target), "%s", argv[1]);
875         printf("Target OST name is '%s'\n", target);
876
877         return rc;
878 }
879
880 static int loadgen_verbose(int argc, char **argv)
881 {
882         if (argc != 2)
883                 return CMD_HELP;
884         o_verbose = atoi(argv[1]);
885         printf("verbosity set to %d\n", o_verbose);
886         return 0;
887 }
888
889 static int loadgen_write(int argc, char **argv)
890 {
891         int threads;
892
893         if (argc < 3 || argc > 4)
894                 return CMD_HELP;
895         threads = atoi(argv[1]);
896         pthread_mutex_lock(&m_list);
897         if (threads > live_threads) {
898                 pthread_mutex_unlock(&m_list);
899                 fprintf(stderr, "requested %d threads but only %d are running. "
900                         "Use 'start' to start some more.\n",
901                         threads, live_threads);
902                 return -EOVERFLOW;
903         } else {
904                 pthread_mutex_unlock(&m_list);
905         }
906         trigger(C_WRITE, threads, atoi(argv[2]),
907                 (argc == 4) ? atoi(argv[3]) : 0);
908         return 0;
909 }
910
911 char ecsname[] = "echosrv";
912 static int loadgen_stop_echosrv(int argc, char **argv)
913 {
914         int verbose = (argc != 9);
915         if (my_oss) {
916                 char name[]="OSS";
917                 cleanup(name, verbose);
918                 my_oss = 0;
919         }
920         if (my_ecs || (argc == 9)) {
921                 cleanup(ecsname, verbose);
922                 my_ecs = 0;
923         }
924         return 0;
925 }
926
927 static int loadgen_start_echosrv(int argc, char **argv)
928 {
929         char *args[5];
930         int rc;
931
932         pthread_mutex_lock(&m_config);
933
934         args[0] = cmdname;
935
936         /* attach obdecho echosrv echosrv_UUID */
937         args[1] = "obdecho";
938         args[2] = args[3] = ecsname;
939         rc = jt_lcfg_attach(4, args);
940         if (rc) {
941                 fprintf(stderr, "%s: can't attach echo server (%d)\n",
942                         cmdname, rc);
943                 /* Assume we want e.g. an old one cleaned anyhow. */
944                 goto clean;
945         }
946         my_ecs = 1;
947
948         /* setup */
949         rc = jt_lcfg_setup(1, args);
950         if (rc) {
951                 fprintf(stderr, "%s: can't setup echo server (%d)\n",
952                         cmdname, rc);
953                 goto clean;
954         }
955
956         /* Create an OSS to handle the communications */
957         /* attach ost OSS OSS_UUID */
958         args[1] = "ost";
959         args[2] = args[3] = "OSS";
960
961         rc = jt_lcfg_attach(4, args);
962         if (rc == EEXIST) {
963                 /* Already set up for somebody else, that's fine. */
964                 printf("OSS already set up, no problem.\n");
965                 pthread_mutex_unlock(&m_config);
966                 return 0;
967         }
968         if (rc) {
969                 fprintf(stderr, "%s: can't attach OSS (%d)\n",
970                         cmdname, rc);
971                 goto clean;
972         }
973         my_oss = 1;
974
975         /* setup */
976         rc = jt_lcfg_setup(1, args);
977         if (rc) {
978                 fprintf(stderr, "%s: can't setup OSS (%d)\n",
979                         cmdname, rc);
980                 goto clean;
981         }
982
983         pthread_mutex_unlock(&m_config);
984         return rc;
985
986 clean:
987         pthread_mutex_unlock(&m_config);
988         loadgen_stop_echosrv(9, argv);
989         return rc;
990 }
991
992 static int loadgen_wait(int argc, char **argv)
993 {
994         /* Give scripts a chance to start some threads */
995         sleep(1);
996         while (!all_done) {
997                 sleep(1);
998         }
999         return 0;
1000 }
1001
1002 static int loadgen_init(int argc, char **argv)
1003 {
1004         char *args[4];
1005         int rc;
1006
1007         sprintf(cmdname, "%s", argv[0]);
1008
1009         signal(SIGTERM, sig_master);
1010         signal(SIGINT, sig_master);
1011
1012         /* Test to make sure obdecho module is loaded */
1013         args[0] = cmdname;
1014         args[1] = "echo_client";
1015         args[2] = args[3] = "ecc_test";
1016         rc = jt_lcfg_attach(4, args);
1017         if (rc) {
1018                 fprintf(stderr, "%s: can't attach echo client (%d)\n",
1019                         cmdname, rc);
1020                 if (rc == ENODEV)
1021                         fprintf(stderr, "%s: is the obdecho module loaded?\n",
1022                                 cmdname);
1023         } else {
1024                 args[1] = args[2];
1025                 jt_obd_detach(1, args);
1026         }
1027
1028         return rc;
1029 }
1030
1031 static int loadgen_exit()
1032 {
1033         int rc;
1034
1035         printf("stopping %d children\n", live_threads);
1036         kill_kids();
1037         rc = wait_for_threads();
1038
1039         loadgen_stop_echosrv(0, NULL);
1040
1041         return rc;
1042 }
1043
1044 /* libptlctl interface */
1045 static int loadgen_main(int argc, char **argv)
1046 {
1047         int rc;
1048
1049         setlinebuf(stdout);
1050         /* without this threaded errors cause segfault */
1051         setlinebuf(stderr);
1052
1053         if ((rc = ptl_initialize(argc, argv)) < 0)
1054                 exit(rc);
1055         if ((rc = obd_initialize(argc, argv)) < 0)
1056                 exit(rc);
1057         if ((rc = dbg_initialize(argc, argv)) < 0)
1058                 exit(rc);
1059
1060         Parser_init("loadgen> ", cmdlist);
1061
1062         rc = loadgen_init(argc, argv);
1063         if (rc)
1064                 goto out;
1065
1066         if (argc > 1) {
1067                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1068         } else {
1069                 rc = Parser_commands();
1070         }
1071
1072         rc = loadgen_exit();
1073
1074 out:
1075         obd_finalize(argc, argv);
1076         return rc < 0 ? -rc : rc;
1077 }
1078
1079 #ifndef LIBLUSTRE_TEST
1080 int main (int argc, char **argv)
1081 {
1082         int rc;
1083         rc = loadgen_main(argc, argv);
1084         pthread_exit((void *)(long)rc);
1085
1086         return rc;
1087 }
1088 #endif