1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2006 Cluster File Systems, Inc.
5 * Author: Nathan Rutman <nathan@clusterfs.com>
7 * This file is part of Lustre, http://www.lustre.org.
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.
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.
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.
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.
34 #include <sys/types.h>
44 #include <lnet/lnetctl.h>
48 static char cmdname[512];
49 static char target[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;
57 static int jt_quit(int argc, char **argv) {
58 Parser_quit(argc, argv);
62 static int loadgen_usage(int argc, char **argv)
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"
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"
76 return (Parser_help(argc, argv));
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);
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"
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>]"},
100 /* User interface commands */
101 {"help", loadgen_usage, 0, "help"},
102 {"exit", jt_quit, 0, "quit"},
103 {"quit", jt_quit, 0, "quit"},
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
121 struct command_t k_cmd;
122 struct kid_t *k_next;
129 static struct kid_t *kid_list = NULL;
131 static struct kid_t *push_kid(int tnum)
134 kid = (struct kid_t *)calloc(1, sizeof(struct kid_t));
136 fprintf(stderr, "malloc failure\n");
139 kid->k_pthread = pthread_self();
140 kid->k_next = kid_list;
147 int trigger_count = 0;
148 int waiting_count = 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;
155 unsigned long long write_bytes;
156 pthread_mutex_t m_count = PTHREAD_MUTEX_INITIALIZER;
158 static void trigger(struct command_t *cmd, int count)
161 pthread_mutex_lock(&m_trigger);
163 trigger_count = count;
164 gettimeofday(&trigger_start, NULL);
166 pthread_mutex_lock(&m_count);
168 pthread_mutex_unlock(&m_count);
170 pthread_cond_broadcast(&cv_trigger);
171 pthread_mutex_unlock(&m_trigger);
174 static __inline__ void stop_all(int unused)
179 static void kill_kids(void)
181 struct command_t cmd;
182 struct kid_t *tmp = kid_list;
185 cmd.c_flags = C_STOP;
188 pthread_kill(tmp->k_pthread, SIGTERM);
193 static void sig_master(int unused)
199 static int wait_for_threads()
201 struct kid_t *tmp = kid_list;
205 printf("waiting for %d children\n", live_threads);
208 rc = pthread_join(tmp->k_pthread, &statusp);
209 status = (long)statusp;
211 printf("%d: joined, rc = %d, status = %d\n",
212 tmp->k_id, rc, status);
213 kid_list = tmp->k_next;
220 printf("%s done, rc = %d\n", cmdname, rc);
224 static int write_proc(char *proc_path, char *value)
228 fd = open(proc_path, O_WRONLY);
230 fprintf(stderr, "open('%s') failed: %s\n",
231 proc_path, strerror(errno));
234 rc = write(fd, value, strlen(value));
236 fprintf(stderr, "write('%s') failed: %s\n",
237 proc_path, strerror(errno));
244 static int read_proc(char *proc_path, long long *value)
249 fd = open(proc_path, O_RDONLY);
251 fprintf(stderr, "open('%s') failed: %s\n",
252 proc_path, strerror(errno));
256 rc = read(fd, buf, sizeof(buf));
258 if (errno == EOPNOTSUPP) {
259 /* probably an echo server */
263 fprintf(stderr, "read('%s') failed: %s (%d)\n",
264 proc_path, strerror(errno), errno);
267 *value = strtoull(buf, NULL, 10);
271 static int grant_estimate(int thread)
273 unsigned long long avail, grant;
278 /* I don't really care about protecting this with a mutex */
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);
291 sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/cur_grant_bytes", thread);
292 rc = read_proc(proc_path, &grant);
298 printf("Estimate %llu clients before we run out of grant space "
299 "(%lluK / %llu)\n", (avail << 10) / grant, avail, grant);
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;
308 static int cleanup(char *obdname, int quiet)
313 pthread_mutex_lock(&m_config);
317 rc = jt_lcfg_device(2, args);
319 fprintf(stderr, "%s: can't configure '%s' (%d)\n",
320 cmdname, obdname, rc);
322 rc = jt_obd_cleanup(2, args);
324 fprintf(stderr, "%s: can't cleanup '%s' (%d)\n",
325 cmdname, obdname, rc);
326 rc = jt_obd_detach(1, args);
328 fprintf(stderr, "%s: can't detach '%s' (%d)\n",
329 cmdname, obdname, rc);
331 pthread_mutex_unlock(&m_config);
335 static int echocli_setup(char *oname, char *ename, int *dev)
341 pthread_mutex_lock(&m_config);
346 /* attach "osc" oscname oscuuid */
348 args[2] = args[3] = oname;
349 rc = jt_lcfg_attach(4, args);
351 fprintf(stderr, "%s: can't attach osc '%s' (%d)\n",
353 /* Assume we want e.g. an old one cleaned anyhow. */
356 /* setup ostname "OSS_UUID" */
358 args[2] = "OSS_UUID";
359 rc = jt_lcfg_setup(3, args);
361 fprintf(stderr, "%s: can't setup osc '%s' (%d)\n",
366 /* Large grants cause ENOSPC to be reported, even though
367 there's space left. We can reduce the grant size by
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");
375 /* attach "echo_client" echoname echouuid */
376 args[1] = "echo_client";
377 args[2] = args[3] = ename;
378 rc = jt_lcfg_attach(4, args);
380 fprintf(stderr, "%s: can't attach '%s' (%d)\n",
383 fprintf(stderr, "%s: is the obdecho module loaded?\n",
389 rc = jt_lcfg_setup(2, args);
391 fprintf(stderr, "%s: can't setup '%s' (%d)\n",
397 rc = jt_obd_device(2, args);
399 fprintf(stderr, "%s: can't set device '%s' (%d)\n",
405 *dev = jt_obd_get_device();
406 pthread_mutex_unlock(&m_config);
410 pthread_mutex_unlock(&m_config);
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)
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);
430 rc = l_ioctl(OBD_DEV_ID, cmd, buf);
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);
447 /* See jt_obd_create */
448 static int obj_create(struct kid_t *kid)
450 struct obd_ioctl_data data;
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;
462 rc = obj_ioctl(OBD_IOC_CREATE, &data, 1);
464 fprintf(stderr, "%d: create (%d) %s\n",
465 kid->k_id, rc, strerror(errno));
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);
475 kid->k_objid = data.ioc_obdo1.o_id;
478 printf("%d: cr "LPX64"\n", kid->k_id, kid->k_objid);
483 /* See jt_obd_destroy */
484 static int obj_delete(struct kid_t *kid)
486 struct obd_ioctl_data data;
490 printf("%d: del "LPU64"\n", kid->k_id, kid->k_objid);
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;
498 rc = obj_ioctl(OBD_IOC_DESTROY, &data, 1);
500 fprintf(stderr, "%s-%d: can't destroy obj "LPU64" (%d)\n",
501 cmdname, kid->k_id, kid->k_objid, rc);
507 #define difftime(a, b) \
508 ((a)->tv_sec - (b)->tv_sec + \
509 ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
511 /* See jt_obd_test_brw */
512 static int obj_write(struct kid_t *kid)
514 struct obd_ioctl_data data;
515 struct timeval start;
517 int rc = 0, i, pages = 0;
520 printf("%d: wr "LPX64"\n", kid->k_id, kid->k_objid);
524 len = pages * getpagesize();
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
531 data.ioc_pbuf1 = (void *)1;
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 |
538 data.ioc_obdo1.o_flags = OBD_FL_DEBUG_CHECK;
539 data.ioc_count = len;
542 gettimeofday(&start, NULL);
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);
548 fprintf(stderr, "%d: write %s\n", kid->k_id,
549 strerror(rc = errno));
553 data.ioc_offset += len;
560 gettimeofday(&end, NULL);
561 diff = difftime(&end, &start);
565 pthread_mutex_lock(&m_count);
566 write_bytes += i * len;
567 pthread_mutex_unlock(&m_count);
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),
577 fprintf(stderr, "%s-%d: err test_brw obj "LPX64" (%d)\n",
578 cmdname, kid->k_id, kid->k_objid, rc);
582 static int do_work(struct kid_t *kid)
584 int rc = 0, err, iter = 0;
586 if (!(kid->k_cmd.c_flags & C_CREATE_EVERY))
587 rc = obj_create(kid);
589 for (iter = 0; iter < kid->k_cmd.c_count; iter++) {
590 if (rc || sig_received)
593 if (kid->k_cmd.c_flags & C_CREATE_EVERY) {
594 rc = obj_create(kid);
599 if (kid->k_cmd.c_flags & C_WRITE) {
601 grant_estimate(kid->k_id);
604 if (kid->k_cmd.c_flags & C_CREATE_EVERY) {
605 err = obj_delete(kid);
609 if ((o_verbose > 3) && (iter % 10 == 0))
610 printf("%d: i%d\n", kid->k_id, iter);
612 sleep(kid->k_cmd.c_delay);
615 if (!(kid->k_cmd.c_flags & C_CREATE_EVERY)) {
616 err = obj_delete(kid);
621 printf("%d: done (%d)\n", kid->k_id, rc);
626 static void report_perf()
631 gettimeofday(&end, NULL);
632 diff = difftime(&end, &trigger_start);
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);
643 static void *run_one_child(void *threadvp)
646 char oname[10], ename[10];
647 int thread = (long)threadvp, dev;
651 printf("%s: running thread #%d\n", cmdname, thread);
653 sprintf(oname, "o%.5d", thread);
654 sprintf(ename, "e%.5d", thread);
655 rc = echocli_setup(oname, ename, &dev);
657 fprintf(stderr, "%s: can't setup '%s/%s' (%d)\n",
658 cmdname, oname, ename, rc);
659 pthread_exit((void *)(long)rc);
662 kid = push_kid(thread);
669 while(!(rc || sig_received)) {
670 pthread_mutex_lock(&m_trigger);
672 if ((waiting_count == live_threads) && timer_on)
675 pthread_cond_wait(&cv_trigger, &m_trigger);
678 /* First trigger_count threads will do the work, the rest
682 printf("%d: trigger %d cmd %x\n",
683 kid->k_id, trigger_count,
684 trigger_cmd->c_flags);
686 kid->k_cmd = *trigger_cmd;
687 pthread_mutex_unlock(&m_trigger);
690 pthread_mutex_unlock(&m_trigger);
695 printf("%s: thread #%d done (%d)\n", cmdname, thread, rc);
701 err = cleanup(ename, 0);
703 err = cleanup(oname, 0);
706 pthread_exit((void *)(long)rc);
709 static int loadgen_start_clients(int argc, char **argv)
712 struct timespec ts = {0, 1000*1000*100}; /* .1 sec */
718 numt = strtoul(argv[1], NULL, 0);
723 fprintf(stderr, "%s: target OST is not defined, use 'device' "
724 "command\n", cmdname);
728 rc = pthread_attr_init(&attr);
730 fprintf(stderr, "%s: pthread_attr_init:(%d) %s\n",
731 cmdname, rc, strerror(errno));
734 pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN);
735 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
737 numt += live_threads;
739 printf("start %d to %d\n", i, numt);
740 while(!rc && !sig_received && (i < numt)) {
744 rc = pthread_create(&thread, &attr, run_one_child,
747 fprintf(stderr, "%s: pthread: #%d - (%d) %s\n",
748 cmdname, i, rc, strerror(rc));
752 /* give them slightly different start times */
753 nanosleep(&ts, NULL);
756 pthread_attr_destroy(&attr);
761 static int loadgen_target(int argc, char **argv)
767 if (argc < 2 || argc > 3)
773 nidx = libcfs_str2nid(argv[2]);
774 if (nidx == LNET_NID_ANY) {
775 fprintf(stderr, "%s: invalid nid '%s'\n",
780 /* Local device should be in list */
782 rc = jt_obd_device(2, args);
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",
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);
797 fprintf(stderr, "%s: can't get local nid (%d)\n",
802 if (strcmp(nid, libcfs_nid2str(nidx)) != 0) {
803 /* if new, do an add_uuid */
804 sprintf(nid, "%s", libcfs_nid2str(nidx));
806 /* Fixme change the uuid for every new one */
807 args[1] = "OSS_UUID";
809 rc = jt_lcfg_add_uuid(3, args);
811 fprintf(stderr, "%s: can't add uuid '%s' (%d)\n",
812 cmdname, args[2], rc);
817 snprintf(target, sizeof(target), "%s", argv[1]);
818 printf("Target OST name is '%s'\n", target);
823 static int loadgen_verbose(int argc, char **argv)
827 o_verbose = atoi(argv[1]);
828 printf("verbosity set to %d\n", o_verbose);
832 static int loadgen_write(int argc, char **argv)
834 struct command_t cmd;
837 if (argc < 3 || argc > 4)
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);
846 cmd.c_flags = C_WRITE;
847 cmd.c_count = atoi(argv[2]);
849 cmd.c_delay = atoi(argv[3]);
850 trigger(&cmd, threads);
854 char ecsname[] = "echosrv";
855 static int loadgen_stop_echosrv(int argc, char **argv)
857 int verbose = (argc != 9);
860 cleanup(name, verbose);
863 if (my_ecs || (argc == 9)) {
864 cleanup(ecsname, verbose);
870 static int loadgen_start_echosrv(int argc, char **argv)
875 pthread_mutex_lock(&m_config);
879 /* attach obdecho echosrv echosrv_UUID */
881 args[2] = args[3] = ecsname;
882 rc = jt_lcfg_attach(4, args);
884 fprintf(stderr, "%s: can't attach echo server (%d)\n",
886 /* Assume we want e.g. an old one cleaned anyhow. */
892 rc = jt_lcfg_setup(1, args);
894 fprintf(stderr, "%s: can't setup echo server (%d)\n",
899 /* Create an OSS to handle the communications */
900 /* attach ost OSS OSS_UUID */
902 args[2] = args[3] = "OSS";
904 rc = jt_lcfg_attach(4, args);
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);
912 fprintf(stderr, "%s: can't attach OSS (%d)\n",
919 rc = jt_lcfg_setup(1, args);
921 fprintf(stderr, "%s: can't setup OSS (%d)\n",
926 pthread_mutex_unlock(&m_config);
930 pthread_mutex_unlock(&m_config);
931 loadgen_stop_echosrv(9, argv);
935 static int loadgen_init(int argc, char **argv)
940 sprintf(cmdname, "%s", argv[0]);
942 signal(SIGTERM, sig_master);
943 signal(SIGINT, sig_master);
945 /* Test to make sure obdecho module is loaded */
947 args[1] = "echo_client";
948 args[2] = args[3] = "ecc_test";
949 rc = jt_lcfg_attach(4, args);
951 fprintf(stderr, "%s: can't attach echo client (%d)\n",
954 fprintf(stderr, "%s: is the obdecho module loaded?\n",
958 jt_obd_detach(1, args);
964 static int loadgen_exit()
968 printf("stopping %d children\n", live_threads);
970 rc = wait_for_threads();
972 loadgen_stop_echosrv(0, NULL);
977 /* libptlctl interface */
978 static int loadgen_main(int argc, char **argv)
983 /* without this threaded errors cause segfault */
986 if ((rc = ptl_initialize(argc, argv)) < 0)
988 if ((rc = obd_initialize(argc, argv)) < 0)
990 if ((rc = dbg_initialize(argc, argv)) < 0)
993 Parser_init("loadgen> ", cmdlist);
995 rc = loadgen_init(argc, argv);
1000 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1002 rc = Parser_commands();
1005 rc = loadgen_exit();
1008 obd_finalize(argc, argv);
1012 #ifndef LIBLUSTRE_TEST
1013 int main (int argc, char **argv)
1016 rc = loadgen_main(argc, argv);
1017 pthread_exit((void *)(long)rc);