Skip to content

Commit

Permalink
Option -m USB added to sar (sadc POWER group)
Browse files Browse the repository at this point in the history
This option takes a snapshot of current USB devices plugged into
the system.
Idea from [email protected] (Fabricio Ceolin).
  • Loading branch information
sysstat committed May 24, 2011
1 parent 6e42cb0 commit 7842c55
Show file tree
Hide file tree
Showing 14 changed files with 427 additions and 8 deletions.
33 changes: 32 additions & 1 deletion activity.c
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,36 @@ struct activity pwr_wghfreq_act = {
.bitmap = &cpu_bitmap
};

/* USB devices plugged into the system */
struct activity pwr_usb_act = {
.id = A_PWR_USB,
.options = AO_NULL,
.magic = ACTIVITY_MAGIC_BASE,
.group = G_POWER,
#ifdef SOURCE_SADC
.f_count = wrap_get_usb_nr,
.f_count2 = NULL,
.f_read = wrap_read_bus_usb_dev,
#endif
#ifdef SOURCE_SAR
.f_print = print_pwr_usb_stats,
.f_print_avg = print_avg_pwr_usb_stats,
#endif
#ifdef SOURCE_SADF
.f_render = render_pwr_usb_stats,
.f_xml_print = xml_print_pwr_usb_stats,
.hdr_line = "manufact;product;BUS;idvendor;idprod;maxpower",
.name = "A_PWR_USB",
#endif
.nr = -1,
.nr2 = 1,
.fsize = STATS_PWR_USB_SIZE,
.msize = STATS_PWR_USB_SIZE,
.opt_flags = 0,
.buf = {NULL, NULL, NULL},
.bitmap = NULL
};


/*
* Array of activities.
Expand Down Expand Up @@ -1166,5 +1196,6 @@ struct activity *act[NR_ACT] = {
&pwr_temp_act,
&pwr_in_act,
&huge_act,
&pwr_wghfreq_act
&pwr_wghfreq_act,
&pwr_usb_act
};
6 changes: 6 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@
#define S_STAT "stat"
#define DEVMAP_DIR "/dev/mapper"
#define DEVICES "/proc/devices"
#define SYSFS_USBDEV "/sys/bus/usb/devices"
#define SYSFS_IDVENDOR "idVendor"
#define SYSFS_IDPRODUCT "idProduct"
#define SYSFS_BMAXPOWER "bMaxPower"
#define SYSFS_MANUFACTURER "manufacturer"
#define SYSFS_PRODUCT "product"

#define MAX_FILE_LEN 256
#define MAX_PF_NAME 1024
Expand Down
112 changes: 112 additions & 0 deletions pr_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -2311,3 +2311,115 @@ void print_pwr_wghfreq_stats(struct activity *a, int prev, int curr,
}
}
}

/*
***************************************************************************
* Display USB devices statistics. This function is used to
* display instantaneous and summary statistics.
*
* IN:
* @a Activity structure with statistics.
* @curr Index in array for current sample statistics.
* @itv Interval of time in jiffies.
* @dispavg TRUE if displaying average statistics.
***************************************************************************
*/
void stub_print_pwr_usb_stats(struct activity *a, int curr, int dispavg)
{
int i, j;
struct stats_pwr_usb *suc, *sum;

if (dis) {
printf("\n%-11s BUS idvendor idprod maxpower",
(dispavg ? _("Summary") : timestamp[!curr]));
printf(" %*s", MAX_MANUF_LEN - 1, "manufact");
printf(" %*s\n", MAX_PROD_LEN - 1, "product");
}

for (i = 0; i < a->nr; i++) {
suc = (struct stats_pwr_usb *) ((char *) a->buf[curr] + i * a->msize);

if (!suc->bus_nr)
/* Bus#0 doesn't exist: We are at the end of the list */
break;

printf("%-11s %6d %9x %9x %9u",
(dispavg ? _("Summary") : timestamp[curr]),
suc->bus_nr,
suc->vendor_id, suc->product_id,
/* bMaxPower is expressed in 2 mA units */
suc->bmaxpower << 1);

printf(" %*s", MAX_MANUF_LEN - 1, suc->manufacturer);
printf(" %*s\n", MAX_PROD_LEN - 1, suc->product);

if (!dispavg) {
/* Save current USB device in summary list */
for (j = 0; j < a->nr; j++) {
sum = (struct stats_pwr_usb *) ((char *) a->buf[2] + j * a->msize);

if ((sum->bus_nr == suc->bus_nr) &&
(sum->vendor_id == suc->vendor_id) &&
(sum->product_id == suc->product_id))
/* USB device found in summary list */
break;
if (!sum->bus_nr) {
/*
* Current slot is free:
* Save USB device in summary list.
*/
*sum = *suc;
break;
}
if (j == a->nr - 1) {
/*
* This is the last slot and
* we still havent't found the device.
* So create a dummy device here.
*/
sum->bus_nr = ~0;
sum->vendor_id = sum->product_id = 0;
sum->bmaxpower = 0;
sum->manufacturer[0] = '\0';
snprintf(sum->product, MAX_PROD_LEN, "%s",
_("Other devices not listed here"));
sum->product[MAX_PROD_LEN - 1] = '\0';
}
}
}
}
}

