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