1 /*- 2 * Copyright (c) 2012 Adrian Chadd 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 * 29 * $FreeBSD$ 30 */ 31 #include "diag.h" 32 33 #include "ah.h" 34 #include "ah_internal.h" 35 36 #include <getopt.h> 37 #include <errno.h> 38 #include <err.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <ctype.h> 42 #include <unistd.h> 43 44 const char *progname; 45 46 static void 47 usage() 48 { 49 fprintf(stderr, "usage: %s [-i ifname]\n", progname); 50 exit(-1); 51 } 52 53 static int 54 get_survey_stats(int s, const char *ifname, HAL_CHANNEL_SURVEY *hs) 55 { 56 uint16_t eedata; 57 struct ath_diag atd; 58 59 memset(&atd, '\0', sizeof(atd)); 60 61 atd.ad_id = HAL_DIAG_CHANSURVEY | ATH_DIAG_OUT; 62 atd.ad_in_size = 0; 63 atd.ad_in_data = NULL; 64 atd.ad_out_size = sizeof(HAL_CHANNEL_SURVEY); 65 atd.ad_out_data = (caddr_t) hs; 66 strncpy(atd.ad_name, ifname, sizeof(atd.ad_name)); 67 68 if (ioctl(s, SIOCGATHDIAG, &atd) < 0) { 69 err(1, "ioctl: %s", atd.ad_name); 70 return (0); 71 } 72 return (1); 73 } 74 75 static void 76 process_survey_stats(HAL_CHANNEL_SURVEY *hs) 77 { 78 int i; 79 float tx = 0.0, rx = 0.0, cc = 0.0, cext = 0.0; 80 float max_tx = 0.0, max_rx = 0.0, max_cc = 0.0, max_cext = 0.0; 81 uint64_t avg_tx = 0, avg_rx = 0, avg_cc = 0, avg_cext = 0; 82 float min_tx = 100.0, min_rx = 100.0, min_cc = 100.0, min_cext = 100.0; 83 int n = 0; 84 int cycle_count = 0, max_cycle_count = 0; 85 86 /* Calculate a percentage channel busy */ 87 for (i = 0; i < CHANNEL_SURVEY_SAMPLE_COUNT; i++) { 88 /* 89 * Skip samples with no cycle count 90 */ 91 if (hs->samples[i].cycle_count == 0) 92 continue; 93 n++; 94 95 /* 96 * Grab cycle count, calculate maximum just for curiousity 97 */ 98 cycle_count = hs->samples[i].cycle_count; 99 if (cycle_count > max_cycle_count) 100 max_cycle_count = cycle_count; 101 102 /* 103 * Calculate percentage 104 */ 105 tx = (float) hs->samples[i].tx_busy * 100.0 / 106 hs->samples[i].cycle_count; 107 rx = (float) hs->samples[i].rx_busy * 100.0 / 108 hs->samples[i].cycle_count; 109 cc = (float) hs->samples[i].chan_busy * 100.0 / 110 hs->samples[i].cycle_count; 111 cext = (float) hs->samples[i].ext_chan_busy * 100.0 / 112 hs->samples[i].cycle_count; 113 114 /* 115 * Update rolling average 116 * XXX to preserve some accuracy, keep two decimal points 117 * using "fixed" point math. 118 */ 119 avg_tx += (uint64_t) hs->samples[i].tx_busy * 10000 / 120 hs->samples[i].cycle_count; 121 avg_rx += (uint64_t) hs->samples[i].rx_busy * 10000 / 122 hs->samples[i].cycle_count; 123 avg_cc += (uint64_t) hs->samples[i].chan_busy * 10000 / 124 hs->samples[i].cycle_count; 125 avg_cext += (uint64_t) hs->samples[i].ext_chan_busy * 10000 / 126 hs->samples[i].cycle_count; 127 128 /* 129 * Update maximum values 130 */ 131 if (tx > max_tx) 132 max_tx = tx; 133 if (rx > max_rx) 134 max_rx = rx; 135 if (cc > max_cc) 136 max_cc = cc; 137 if (cext > max_cext) 138 max_cext = cext; 139 140 /* 141 * Update minimum values 142 */ 143 if (tx < min_tx) 144 min_tx = tx; 145 if (rx < min_rx) 146 min_rx = rx; 147 if (cc < min_cc) 148 min_cc = cc; 149 if (cext < min_cext) 150 min_cext = cext; 151 } 152 153 printf("(%4.1f %4.1f %4.1f %4.1f) ", 154 min_tx, min_rx, min_cc, min_cext); 155 printf("(%4.1f %4.1f %4.1f %4.1f) ", 156 n == 0 ? 0.0 : (float) (avg_tx / n) / 100.0, 157 n == 0 ? 0.0 : (float) (avg_rx / n) / 100.0, 158 n == 0 ? 0.0 : (float) (avg_cc / n) / 100.0, 159 n == 0 ? 0.0 : (float) (avg_cext / n) / 100.0); 160 printf("(%4.1f %4.1f %4.1f %4.1f)\n", 161 max_tx, max_rx, max_cc, max_cext); 162 } 163 164 int 165 main(int argc, char *argv[]) 166 { 167 FILE *fd = NULL; 168 const char *ifname; 169 int c, s; 170 int l = 0; 171 172 s = socket(AF_INET, SOCK_DGRAM, 0); 173 if (s < 0) 174 err(1, "socket"); 175 ifname = getenv("ATH"); 176 if (!ifname) 177 ifname = ATH_DEFAULT; 178 179 progname = argv[0]; 180 while ((c = getopt(argc, argv, "i:")) != -1) 181 switch (c) { 182 case 'i': 183 ifname = optarg; 184 break; 185 default: 186 usage(); 187 /*NOTREACHED*/ 188 } 189 argc -= optind; 190 argv += optind; 191 192 /* Now, loop over and fetch some statistics .. */ 193 while (1) { 194 HAL_CHANNEL_SURVEY hs; 195 memset(&hs, '\0', sizeof(hs)); 196 if (get_survey_stats(s, ifname, &hs) == 0) 197 break; 198 /* XXX screen height! */ 199 if (l % 23 == 0) { 200 printf(" " 201 "min " 202 "avg " 203 "max\n"); 204 printf(" tx%% rx%% bc%% ec%% "); 205 printf(" tx%% rx%% bc%% ec%% "); 206 printf(" tx%% rx%% bc%% ec%%\n"); 207 } 208 process_survey_stats(&hs); 209 sleep(1); 210 l++; 211 } 212 213 return (0); 214 } 215 216 217