/*
***************************************************************************
* Display memory and swap statistics.
*
* IN:
* @a Activity structure with statistics.
* @prev Index in array where stats used as reference are.
* @curr Index in array for current sample statistics.
* @itv Interval of time in jiffies.
***************************************************************************
*/
__print_funct_t print_pwr_usb_stats(struct activity *a, int prev, int curr,
unsigned long long itv)
{
stub_print_pwr_usb_stats(a, curr, FALSE);
}

/*
***************************************************************************
* Display average memory statistics.
*
* IN:
* @a Activity structure with statistics.
* @prev Index in array where stats used as reference are.
* @curr Index in array for current sample statistics.
* @itv Interval of time in jiffies.
***************************************************************************
*/
__print_funct_t print_avg_pwr_usb_stats(struct activity *a, int prev, int curr,
unsigned long long itv)
{
stub_print_pwr_usb_stats(a, 2, TRUE);
}
4 changes: 4 additions & 0 deletions pr_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ extern __print_funct_t print_huge_stats
(struct activity *, int, int, unsigned long long);
extern __print_funct_t print_pwr_wghfreq_stats
(struct activity *, int, int, unsigned long long);
extern __print_funct_t print_pwr_usb_stats
(struct activity *, int, int, unsigned long long);

/* Functions used to display average statistics */
extern __print_funct_t print_avg_memory_stats
Expand All @@ -108,5 +110,7 @@ extern __print_funct_t print_avg_pwr_in_stats
(struct activity *, int, int, unsigned long long);
extern __print_funct_t print_avg_huge_stats
(struct activity *, int, int, unsigned long long);
extern __print_funct_t print_avg_pwr_usb_stats
(struct activity *, int, int, unsigned long long);

#endif /* _PR_STATS_H */
149 changes: 149 additions & 0 deletions rd_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,121 @@ void read_time_in_state(struct stats_pwr_wghfreq *st_pwr_wghfreq, int cpu_nr, in
fclose(fp);
}

/*
***************************************************************************
* Read current USB device data.
*
* IN:
* @st_pwr_usb Structure where stats will be saved.
* @usb_device File name for current USB device.
*
* OUT:
* @st_pwr_usb Structure with statistics.
***************************************************************************
*/
void read_usb_stats(struct stats_pwr_usb *st_pwr_usb, char *usb_device)
{
int l;
FILE *fp;
char filename[MAX_PF_NAME];

/* Get USB device bus number */
sscanf(usb_device, "%u", &st_pwr_usb->bus_nr);

/* Read USB device vendor ID */
snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
SYSFS_USBDEV, usb_device, SYSFS_IDVENDOR);
if ((fp = fopen(filename, "r")) != NULL) {
fscanf(fp, "%x",
&st_pwr_usb->vendor_id);
fclose(fp);
}

/* Read USB device product ID */
snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
SYSFS_USBDEV, usb_device, SYSFS_IDPRODUCT);
if ((fp = fopen(filename, "r")) != NULL) {
fscanf(fp, "%x",
&st_pwr_usb->product_id);
fclose(fp);
}

/* Read USB device max power consumption */
snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
SYSFS_USBDEV, usb_device, SYSFS_BMAXPOWER);
if ((fp = fopen(filename, "r")) != NULL) {
fscanf(fp, "%u",
&st_pwr_usb->bmaxpower);
fclose(fp);
}

