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