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 + -
显示快捷键?