/* Read USB device manufacturer */
snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
SYSFS_USBDEV, usb_device, SYSFS_MANUFACTURER);
if ((fp = fopen(filename, "r")) != NULL) {
fgets(st_pwr_usb->manufacturer, MAX_MANUF_LEN - 1, fp);
fclose(fp);
if ((l = strlen(st_pwr_usb->manufacturer)) > 0) {
/* Remove trailing CR */
st_pwr_usb->manufacturer[l - 1] = '\0';
}
}

/* Read USB device product */
snprintf(filename, MAX_PF_NAME, "%s/%s/%s",
SYSFS_USBDEV, usb_device, SYSFS_PRODUCT);
if ((fp = fopen(filename, "r")) != NULL) {
fgets(st_pwr_usb->product, MAX_PROD_LEN - 1, fp);
fclose(fp);
if ((l = strlen(st_pwr_usb->product)) > 0) {
/* Remove trailing CR */
st_pwr_usb->product[l - 1] = '\0';
}
}
}

/*
***************************************************************************
* Read USB devices statistics.
*
* IN:
* @st_pwr_usb Structure where stats will be saved.
* @nbr Total number of USB devices.
*
* OUT:
* @st_pwr_usb Structure with statistics.
***************************************************************************
*/
void read_bus_usb_dev(struct stats_pwr_usb *st_pwr_usb, int nbr)
{
DIR *dir;
struct dirent *drd;
struct stats_pwr_usb *st_pwr_usb_j;
int j = 0;

/* Open relevant /sys directory */
if ((dir = opendir(SYSFS_USBDEV)) == NULL)
return;

/* Get current file entry */
while ((drd = readdir(dir)) != NULL) {

if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
if (j < nbr) {
/* Read current USB device data */
st_pwr_usb_j = st_pwr_usb + j;
read_usb_stats(st_pwr_usb_j, drd->d_name);
j++;
}
else
break;
}
}

/* Close directory */
closedir(dir);
}

/*
***************************************************************************
* Read machine uptime, independently of the number of processors.
Expand Down Expand Up @@ -2127,3 +2242,37 @@ int get_freq_nr(void)

return freq;
}

/*
***************************************************************************
* Count number of USB devices in /sys/bus/usb/devices.
*
* RETURNS:
* Number of USB devices plugged into the system.
* Don't count USB root hubs.
* Return -1 if directory doesn't exist in sysfs.
***************************************************************************
*/
int get_usb_nr(void)
{
DIR *dir;
struct dirent *drd;
int usb = 0;

/* Open relevant /sys directory */
if ((dir = opendir(SYSFS_USBDEV)) == NULL)
return -1;

/* Get current file entry */
while ((drd = readdir(dir)) != NULL) {

if (isdigit(drd->d_name[0]) && !strchr(drd->d_name, ':')) {
usb++;
}
}

/* Close directory */
closedir(dir);

return usb;
}
22 changes: 22 additions & 0 deletions rd_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@

/* Maximum length of network interface name */
#define MAX_IFACE_LEN IFNAMSIZ
/* Maximum length of USB manufacturer string */
#define MAX_MANUF_LEN 24
/* Maximum length of USB product string */
#define MAX_PROD_LEN 48

#define CNT_DEV 0
#define CNT_PART 1
Expand Down Expand Up @@ -504,6 +508,20 @@ struct stats_pwr_wghfreq {

#define STATS_PWR_WGHFREQ_SIZE (sizeof(struct stats_pwr_wghfreq))

/*
* Structure for USB devices plugged into the system.
*/
struct stats_pwr_usb {
unsigned int bus_nr __attribute__ ((aligned (4)));
unsigned int vendor_id __attribute__ ((packed));
unsigned int product_id __attribute__ ((packed));
unsigned int bmaxpower __attribute__ ((packed));
char manufacturer[MAX_MANUF_LEN];
char product[MAX_PROD_LEN];
};

#define STATS_PWR_USB_SIZE (sizeof(struct stats_pwr_usb))

/*
***************************************************************************
* Prototypes for functions used to read system statistics
Expand Down Expand Up @@ -577,6 +595,8 @@ extern void
read_meminfo_huge(struct stats_huge *);
extern void
read_time_in_state(struct stats_pwr_wghfreq *, int, int);
extern void
read_bus_usb_dev(struct stats_pwr_usb *, int);

/*
***************************************************************************
Expand All @@ -600,5 +620,7 @@ extern int
get_irqcpu_nr(char *, int, int);
extern int
get_freq_nr(void);
extern int
get_usb_nr(void);

#endif /* _RD_STATS_H */

0 comments on commit 7842c55

Please sign in to comment.