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