sarファイルのソースコードを読んでみよう

sarコマンド

sarコマンドはどこからネットワークの受信や送信情報を取得しているのだろうか。

気になったらコマンドのソースコードを読んでみよう。

ネットワークの情報は、/proc/netから読み込んでいると予想をたてさくらエディタでの
探検開始。

どうも「/proc/net/dev」が情報源と見える。

Every 2.0s: cat /proc/net/dev Thu Jul 9 22:01:07 2015

Inter-| Receive | Transmit
face |bytes packets errs drop fifo frame compressed multicast|bytes packets errs drop fifo colls carrier compressed
lo: 3770 45 0 0 0 0 0 0 3770 45 0 0 0 0 0 0
eth0: 149037 1724 0 0 0 0 0 13 337074 1287 0 0 0 0 0 0


ちなみにsar -n DEV の結果


22時01分35秒 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s
22時01分36秒 lo 0.00 0.00 0.00 0.00 0.00 0.00 0.00
22時01分36秒 eth0 2.00 2.00 0.12 0.54 0.00 0.00 0.00


さくらエディタでのgrep検索結果
sysstat-11.1.5\rd_stats.h(56,19) [SJIS]: #define NET_DEV "/proc/net/dev"


以下のコードで"/proc/net/dev"(NET_DEV)を読み込んでいる。
どうもソースからNIC数をカウントしている模様。

int get_iface_nr(void)

{
FILE *fp;

char line[128];

int iface = 0;

 

if *1 == NULL)

return 0; /* No network device file */

 


while (fgets(line, sizeof(line), fp) != NULL) {

if (strchr(line, ':')) {

iface++;

}

}


fclose(fp);


return iface;

}


次にここが総本山。この構造体がデータの格納場所のよう。間違いなさそう。

int read_net_dev(struct stats_net_dev *st_net_dev, int nbr)
{
FILE *fp;
struct stats_net_dev *st_net_dev_i;
char line[256];
char iface[MAX_IFACE_LEN];
int dev = 0;
int pos;

if *2 == NULL)
return 0;

while *3 {

pos = strcspn(line, ":");
if (pos < strlen(line)) {
st_net_dev_i = st_net_dev + dev;
strncpy(iface, line, MINIMUM(pos, MAX_IFACE_LEN - 1));
iface[MINIMUM(pos, MAX_IFACE_LEN - 1)] = '\0';
sscanf(iface, "%s", st_net_dev_i->interface); /* Skip heading spaces */
sscanf(line + pos + 1, "%llu %llu %*u %*u %*u %*u %llu %llu %llu %llu "
"%*u %*u %*u %*u %*u %llu",
&st_net_dev_i->rx_bytes,
&st_net_dev_i->rx_packets,
&st_net_dev_i->rx_compressed,
&st_net_dev_i->multicast,
&st_net_dev_i->tx_bytes,
&st_net_dev_i->tx_packets,
&st_net_dev_i->tx_compressed);
dev++;
}
}

fclose(fp);

return dev;
}

まずはこの関数「read_net_dev」を調べてみる
このあたりから少しわからなくなる。
なんとなくsarの表示の定義のよう。
activity.cから

* Network interfaces activity */
struct activity net_dev_act = {
.id = A_NET_DEV,
.options = AO_COLLECTED,
.magic = ACTIVITY_MAGIC_BASE + 2,
.group = G_DEFAULT,
#ifdef SOURCE_SADC
.f_count_index = 4, /* wrap_get_iface_nr() */
.f_count2 = NULL,
.f_read = ,
#endif
#ifdef SOURCE_SAR
.f_print = print_net_dev_stats,
.f_print_avg = print_net_dev_stats,
#endif
#ifdef SOURCE_SADF
.f_render = render_net_dev_stats,
.f_xml_print = xml_print_net_dev_stats,
.f_json_print = json_print_net_dev_stats,
.hdr_line = "IFACE;rxpck/s;txpck/s;rxkB/s;txkB/s;rxcmp/s;txcmp/s;rxmcst/s;%ifutil",
.name = "A_NET_DEV",
#endif
.nr = -1,
.nr2 = 1,
.fsize = STATS_NET_DEV_SIZE,
.msize = STATS_NET_DEV_SIZE,
.opt_flags = 0,
.buf = {NULL, NULL, NULL},
.bitmap = NULL
};


ちなみにintervalは
sysstat-11.1.5\sar.c(1179,14) [SJIS]: int main(int argc, char **argv)のなかの
intervalから取得していた。

else if (interval < 0) {
/* Get interval */
if (strspn(argv[opt], DIGITS) != strlen(argv[opt])) {
usage(argv[0]);
}
interval = atol(argv[opt++]);
if (interval < 0) {
usage(argv[0]);
}


ふむふむ。

結論として
受信と送信は「"/proc/net/dev"」から取得する。

*1:fp = fopen(NET_DEV, "r"

*2:fp = fopen(NET_DEV, "r"

*3:fgets(line, sizeof(line), fp) != NULL) && (dev < nbr