loadgen.c

来自「lustre 1.6.5 source code」· C语言 代码 · 共 1,038 行 · 第 1/3 页

C
1,038
字号
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * *   Copyright (C) 2006 Cluster File Systems, Inc. *   Author: Nathan Rutman <nathan@clusterfs.com> * *   This file is part of Lustre, http://www.lustre.org. * *   Lustre is free software; you can redistribute it and/or *   modify it under the terms of version 2 of the GNU General Public *   License as published by the Free Software Foundation. * *   Lustre is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with Lustre; if not, write to the Free Software *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * loadgen.c * See how many local OSCs we can start whaling on a OST * We're doing direct ioctls instead of going though a system() call to lctl * to avoid the bash overhead. * Adds an osc / echo client pair in each thread and starts echo transactions. * */#include <pthread.h>#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <signal.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <sys/wait.h>#include <time.h>#include <sys/time.h>#include <lnet/lnetctl.h>#include "parser.h"#include "obdctl.h"static char cmdname[512];static char target[64] = "";char nid[64] = "";static int live_threads = 0;static int sig_received = 0;static int o_verbose = 4; /* 0-5 */static int my_oss = 0;static int my_ecs = 0;static int jt_quit(int argc, char **argv) {        Parser_quit(argc, argv);        return 0;}static int loadgen_usage(int argc, char **argv){        if (argc == 1) {                fprintf(stderr,         "This is a test program used to simulate large numbers of\n"        "clients.  The echo obds are used, so the obdecho module must\n"        "be loaded.\n"        "Typical usage would be:\n"        "  loadgen> dev lustre-OST0000       set the target device\n"        "  loadgen> start 20                 start 20 echo clients\n"        "  loadgen> wr 10 5                  have 10 clients do the brw_write\n"        "                                      test 5 times each\n"                        );        }        return (Parser_help(argc, argv));}static int loadgen_verbose(int argc, char **argv);static int loadgen_target(int argc, char **argv);static int loadgen_start_echosrv(int argc, char **argv);static int loadgen_start_clients(int argc, char **argv);static int loadgen_wait(int argc, char **argv);static int loadgen_write(int argc, char **argv);command_t cmdlist[] = {        {"device", loadgen_target, 0,         "set target ost name (e.g. lustre-OST0000)\n"         "usage: device <name> [<nid>]"},        {"dl", jt_obd_list, 0, "show all devices\n"         "usage: dl"},        {"echosrv", loadgen_start_echosrv, 0, "start an echo server\n"},        {"start", loadgen_start_clients, 0, "set up echo clients\n"         "usage: start_clients <num>"},        {"verbose", loadgen_verbose, 0, "set verbosity level 0-5\n"         "usage: verbose <level>"},        {"wait", loadgen_wait, 0,         "wait for all threads to finish\n"},        {"write", loadgen_write, 0,         "start a test_brw write test on X clients for Y iterations\n"         "usage: write <num_clients> <num_iter> [<delay>]"},        /* User interface commands */        {"help", loadgen_usage, 0, "help"},        {"exit", jt_quit, 0, "quit"},        {"quit", jt_quit, 0, "quit"},        { 0, 0, 0, NULL }};/* Command flags */#define C_STOP           0x0001#define C_CREATE_EVERY   0x0002  /* destroy and recreate every time */#define C_READ           0x0004#define C_WRITE          0x0008struct command_t {        int           c_flags;        int           c_rpt;        int           c_delay;};struct kid_t {        struct command_t k_cmd;        struct kid_t    *k_next;        pthread_t        k_pthread;        __u64            k_objid;        int              k_id;        int              k_dev;};static struct kid_t *kid_list = NULL;static struct kid_t *push_kid(int tnum){        struct kid_t *kid;        kid = (struct kid_t *)calloc(1, sizeof(struct kid_t));        if (kid == NULL) {                fprintf(stderr, "malloc failure\n");                return NULL;        }        kid->k_pthread = pthread_self();        kid->k_next = kid_list;        kid->k_id = tnum;        kid_list = kid;        live_threads++;        return kid;}int trigger_count = 0;int waiting_count = 0;int timer_on = 0;int all_done = 1;struct timeval trigger_start;struct command_t trigger_cmd;pthread_mutex_t m_trigger = PTHREAD_MUTEX_INITIALIZER;pthread_cond_t cv_trigger = PTHREAD_COND_INITIALIZER;unsigned long long write_bytes;pthread_mutex_t m_count = PTHREAD_MUTEX_INITIALIZER;static void trigger(int command, int threads, int repeat, int delay){        pthread_mutex_lock(&m_trigger);        trigger_cmd.c_flags = command;        trigger_cmd.c_rpt = repeat;        trigger_cmd.c_delay = delay;        trigger_count = threads;        if (o_verbose > 4)                printf("trigger %d cmd c=%d f=%x\n", trigger_count,                       trigger_cmd.c_rpt, trigger_cmd.c_flags);        gettimeofday(&trigger_start, NULL);        timer_on = 1;        pthread_mutex_lock(&m_count);        write_bytes = 0;        pthread_mutex_unlock(&m_count);        pthread_cond_broadcast(&cv_trigger);        pthread_mutex_unlock(&m_trigger);}static __inline__ void stop_all(int unused){        sig_received++;}static void kill_kids(void){        struct kid_t *tmp = kid_list;        stop_all(SIGINT);        trigger(C_STOP, 0, 0, 0);        while(tmp) {                pthread_kill(tmp->k_pthread, SIGTERM);                tmp = tmp->k_next;        }}static void sig_master(int unused){        stop_all(SIGINT);        //jt_quit(0, NULL);}static int wait_for_threads(){        struct kid_t *tmp = kid_list;        int rc = 0, status;        void *statusp;        printf("waiting for %d children\n", live_threads);        while(tmp) {                rc = pthread_join(tmp->k_pthread, &statusp);                status = (long)statusp;                if (o_verbose > 2)                        printf("%d: joined, rc = %d, status = %d\n",                               tmp->k_id, rc, status);                kid_list = tmp->k_next;                free(tmp);                tmp = kid_list;                live_threads--;        }        if (o_verbose > 0)                printf("%s done, rc = %d\n", cmdname, rc);        return rc;}static int write_proc(char *proc_path, char *value){        int fd, rc;        fd = open(proc_path, O_WRONLY);        if (fd == -1) {                fprintf(stderr, "open('%s') failed: %s\n",                        proc_path, strerror(errno));                rc = errno;        } else {                rc = write(fd, value, strlen(value));                if (rc < 0) {                        fprintf(stderr, "write('%s') failed: %s\n",                                proc_path, strerror(errno));                }                close(fd);        }        return rc;}static int read_proc(char *proc_path, unsigned long long *value){        int fd, rc;        char buf[50];        fd = open(proc_path, O_RDONLY);        if (fd == -1) {                fprintf(stderr, "open('%s') failed: %s\n",                        proc_path, strerror(errno));                return (errno);        }        rc = read(fd, buf, sizeof(buf));        close(fd);        if (errno == EOPNOTSUPP) {                /* probably an echo server */                return rc;        }        if (rc <= 0) {                fprintf(stderr, "read('%s') failed: %s (%d)\n",                        proc_path, strerror(errno), errno);                return rc;        }        *value = strtoull(buf, NULL, 10);        return 0;}static int grant_estimate(int thread){        unsigned long long avail, grant;        char proc_path[50];        int rc;        static int ran = 0;        /* I don't really care about protecting this with a mutex */        if (ran)                return 0;        if (o_verbose < 2)                return 0;        /* Divide /proc/fs/lustre/osc/o_0001/kbytesavail           by /proc/fs/lustre/osc/o_0001/cur_grant_bytes to find max clients */        sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/kbytesavail", thread);        rc = read_proc(proc_path, &avail);        if (rc)                return rc;        sprintf(proc_path, "/proc/fs/lustre/osc/o%.5d/cur_grant_bytes", thread);        rc = read_proc(proc_path, &grant);        if (rc)                return rc;        if (grant == 0) {                return -EINVAL;        }        printf("Estimate %llu clients before we run out of grant space "               "(%lluK / %llu)\n", (avail << 10)  / grant, avail, grant);        ran++;        return 0;}/* We hold a thread mutex around create/cleanup because cur_dev is not   shared-memory safe */pthread_mutex_t m_config = PTHREAD_MUTEX_INITIALIZER;static int cleanup(char *obdname, int quiet){        char *args[3];        int rc;        pthread_mutex_lock(&m_config);        args[0] = cmdname;        args[1] = obdname;        rc = jt_lcfg_device(2, args);        if (rc && !quiet)                fprintf(stderr, "%s: can't configure '%s' (%d)\n",                        cmdname, obdname, rc);        args[1] = "force";        rc = jt_obd_cleanup(2, args);        if (rc && !quiet)                fprintf(stderr, "%s: can't cleanup '%s' (%d)\n",                        cmdname, obdname, rc);        rc = jt_obd_detach(1, args);        if (rc && !quiet)                fprintf(stderr, "%s: can't detach '%s' (%d)\n",                        cmdname, obdname, rc);        pthread_mutex_unlock(&m_config);        return rc;}static int echocli_setup(char *oname, char *ename, int *dev){        char *args[5];        char proc_path[50];        int rc;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?