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