ltrack_stats.c

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

C
494
字号
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * *  Copyright (C) 2007 Cluster File Systems, Inc. *   Author: Milind Dumbare <milind@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. * */#include <sys/types.h>#include <sys/wait.h>#include <getopt.h>#include <stdio.h>#include <unistd.h>#include <glob.h>#include <signal.h>#include <string.h>#include <stdlib.h>#define TRACK_BY_GID 0#define TRACK_BY_PPID 1#define TRACK_BY_PID 2#define TRACK_FOR_ALL 3/* We can have at the most 1024 llstats monitoring 1024 lustre clients * at a time */#define NO_OF_CLIENTS 1024/* length of absolute path of vfs_ops_stats */#define LEN_STATS 1024/* Length of llstat command with all its switches and command line options */#define LEN_LLSTAT (25 + LEN_STATS)/* strlen of each lustre client entry in /proc/fs/lustre/llite/ */#define LEN_CLIENT 1024/* size of output of llstat command we read at a time */#define MAX 1024/* max strlen of outfile we get on command line */#define LEN_OUT 1024/* Length of command given on command line */#define COMM_LEN 4096pid_t llstat[1024];/* print usage */void print_usage(){        printf("Usage:\n\n");        printf("ltrack_stats runs command given and does one of the "                "following:\n"                "\t1. Writes its pid to "                "/proc/fs/lustre/llite/.../stats_track_pid\n"                " to collects stats for that process.\n"                "\t2. Writes its ppid to "                "/proc/fs/lustre/llite/.../stats_track_ppid\n"                " to collect stats of that process and all its children \n"                "\t3. Sets gid of process to some random gid (444) and also\n"                " writes that to/proc/fs/lustre/llite/.../stats_track_gid to"                " collect stats \nof all processes in that group\n\n"                " It also uses llstat to generate output with interval of 1 "                " second and duration\n of run of command for plot-llstat to "                "generate a graph\n\n");        printf("ltrack_stats [-l filename] [-g <gid> | -a | -i | -c | -h ]\n"               "\t<command with arguments ...>\n\n");        printf("-l: outputs the llstat.pl's output to given <filename>"               "with interval of 1 second \nbetween each output and flag for"               "graphable output. If -l flag is not given llstat \nwont be"               "executed\n\n");        printf("-g: for displaying VFS operation statistics collected"               "for all processes having \ngroup id as given <gid> \n\n");        printf("-a: for displaying VFS operations statistics collected"               "for all processes\n\n");        printf("-i: for displaying VFS operation statistics collected"               "for only given <command's> \nPID.\n\n");        printf("-c: for displaying VFS operation statistics collected"               " for all processes whose \nparents' PID is same as pid of "               "<command> to be executed\n\n");        printf("-h: for showing this help\n");}/* - type: to which file data should be written to track VFS operations * statistics * - id: we either need to write gid which is given on command line or pid * to collect statistics of that process or its children. */void write_track_xid(int type, unsigned short id, char* stats_path){        FILE *fp;        /* for loop is used if we have more than one lustre clients on same         * machine. glob() return /proc entry for each lustre client */        switch(type) {                case TRACK_BY_GID:                        strcat(stats_path, "/stats_track_gid");                        break;                case TRACK_BY_PPID:                        strcat(stats_path, "/stats_track_ppid");                        break;                case TRACK_BY_PID:                        strcat(stats_path, "/stats_track_pid");                        break;        }        fp = fopen(stats_path, "w+");        if (!fp) {                fprintf(stderr, "Error: Couldn't open /proc entry file: %s\n",                        stats_path);                exit(1);        }        if (fprintf(fp, "%d", id) < 0) {                fprintf(stderr, "Error: Couldn't write id to tracking /proc"                        "entry file: %s\n", stats_path);                exit(1);        }        if (fclose(fp)) {                fprintf(stderr, "Error: Couldn't close tracking /proc entry"                        " file: %s\n", stats_path);                exit(1);        }}/* Get extra command lines concatenated to "command Function getopt scans *  one switch and its optional argument. So if command line is  * "-g 1234 make bzImage" 1234 is optarg and "make bzImage" will be collected *  with following function to exec it. */char* get_command_from_argv(int optind, int argc, char** argv,char* optarg,                            char* command){        int index = 0;        strcpy(command, optarg);        strcat(command, " ");        for (index = optind; index < argc; index++) {                strcat(command, argv[index]);                strcat(command, " ");        }        if (strlen(command) == 1) {                fprintf(stderr,"Error: command missing \n");                print_usage();                exit(1);        } else if (strlen(command) > COMM_LEN) {                fprintf(stderr,"Error: Too long command \n");                print_usage();                exit(1);        }        return command;}/* Check for the llstat command in $PATH env variable. */void check_llstat(){        int status;        status = system("which llstat.pl &> /dev/null");        if (status) {                fprintf(stderr,"Error: llstat.pl not found in PATH\n");                exit(1);        }}pid_t fork_llstat_command(char* llstat_file,char* stats_path){        char truncate_command[100];        char llstat_command[LEN_LLSTAT];        pid_t pid_llstat_command;        FILE *fp_popen, *fp_out;        char buffer[MAX];                /* Truncating llstat output file as it will be opened in while         * loop to append output */        sprintf(truncate_command,"> %s",llstat_file);        system(truncate_command);         strcat(stats_path, "/stats");        /* creating a string of llstat command to give to         * popen */        sprintf(llstat_command, "llstat -i 1 -g %s ",                stats_path);        /* fork for llstat */        if ((pid_llstat_command = fork()) < 0)                fprintf(stderr, "Error: Fork error\n");        /* in child (llstat) */        if (pid_llstat_command == 0) {                /* Doing popen for llstat command */                fp_popen = popen(llstat_command, "r");                if (fp_popen == NULL) {                        fprintf(stderr,"Couldn't popen the llstat command:"                                "\"%s\"n", llstat_command);                        exit(1);                }                while (fgets(buffer, 1024, fp_popen) != NULL) {                        /* Following code should be in while loop as llstat                          * will keep on sending output each second and will                         * not exit on itself. It will be killed when we finsh                         * with our command so we must make the output file                          * consistent after writing each 1024 bytes chunk */                        /* opening file where llstat will write its output */                        fp_out = fopen(llstat_file, "a");                        if (!fp_out) {                                fprintf(stderr, "Error: Couldn't open llstat"                                        "outfile file: %s\n",                                        llstat_file);                                exit(1);                        }                        /* fgets reads the popen output and fprintf writes it to                         * output file */                        if (fputs(buffer, fp_out) == EOF) {                                 fprintf(stderr, "Error: Couldn't write output"                                         "of llstat to out file\n");                                 exit(1);                        }                        /* closing file opened for storing llstat's output */                        if (fclose(fp_out)) {                                fprintf(stderr, "Error: Couldn't close llstat"                                        "outfile: %s\n", llstat_file);                                exit(1);

⌨️ 快捷键说明

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