/* *************************************************************************** * Read stats from the sysfs filesystem * for the devices entered on the command line *************************************************************************** */ void read_sysfs_dlist_stat(int curr, int flags) { int dev, ok; char filename[MAX_PF_NAME]; struct io_dlist *st_dev_list_i; /* Every I/O device (or partition) is potentially unregistered */ set_entries_inactive(iodev_nr); for (dev = 0; dev < dlist_idx; dev++) { st_dev_list_i = st_dev_list + dev; sprintf(filename, "%s/%s/%s", SYSFS_BLOCK, st_dev_list_i->dev_name, S_STAT); /* Read device stats */ ok = read_sysfs_file_stat(curr, filename, st_dev_list_i->dev_name, DT_DEVICE); if (ok && st_dev_list_i->disp_part) /* Also read stats for its partitions */ read_sysfs_dlist_part_stat(curr, st_dev_list_i->dev_name); } /* Free structures corresponding to unregistered devices */ free_inactive_entries(iodev_nr); }
/* *************************************************************************** * Read CIFS-mount directories stats from /proc/fs/cifs/Stats. * * IN: * @curr Index in array for current sample statistics. *************************************************************************** */ void read_cifs_stat(int curr) { FILE *fp; char line[256]; char aux[32]; int start = 0; char cifs_name[MAX_NAME_LEN]; char name_tmp[MAX_NAME_LEN]; struct cifs_stats scifs; /* Every CIFS entry is potentially unregistered */ set_entries_inactive(); if ((fp = fopen(CIFSSTATS, "r")) == NULL) return; sprintf(aux, "%%*d) %%%ds", MAX_NAME_LEN < 200 ? MAX_NAME_LEN - 1 : 200); while (fgets(line, 256, fp) != NULL) { /* Read CIFS directory name */ if (isdigit((unsigned char) line[0]) && sscanf(line, aux , name_tmp) == 1) { if (start) { save_stats(cifs_name, curr, &scifs); } else { start = 1; } strcpy(cifs_name, name_tmp); } else { if (!strncmp(line, "Reads:", 6)) { sscanf(line, "Reads: %llu Bytes: %llu", &scifs.rd_ops, &scifs.rd_bytes); } if (!strncmp(line, "Writes:", 7)) { sscanf(line, "Writes: %llu Bytes: %llu", &scifs.wr_ops, &scifs.wr_bytes); } if (!strncmp(line, "Opens:", 6)) { sscanf(line, "Opens: %llu Closes:%llu Deletes: %llu", &scifs.fopens, &scifs.fcloses, &scifs.fdeletes); } } } if (start) { save_stats(cifs_name, curr, &scifs); } fclose(fp); /* Free structures corresponding to unregistered filesystems */ free_inactive_entries(); }
/* *************************************************************************** * Read stats from /proc/partitions *************************************************************************** */ void read_ppartitions_stat(int curr, int flags) { FILE *fp; char line[256], dev_name[MAX_NAME_LEN]; struct io_stats sdev; unsigned long rd_ios, rd_merges, rd_ticks, wr_ios, wr_merges, wr_ticks; unsigned long ios_pgr, tot_ticks, rq_ticks; unsigned long long rd_sec, wr_sec; char *ioc_dname; unsigned int major, minor; /* Every I/O device entry is potentially unregistered */ set_entries_inactive(iodev_nr); if ((fp = fopen(PPARTITIONS, "r")) == NULL) return; while (fgets(line, 256, fp) != NULL) { /* major minor #blocks name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */ if (sscanf(line, "%u %u %*u %s %lu %lu %llu %lu %lu %lu %llu" " %lu %lu %lu %lu", &major, &minor, dev_name, &rd_ios, &rd_merges, &rd_sec, &rd_ticks, &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks) == 14) { /* Device or partition */ sdev.rd_ios = rd_ios; sdev.rd_merges = rd_merges; sdev.rd_sectors = rd_sec; sdev.rd_ticks = rd_ticks; sdev.wr_ios = wr_ios; sdev.wr_merges = wr_merges; sdev.wr_sectors = wr_sec; sdev.wr_ticks = wr_ticks; sdev.ios_pgr = ios_pgr; sdev.tot_ticks = tot_ticks; sdev.rq_ticks = rq_ticks; } else /* Unknown entry: ignore it */ continue; if ((ioc_dname = ioc_name(major, minor)) != NULL) { if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) /* Compensate for EMC PowerPath driver bug */ strcpy(dev_name, ioc_dname); } save_dev_stats(dev_name, curr, &sdev); } fclose(fp); /* Free structures corresponding to unregistered devices */ free_inactive_entries(iodev_nr); }
/* *************************************************************************** * Read stats from the sysfs filesystem * for every block devices found *************************************************************************** */ void read_sysfs_stat(int curr, int flags) { DIR *dir; struct dirent *drd; char filename[MAX_PF_NAME]; int ok; /* Every I/O device entry is potentially unregistered */ set_entries_inactive(iodev_nr); /* Open /sys/block directory */ if ((dir = opendir(SYSFS_BLOCK)) != NULL) { /* Get current entry */ while ((drd = readdir(dir)) != NULL) { if (!strcmp(drd->d_name, ".") || !strcmp(drd->d_name, "..")) continue; sprintf(filename, "%s/%s/%s", SYSFS_BLOCK, drd->d_name, S_STAT); /* If current entry is a directory, try to read its stat file */ ok = read_sysfs_file_stat(curr, filename, drd->d_name, DT_DEVICE); /* * If '-p ALL' was entered on the command line, * also try to read stats for its partitions */ if (ok && DISPLAY_PART_ALL(flags)) read_sysfs_dlist_part_stat(curr, drd->d_name); } /* Close /sys/block directory */ closedir(dir); } /* Free structures corresponding to unregistered devices */ free_inactive_entries(iodev_nr); }
/* *************************************************************************** * Read stats from /proc/diskstats *************************************************************************** */ void read_diskstats_stat(int curr, int flags) { FILE *fp; char line[256], dev_name[MAX_NAME_LEN]; struct io_stats sdev; int i; unsigned long rd_ios, rd_merges_or_rd_sec, rd_ticks_or_wr_sec, wr_ios; unsigned long ios_pgr, tot_ticks, rq_ticks, wr_merges, wr_ticks; unsigned long long rd_sec_or_wr_ios, wr_sec; char *ioc_dname; unsigned int major, minor; /* Every I/O device entry is potentially unregistered */ set_entries_inactive(iodev_nr); if ((fp = fopen(DISKSTATS, "r")) == NULL) return; while (fgets(line, 256, fp) != NULL) { /* major minor name rio rmerge rsect ruse wio wmerge wsect wuse running use aveq */ i = sscanf(line, "%u %u %s %lu %lu %llu %lu %lu %lu %llu %lu %lu %lu %lu", &major, &minor, dev_name, &rd_ios, &rd_merges_or_rd_sec, &rd_sec_or_wr_ios, &rd_ticks_or_wr_sec, &wr_ios, &wr_merges, &wr_sec, &wr_ticks, &ios_pgr, &tot_ticks, &rq_ticks); if (i == 14) { /* Device */ sdev.rd_ios = rd_ios; sdev.rd_merges = rd_merges_or_rd_sec; sdev.rd_sectors = rd_sec_or_wr_ios; sdev.rd_ticks = rd_ticks_or_wr_sec; sdev.wr_ios = wr_ios; sdev.wr_merges = wr_merges; sdev.wr_sectors = wr_sec; sdev.wr_ticks = wr_ticks; sdev.ios_pgr = ios_pgr; sdev.tot_ticks = tot_ticks; sdev.rq_ticks = rq_ticks; } else if (i == 7) { /* Partition */ if (DISPLAY_EXTENDED(flags) || (!dlist_idx && !DISPLAY_PARTITIONS(flags))) continue; sdev.rd_ios = rd_ios; sdev.rd_sectors = rd_merges_or_rd_sec; sdev.wr_ios = rd_sec_or_wr_ios; sdev.wr_sectors = rd_ticks_or_wr_sec; } else /* Unknown entry: ignore it */ continue; if ((ioc_dname = ioc_name(major, minor)) != NULL) { if (strcmp(dev_name, ioc_dname) && strcmp(ioc_dname, K_NODEV)) /* * No match: Use name generated from sysstat.ioconf data (if different * from "nodev") works around known issues with EMC PowerPath. */ strcpy(dev_name, ioc_dname); } save_dev_stats(dev_name, curr, &sdev); } fclose(fp); /* Free structures corresponding to unregistered devices */ free_inactive_entries(iodev_nr); }
/* *************************************************************************** * Read stats from /proc/stat file... * Useful at least for CPU utilization. * May be useful to get disk stats if /sys not available. *************************************************************************** */ void read_proc_stat(int curr, int flags) { FILE *fp; char line[8192]; int pos, i; unsigned long v_tmp[4]; unsigned int v_major, v_index; struct io_stats *st_iodev_tmp[4]; unsigned long long cc_idle, cc_iowait, cc_steal; unsigned long long cc_user, cc_nice, cc_system, cc_hardirq, cc_softirq; /* * Prepare pointers on the 4 disk structures in case we have a * /proc/stat file with "disk_rblk", etc. entries. */ for (i = 0; i < 4; i++) st_iodev_tmp[i] = st_iodev[curr] + i; if ((fp = fopen(STAT, "r")) == NULL) { perror("fopen"); exit(2); } while (fgets(line, 8192, fp) != NULL) { if (!strncmp(line, "cpu ", 4)) { /* * Read the number of jiffies spent in the different modes, * and compute system uptime in jiffies (1/100ths of a second * if HZ=100). * Some fields are only present in 2.6 kernels. */ comm_stats[curr].cpu_iowait = 0; /* For pre 2.6 kernels */ comm_stats[curr].cpu_steal = 0; cc_hardirq = cc_softirq = 0; /* CPU counters became unsigned long long with kernel 2.6.5 */ sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu", &(comm_stats[curr].cpu_user), &(comm_stats[curr].cpu_nice), &(comm_stats[curr].cpu_system), &(comm_stats[curr].cpu_idle), &(comm_stats[curr].cpu_iowait), &cc_hardirq, &cc_softirq, &(comm_stats[curr].cpu_steal)); /* * Time spent in system mode also includes time spent servicing * hard interrupts and softirqs. */ comm_stats[curr].cpu_system += cc_hardirq + cc_softirq; /* * Compute system uptime in jiffies. * Uptime is multiplied by the number of processors. */ comm_stats[curr].uptime = comm_stats[curr].cpu_user + comm_stats[curr].cpu_nice + comm_stats[curr].cpu_system + comm_stats[curr].cpu_idle + comm_stats[curr].cpu_iowait + comm_stats[curr].cpu_steal; } else if ((!strncmp(line, "cpu0", 4)) && (cpu_nr > 1)) { /* * Read CPU line for proc#0 (if available). * This is necessary to compute time interval since * processors may be disabled (offline) sometimes. * (Assume that proc#0 can never be offline). */ cc_iowait = cc_hardirq = cc_softirq = cc_steal = 0; sscanf(line + 5, "%llu %llu %llu %llu %llu %llu %llu %llu", &cc_user, &cc_nice, &cc_system, &cc_idle, &cc_iowait, &cc_hardirq, &cc_softirq, &cc_steal); comm_stats[curr].uptime0 = cc_user + cc_nice + cc_system + cc_idle + cc_iowait + cc_hardirq + cc_softirq + cc_steal; } else if (DISPLAY_EXTENDED(flags) || HAS_DISKSTATS(flags) || HAS_PPARTITIONS(flags) || HAS_SYSFS(flags)) /* * When displaying extended statistics, or if /proc/diskstats or * /proc/partitions exists, or /sys is mounted, * we just need to get CPU info from /proc/stat. */ continue; else if (!strncmp(line, "disk_rblk ", 10)) { /* * Read the number of blocks read from disk. * A block is of indeterminate size. * The size may vary depending on the device type. */ sscanf(line + 10, "%lu %lu %lu %lu", &v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]); st_iodev_tmp[0]->dk_drive_rblk = v_tmp[0]; st_iodev_tmp[1]->dk_drive_rblk = v_tmp[1]; st_iodev_tmp[2]->dk_drive_rblk = v_tmp[2]; st_iodev_tmp[3]->dk_drive_rblk = v_tmp[3]; } else if (!strncmp(line, "disk_wblk ", 10)) { /* Read the number of blocks written to disk */ sscanf(line + 10, "%lu %lu %lu %lu", &v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]); st_iodev_tmp[0]->dk_drive_wblk = v_tmp[0]; st_iodev_tmp[1]->dk_drive_wblk = v_tmp[1]; st_iodev_tmp[2]->dk_drive_wblk = v_tmp[2]; st_iodev_tmp[3]->dk_drive_wblk = v_tmp[3]; } else if (!strncmp(line, "disk ", 5)) { /* Read the number of I/O done since the last reboot */ sscanf(line + 5, "%lu %lu %lu %lu", &v_tmp[0], &v_tmp[1], &v_tmp[2], &v_tmp[3]); st_iodev_tmp[0]->dk_drive = v_tmp[0]; st_iodev_tmp[1]->dk_drive = v_tmp[1]; st_iodev_tmp[2]->dk_drive = v_tmp[2]; st_iodev_tmp[3]->dk_drive = v_tmp[3]; } else if (!strncmp(line, "disk_io: ", 9)) { struct io_stats sdev; char dev_name[MAX_NAME_LEN]; pos = 9; /* Every disk_io entry is potentially unregistered */ set_entries_inactive(iodev_nr); /* Read disks I/O statistics (for 2.4 kernels) */ while (pos < strlen(line) - 1) { /* Beware: a CR is already included in the line */ sscanf(line + pos, "(%u,%u):(%lu,%*u,%lu,%*u,%lu) ", &v_major, &v_index, &v_tmp[0], &v_tmp[1], &v_tmp[2]); sprintf(dev_name, "dev%d-%d", v_major, v_index); sdev.dk_drive = v_tmp[0]; sdev.dk_drive_rblk = v_tmp[1]; sdev.dk_drive_wblk = v_tmp[2]; save_dev_stats(dev_name, curr, &sdev); pos += strcspn(line + pos, " ") + 1; } /* Free structures corresponding to unregistered disks */ free_inactive_entries(iodev_nr); } } fclose(fp); }
/* *************************************************************************** * Read NFS-mount directories stats from /proc/self/mountstats. * * IN: * @curr Index in array for current sample statistics. *************************************************************************** */ void read_nfs_stat(int curr) { FILE *fp; int sw = 0; char line[256]; char *xprt_line; char *mount_part; char nfs_name[MAX_NAME_LEN]; char mount[10], on[10], prefix[10], aux[32]; char operation[16]; struct io_nfs_stats snfs; long int v1; /* Every I/O NFS entry is potentially unregistered */ set_entries_inactive(); if ((fp = fopen(NFSMOUNTSTATS, "r")) == NULL) return; sprintf(aux, "%%%ds", MAX_NAME_LEN < 200 ? MAX_NAME_LEN-1 : 200); while (fgets(line, 256, fp) != NULL) { /* Read NFS directory name */ if (!strncmp(line, "device", 6)) { sw = 0; sscanf(line + 6, aux, nfs_name); mount_part = strchr(line + 7, ' '); if (mount_part != NULL) { sscanf(mount_part, "%9s %9s", mount, on); if ((!strncmp(mount, "mounted", 7)) && (!strncmp(on, "on", 2))) { sw = 1; } } } sscanf(line, "%9s", prefix); if (sw && (!strncmp(prefix, "bytes:", 6))) { /* Read the stats for the last NFS-mounted directory */ sscanf(strstr(line, "bytes:") + 6, "%llu %llu %llu %llu %llu %llu", &snfs.rd_normal_bytes, &snfs.wr_normal_bytes, &snfs.rd_direct_bytes, &snfs.wr_direct_bytes, &snfs.rd_server_bytes, &snfs.wr_server_bytes); sw = 2; } if ((sw == 2) && (!strncmp(prefix, "xprt:", 5))) { /* * Read extended statistic for the last NFS-mounted directory * - number of sent rpc requests. */ xprt_line = (strstr(line, "xprt:") + 6); /* udp, tcp or rdma data */ if (!strncmp(xprt_line, "udp", 3)) { /* port bind_count sends recvs (bad_xids req_u bklog_u) */ sscanf(strstr(xprt_line, "udp") + 4, "%*u %*u %lu", &snfs.rpc_sends); } if (!strncmp(xprt_line, "tcp", 3)) { /* * port bind_counter connect_count connect_time idle_time * sends recvs (bad_xids req_u bklog_u) */ sscanf(strstr(xprt_line, "tcp") + 4, "%*u %*u %*u %*u %*d %lu", &snfs.rpc_sends); } if (!strncmp(xprt_line,"rdma", 4)) { /* * 0(port) bind_count connect_count connect_time idle_time * sends recvs (bad_xids req_u bklog_u...) */ sscanf(strstr(xprt_line, "rdma") + 5, "%*u %*u %*u %*u %*d %lu", &snfs.rpc_sends); } sw = 3; } if ((sw == 3) && (!strncmp(prefix, "per-op", 6))) { sw = 4; while (sw == 4) { fgets(line, 256, fp); sscanf(line, "%15s %lu", operation, &v1); if (!strncmp(operation, "READ:", 5)) { snfs.nfs_rops = v1; } else if (!strncmp(operation, "WRITE:", 6)) { snfs.nfs_wops = v1; save_stats(nfs_name, curr, &snfs); sw = 0; } } } } fclose(fp); /* Free structures corresponding to unregistered filesystems */ free_inactive_entries(); }