4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
30 * Copyright (c) 2013, Intel Corporation.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/utils/loadgen.c
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.
43 * Author: Nathan Rutman <nathan@clusterfs.com>
50 #include <sys/types.h>
60 #include <lnet/lnetctl.h>
61 #include <lnet/nidstr.h>
62 #include <libcfs/libcfsutil.h>
63 #include <lustre_ioctl.h>
66 static char cmdname[512];
67 static char target[64] = "";
69 static int sig_received = 0;
70 static int o_verbose = 4; /* 0-5 */
71 static int my_oss = 0;
72 static int my_ecs = 0;
74 static int jt_quit(int argc, char **argv) {
75 Parser_quit(argc, argv);
79 static int loadgen_usage(int argc, char **argv)
83 "This is a test program used to simulate large numbers of\n"
84 "clients. The echo obds are used, so the obdecho module must\n"
86 "Typical usage would be:\n"
87 " loadgen> dev lustre-OST0000 set the target device\n"
88 " loadgen> start 20 start 20 echo clients\n"
89 " loadgen> wr 10 5 have 10 clients do the brw_write\n"
90 " test 5 times each\n"
93 return (Parser_help(argc, argv));
96 static int loadgen_verbose(int argc, char **argv);
97 static int loadgen_target(int argc, char **argv);
98 static int loadgen_start_echosrv(int argc, char **argv);
99 static int loadgen_start_clients(int argc, char **argv);
100 static int loadgen_wait(int argc, char **argv);
101 static int loadgen_write(int argc, char **argv);
103 command_t cmdlist[] = {
104 {"device", loadgen_target, 0,
105 "set target ost name (e.g. lustre-OST0000)\n"
106 "usage: device <name> [<nid>]"},
107 {"dl", jt_obd_list, 0, "show all devices\n"
109 {"echosrv", loadgen_start_echosrv, 0, "start an echo server\n"},
110 {"start", loadgen_start_clients, 0, "set up echo clients\n"
111 "usage: start_clients <num>"},
112 {"verbose", loadgen_verbose, 0, "set verbosity level 0-5\n"
113 "usage: verbose <level>"},
114 {"wait", loadgen_wait, 0,
115 "wait for all threads to finish\n"},
116 {"write", loadgen_write, 0,
117 "start a test_brw write test on X clients for Y iterations\n"
118 "usage: write <num_clients> <num_iter> [<delay>]"},
120 /* User interface commands */
121 {"help", loadgen_usage, 0, "help"},
122 {"exit", jt_quit, 0, "quit"},
123 {"quit", jt_quit, 0, "quit"},
129 #define C_STOP 0x0001
130 #define C_CREATE_EVERY 0x0002 /* destroy and recreate every time */
131 #define C_READ 0x0004
132 #define C_WRITE 0x0008
141 struct command_t k_cmd;
142 struct kid_t *k_next;
149 static int live_threads = 0;
150 static struct kid_t *kid_list = NULL;
151 pthread_mutex_t m_list = PTHREAD_MUTEX_INITIALIZER;
153 static struct kid_t *push_kid(int tnum)
156 kid = (struct kid_t *)calloc(1, sizeof(struct kid_t));
158 fprintf(stderr, "malloc failure\n");
161 kid->k_pthread = pthread_self();
162 pthread_mutex_lock(&m_list);
163 kid->k_next = kid_list;
167 pthread_mutex_unlock(&m_list);
171 int trigger_count = 0;
172 int waiting_count = 0;
175 struct timeval trigger_start;
176 struct command_t trigger_cmd;
177 pthread_mutex_t m_trigger = PTHREAD_MUTEX_INITIALIZER;
178 pthread_cond_t cv_trigger = PTHREAD_COND_INITIALIZER;
180 unsigned long long write_bytes;
181 pthread_mutex_t m_count = PTHREAD_MUTEX_INITIALIZER;
183 static void trigger(int command, int threads, int repeat, int delay)
186 pthread_mutex_lock(&m_trigger);
187 trigger_cmd.c_flags = command;
188 trigger_cmd.c_rpt = repeat;
189 trigger_cmd.c_delay = delay;
190 trigger_count = threads;
192 printf("trigger %d cmd c=%d f=%x\n", trigger_count,
193 trigger_cmd.c_rpt, trigger_cmd.c_flags);
194 gettimeofday(&trigger_start, NULL);
196 pthread_mutex_lock(&m_count);
198 pthread_mutex_unlock(&m_count);
200 pthread_cond_broadcast(&cv_trigger);
201 pthread_mutex_unlock(&m_trigger);
204 static __inline__ void stop_all(int unused)
209 static void kill_kids(void)
211 struct kid_t *tmp = kid_list;
214 trigger(C_STOP, 0, 0, 0);
216 pthread_kill(tmp->k_pthread, SIGTERM);
221 static void sig_master(int unused)
227 static int wait_for_threads()
229 struct kid_t *tmp = kid_list;
233 printf("waiting for %d children\n", live_threads);
236 rc = pthread_join(tmp->k_pthread, &statusp);
237 status = (long)statusp;
239 printf("%d: joined, rc = %d, status = %d\n",
240 tmp->k_id, rc, status);
241 kid_list = tmp->k_next;
248 printf("%s done, rc = %d\n", cmdname, rc);
252 static int write_proc(char *proc_path, char *value)
256 fd = open(proc_path, O_WRONLY);
258 fprintf(stderr, "open('%s') failed: %s\n",
259 proc_path, strerror(errno));
262 rc = write(fd, value, strlen(value));
264 fprintf(stderr, "write('%s') failed: %s\n",
265 proc_path, strerror(errno));
272 static int read_proc(char *proc_path, unsigned long long *value)
277 fd = open(proc_path, O_RDONLY);
279 fprintf(stderr, "open('%s') failed: %s\n",
280 proc_path, strerror(errno));
284 rc = read(fd, buf, sizeof(buf));
286 if (errno == EOPNOTSUPP) {
287 /* probably an echo server */
291 fprintf(stderr, "read('%s') failed: %s (%d)\n",
292 proc_path, strerror(errno), errno);
295 *value = strtoull(buf, NULL, 10);
299 static int grant_estimate(int thread)
301 unsigned long long avail, grant;
306 /* I don't really care about protecting this with a mutex */
313 /* Divide /proc/fs/lustre/osc/o_0001/kbytesavail
314 by /proc/fs/lustre/osc/o_0001/cur_grant_bytes to find max clients */
315 sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/kbytesavail", thread);
316 rc = read_proc(proc_path, &avail);
319 sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/cur_grant_bytes", thread);
320 rc = read_proc(proc_path, &grant);
326 printf("Estimate %llu clients before we run out of grant space "
327 "(%lluK / %llu)\n", (avail << 10) / grant, avail, grant);
332 /* We hold a thread mutex around create/cleanup because cur_dev is not
333 shared-memory safe */
334 pthread_mutex_t m_config = PTHREAD_MUTEX_INITIALIZER;
336 static int cleanup(char *obdname, int quiet)
341 pthread_mutex_lock(&m_config);
345 rc = jt_lcfg_device(2, args);
347 fprintf(stderr, "%s: can't configure '%s' (%d)\n",
348 cmdname, obdname, rc);
350 rc = jt_obd_cleanup(2, args);
352 fprintf(stderr, "%s: can't cleanup '%s' (%d)\n",
353 cmdname, obdname, rc);
354 rc = jt_obd_detach(1, args);
356 fprintf(stderr, "%s: can't detach '%s' (%d)\n",
357 cmdname, obdname, rc);
359 pthread_mutex_unlock(&m_config);
363 static int echocli_setup(char *oname, char *ename, int *dev)
369 pthread_mutex_lock(&m_config);
374 /* attach "osc" oscname oscuuid */
376 args[2] = args[3] = oname;
377 rc = jt_lcfg_attach(4, args);
379 fprintf(stderr, "%s: can't attach osc '%s' (%d)\n",
381 /* Assume we want e.g. an old one cleaned anyhow. */
384 /* setup ostname "OSS_UUID" */
386 args[2] = "OSS_UUID";
387 rc = jt_lcfg_setup(3, args);
389 fprintf(stderr, "%s: can't setup osc '%s' (%d)\n",
394 /* Large grants cause ENOSPC to be reported, even though
395 there's space left. We can reduce the grant size by
397 sprintf(proc_path, "/proc/fs/lustre/osc/%s/max_dirty_mb", oname);
398 rc = write_proc(proc_path, "1");
399 sprintf(proc_path, "/proc/fs/lustre/osc/%s/max_rpcs_in_flight", oname);
400 rc = write_proc(proc_path, "1");
403 /* attach "echo_client" echoname echouuid */
404 args[1] = "echo_client";
405 args[2] = args[3] = ename;
406 rc = jt_lcfg_attach(4, args);
408 fprintf(stderr, "%s: can't attach '%s' (%d)\n",
411 fprintf(stderr, "%s: is the obdecho module loaded?\n",
417 rc = jt_lcfg_setup(2, args);
419 fprintf(stderr, "%s: can't setup '%s' (%d)\n",
425 rc = jt_obd_device(2, args);
427 fprintf(stderr, "%s: can't set device '%s' (%d)\n",
433 *dev = jt_obd_get_device();
434 pthread_mutex_unlock(&m_config);
438 pthread_mutex_unlock(&m_config);
444 /* We can't use the libptlctl library fns because they are not shared-memory
445 safe with respect to the ioctl device (cur_dev) */
446 static int obj_ioctl(int cmd, struct obd_ioctl_data *data, int unpack)
451 //IOC_PACK(cmdname, data);
452 if (obd_ioctl_pack(data, &buf, sizeof(*data))) {
453 fprintf(stderr, "dev %d invalid ioctl\n", data->ioc_dev);
458 rc = l_ioctl(OBD_DEV_ID, cmd, buf);
461 //IOC_UNPACK(argv[0], data);
462 if (obd_ioctl_unpack(data, buf, sizeof(*data))) {
463 fprintf(stderr, "dev %d invalid reply\n", data->ioc_dev);
475 /* See jt_obd_create */
476 static int obj_create(struct kid_t *kid)
478 struct obd_ioctl_data data;
481 memset(&data, 0, sizeof(data));
482 data.ioc_dev = kid->k_dev;
483 data.ioc_obdo1.o_mode = 0100644;
484 ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
485 ostid_set_id(&data.ioc_obdo1.o_oi, 1);
486 data.ioc_obdo1.o_uid = 0;
487 data.ioc_obdo1.o_gid = 0;
488 data.ioc_obdo1.o_valid = OBD_MD_FLTYPE | OBD_MD_FLMODE |
489 OBD_MD_FLID | OBD_MD_FLUID | OBD_MD_FLGID;
491 rc = obj_ioctl(OBD_IOC_CREATE, &data, 1);
493 fprintf(stderr, "%d: create (%d) %s\n",
494 kid->k_id, rc, strerror(errno));
498 if (!(data.ioc_obdo1.o_valid & OBD_MD_FLID)) {
499 fprintf(stderr, "%d: create oid not valid "LPX64"\n",
500 kid->k_id, data.ioc_obdo1.o_valid);
504 kid->k_objid = ostid_id(&data.ioc_obdo1.o_oi);
507 printf("%d: cr "LPX64"\n", kid->k_id, kid->k_objid);
512 /* See jt_obd_destroy */
513 static int obj_delete(struct kid_t *kid)
515 struct obd_ioctl_data data;
519 printf("%d: del "LPX64"\n", kid->k_id, kid->k_objid);
521 memset(&data, 0, sizeof(data));
522 data.ioc_dev = kid->k_dev;
523 ostid_set_id(&data.ioc_obdo1.o_oi, kid->k_objid);
524 data.ioc_obdo1.o_mode = S_IFREG | 0644;
525 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLMODE;
527 rc = obj_ioctl(OBD_IOC_DESTROY, &data, 1);
529 fprintf(stderr, "%s-%d: can't destroy obj "LPX64" (%d)\n",
530 cmdname, kid->k_id, kid->k_objid, rc);
536 #define difftime(a, b) \
537 ((a)->tv_sec - (b)->tv_sec + \
538 ((a)->tv_usec - (b)->tv_usec) / 1000000.0)
540 /* See jt_obd_test_brw */
541 static int obj_write(struct kid_t *kid)
543 struct obd_ioctl_data data;
544 struct timeval start;
546 int rc = 0, i, pages = 0;
549 printf("%d: wr "LPX64"\n", kid->k_id, kid->k_objid);
553 len = pages * getpagesize();
555 memset(&data, 0, sizeof(data));
556 data.ioc_dev = kid->k_dev;
557 /* communicate the 'type' of brw test and batching to echo_client.
558 * don't start. we'd love to refactor this lctl->echo_client
560 data.ioc_pbuf1 = (void *)1;
563 ostid_set_seq_echo(&data.ioc_obdo1.o_oi);
564 ostid_set_id(&data.ioc_obdo1.o_oi, kid->k_objid);
565 data.ioc_obdo1.o_mode = S_IFREG;
566 data.ioc_obdo1.o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLMODE |
567 OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
568 data.ioc_obdo1.o_flags = OBD_FL_DEBUG_CHECK;
569 data.ioc_count = len;
572 gettimeofday(&start, NULL);
574 for (i = 1; i <= count; i++) {
575 data.ioc_obdo1.o_valid &= ~(OBD_MD_FLBLOCKS|OBD_MD_FLGRANT);
576 rc = obj_ioctl(OBD_IOC_BRW_WRITE, &data, 0);
578 fprintf(stderr, "%d: write %s\n", kid->k_id,
579 strerror(rc = errno));
583 data.ioc_offset += len;
590 gettimeofday(&end, NULL);
591 diff = difftime(&end, &start);
595 pthread_mutex_lock(&m_count);
596 write_bytes += i * len;
597 pthread_mutex_unlock(&m_count);
600 printf("%d: wrote %dx%d pages in %.3fs (%.3f MB/s): %s",
601 kid->k_id, i, pages, diff,
602 ((double)i * len) / (diff * 1048576.0),
607 fprintf(stderr, "%s-%d: err test_brw obj "LPX64" (%d)\n",
608 cmdname, kid->k_id, kid->k_objid, rc);
612 static int do_work(struct kid_t *kid)
614 int rc = 0, err, iter = 0;
616 if (!(kid->k_cmd.c_flags & C_CREATE_EVERY))
617 rc = obj_create(kid);
619 for (iter = 0; iter < kid->k_cmd.c_rpt; iter++) {
620 if (rc || sig_received)
623 if (kid->k_cmd.c_flags & C_CREATE_EVERY) {
624 rc = obj_create(kid);
629 if (kid->k_cmd.c_flags & C_WRITE) {
631 grant_estimate(kid->k_id);
634 if (kid->k_cmd.c_flags & C_CREATE_EVERY) {
635 err = obj_delete(kid);
639 if ((o_verbose > 3) && (iter % 10 == 0))
640 printf("%d: i%d\n", kid->k_id, iter);
642 sleep(kid->k_cmd.c_delay);
645 if (!(kid->k_cmd.c_flags & C_CREATE_EVERY)) {
646 err = obj_delete(kid);
651 printf("%d: done (%d)\n", kid->k_id, rc);
656 static void report_perf()
661 gettimeofday(&end, NULL);
662 diff = difftime(&end, &trigger_start);
664 pthread_mutex_lock(&m_count);
665 printf("wrote %lluMB in %.3fs (%.3f MB/s)\n",
666 write_bytes >> 20, diff,
667 (write_bytes >> 20) / diff);
668 pthread_mutex_unlock(&m_count);
672 static void *run_one_child(void *threadvp)
675 char oname[16], ename[16];
676 int thread = (long)threadvp;
682 printf("%s: running thread #%d\n", cmdname, thread);
684 rc = snprintf(oname, sizeof(oname), "o%.5d", thread);
689 rc = snprintf(ename, sizeof(ename), "e%.5d", thread);
694 rc = echocli_setup(oname, ename, &dev);
696 fprintf(stderr, "%s: can't setup '%s/%s' (%d)\n",
697 cmdname, oname, ename, rc);
701 kid = push_kid(thread);
708 while(!(rc || sig_received)) {
709 pthread_mutex_lock(&m_trigger);
710 pthread_mutex_lock(&m_list);
712 if ((waiting_count == live_threads) && timer_on) {
717 pthread_mutex_unlock(&m_list);
718 pthread_cond_wait(&cv_trigger, &m_trigger);
722 /* First trigger_count threads will do the work, the rest
726 printf("%d: trigger %d cmd %x\n",
727 kid->k_id, trigger_count,
728 trigger_cmd.c_flags);
730 memcpy(&kid->k_cmd, &trigger_cmd, sizeof(trigger_cmd));
731 pthread_mutex_unlock(&m_trigger);
734 pthread_mutex_unlock(&m_trigger);
739 printf("%s: thread #%d done (%d)\n", cmdname, thread, rc);
745 err = cleanup(ename, 0);
747 err = cleanup(oname, 0);
751 pthread_exit((void *)(long)rc);
755 * PTHREAD_STACK_MIN is 16K minimal stack for threads. This
756 * is stack consumed by one thread, which executes NULL procedure.
757 * We need some more here and 20k stack for one client thread
758 * is enough to not overflow. In same time it does not consume
759 * a lot of memory for large number of threads.
761 * 20K virtual clients will only consume 320M + 400M. Still to
762 * create this number of virtual clients we need to fix 8192
765 #define CLIENT_THREAD_STACK_SIZE (PTHREAD_STACK_MIN + (20 * 1024))
767 static int loadgen_start_clients(int argc, char **argv)
770 struct timespec ts = {0, 1000*1000*100}; /* .1 sec */
776 numt = strtoul(argv[1], NULL, 0);
781 fprintf(stderr, "%s: target OST is not defined, use 'device' "
782 "command\n", cmdname);
786 rc = pthread_attr_init(&attr);
788 fprintf(stderr, "%s: pthread_attr_init:(%d) %s\n",
789 cmdname, rc, strerror(errno));
792 pthread_attr_setstacksize (&attr, CLIENT_THREAD_STACK_SIZE);
793 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
795 numt += live_threads;
797 printf("start %d to %d\n", i, numt);
798 while(!rc && !sig_received && (i < numt)) {
802 rc = pthread_create(&thread, &attr, run_one_child,
805 fprintf(stderr, "%s: pthread: #%d - (%d) %s\n",
806 cmdname, i, rc, strerror(rc));
810 /* give them slightly different start times */
811 nanosleep(&ts, NULL);
814 pthread_attr_destroy(&attr);
819 static int loadgen_target(int argc, char **argv)
825 if (argc < 2 || argc > 3)
831 nidx = libcfs_str2nid(argv[2]);
832 if (nidx == LNET_NID_ANY) {
833 fprintf(stderr, "%s: invalid nid '%s'\n",
838 /* Local device should be in list */
840 rc = jt_obd_device(2, args);
842 fprintf(stderr, "%s: local device '%s' doesn't "
843 "seem to exist. You must use obdfilter device "
844 "names like 'lustre-OST0000'. Use 'dl' to "
845 "list all devices.\n",
850 /* Use the first local nid */
851 args[1] = (char *)(&nidx);
852 args[1][0] = 1; /* hack to get back first nid */
853 rc = jt_ptl_list_nids(2, args);
855 fprintf(stderr, "%s: can't get local nid (%d)\n",
860 if (strcmp(nid, libcfs_nid2str(nidx)) != 0) {
861 /* if new, do an add_uuid */
862 sprintf(nid, "%s", libcfs_nid2str(nidx));
864 /* Fixme change the uuid for every new one */
865 args[1] = "OSS_UUID";
867 rc = jt_lcfg_add_uuid(3, args);
869 fprintf(stderr, "%s: can't add uuid '%s' (%d)\n",
870 cmdname, args[2], rc);
875 snprintf(target, sizeof(target), "%s", argv[1]);
876 printf("Target OST name is '%s'\n", target);
881 static int loadgen_verbose(int argc, char **argv)
885 o_verbose = atoi(argv[1]);
886 printf("verbosity set to %d\n", o_verbose);
890 static int loadgen_write(int argc, char **argv)
894 if (argc < 3 || argc > 4)
896 threads = atoi(argv[1]);
897 pthread_mutex_lock(&m_list);
898 if (threads > live_threads) {
899 pthread_mutex_unlock(&m_list);
900 fprintf(stderr, "requested %d threads but only %d are running. "
901 "Use 'start' to start some more.\n",
902 threads, live_threads);
905 pthread_mutex_unlock(&m_list);
907 trigger(C_WRITE, threads, atoi(argv[2]),
908 (argc == 4) ? atoi(argv[3]) : 0);
912 char ecsname[] = "echosrv";
913 static int loadgen_stop_echosrv(int argc, char **argv)
915 int verbose = (argc != 9);
918 cleanup(name, verbose);
921 if (my_ecs || (argc == 9)) {
922 cleanup(ecsname, verbose);
928 static int loadgen_start_echosrv(int argc, char **argv)
933 pthread_mutex_lock(&m_config);
937 /* attach obdecho echosrv echosrv_UUID */
939 args[2] = args[3] = ecsname;
940 rc = jt_lcfg_attach(4, args);
942 fprintf(stderr, "%s: can't attach echo server (%d)\n",
944 /* Assume we want e.g. an old one cleaned anyhow. */
950 rc = jt_lcfg_setup(1, args);
952 fprintf(stderr, "%s: can't setup echo server (%d)\n",
957 /* Create an OSS to handle the communications */
958 /* attach ost OSS OSS_UUID */
960 args[2] = args[3] = "OSS";
962 rc = jt_lcfg_attach(4, args);
964 /* Already set up for somebody else, that's fine. */
965 printf("OSS already set up, no problem.\n");
966 pthread_mutex_unlock(&m_config);
970 fprintf(stderr, "%s: can't attach OSS (%d)\n",
977 rc = jt_lcfg_setup(1, args);
979 fprintf(stderr, "%s: can't setup OSS (%d)\n",
984 pthread_mutex_unlock(&m_config);
988 pthread_mutex_unlock(&m_config);
989 loadgen_stop_echosrv(9, argv);
993 static int loadgen_wait(int argc, char **argv)
995 /* Give scripts a chance to start some threads */
1003 static int loadgen_init(int argc, char **argv)
1008 sprintf(cmdname, "%s", argv[0]);
1010 signal(SIGTERM, sig_master);
1011 signal(SIGINT, sig_master);
1013 /* Test to make sure obdecho module is loaded */
1015 args[1] = "echo_client";
1016 args[2] = args[3] = "ecc_test";
1017 rc = jt_lcfg_attach(4, args);
1019 fprintf(stderr, "%s: can't attach echo client (%d)\n",
1022 fprintf(stderr, "%s: is the obdecho module loaded?\n",
1026 jt_obd_detach(1, args);
1032 static int loadgen_exit()
1036 printf("stopping %d children\n", live_threads);
1038 rc = wait_for_threads();
1040 loadgen_stop_echosrv(0, NULL);
1045 /* libptlctl interface */
1046 static int loadgen_main(int argc, char **argv)
1051 /* without this threaded errors cause segfault */
1054 if ((rc = ptl_initialize(argc, argv)) < 0)
1056 if ((rc = obd_initialize(argc, argv)) < 0)
1058 if ((rc = dbg_initialize(argc, argv)) < 0)
1061 Parser_init("loadgen> ", cmdlist);
1063 rc = loadgen_init(argc, argv);
1068 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1070 rc = Parser_commands();
1073 rc = loadgen_exit();
1076 obd_finalize(argc, argv);
1077 return rc < 0 ? -rc : rc;
1080 #ifndef LIBLUSTRE_TEST
1081 int main (int argc, char **argv)
1084 rc = loadgen_main(argc, argv);
1085 pthread_exit((void *)(long)rc);