讨论:GetProcessIoCounters中的IO到底指的是什么IO

沙老师 2011-03-23 08:02:51
在做一个应用程序性能测量的程序,用到了这个函数,令人诧异的是,GOOGLE搜了个底朝天,根本没有关于其IO到底什么含义的详细解释,只有少数地方含糊地提到包含文件、网络等IO,无奈只得自己做实验,写了如下测试程序:


#include <windows.h>
#include <stdio.h>
#include <process.h>

void printIoDelta() {
static DWORD lastTickCount;
static IO_COUNTERS lastIoCounters;
DWORD tickCount;
IO_COUNTERS ioCounters;
static int firstTime = 1;

tickCount = GetTickCount();
if (!GetProcessIoCounters(GetCurrentProcess(), &ioCounters)) {
return;
}

if (firstTime) {
firstTime = 0;
printf(" Time Read Write Other Read(Bytes) Write(Bytes) Other(Bytes)\n");
printf("--------------------------------------------------------------------------------\n");
} else {
printf("%8lu%8llu%8llu%8llu%16llu%16llu%16llu\n",
tickCount - lastTickCount,
ioCounters.ReadOperationCount - lastIoCounters.ReadOperationCount,
ioCounters.WriteOperationCount - lastIoCounters.WriteOperationCount,
ioCounters.OtherOperationCount - lastIoCounters.OtherOperationCount,
ioCounters.ReadTransferCount - lastIoCounters.ReadTransferCount,
ioCounters.WriteTransferCount - lastIoCounters.WriteTransferCount,
ioCounters.OtherTransferCount - lastIoCounters.OtherTransferCount
);
}

lastTickCount = tickCount;
memcpy(&lastIoCounters, &ioCounters, sizeof(IO_COUNTERS));
}

void workerThread(void * dummy) {
int i;
FILE * fp;
char buff[500000];
WSADATA wsaData;
SOCKET s;
struct sockaddr_in localAddr;
struct sockaddr_in peerAddr;

memset(buff, 'X', sizeof(buff));

Sleep(2000);

// 写文件
fp = fopen("io.txt", "w");
if (fp) {
printf("fwrite = %d\n", fwrite(buff, 1, sizeof(buff), fp));
Sleep(10000);
// 关闭文件,测试Flush
printf("fclose\n");
fclose(fp);
Sleep(2000);
}

// 读文件
fp = fopen("io.txt", "r");
if (fp) {
printf("fread = %d\n", fread(buff, 1, sizeof(buff), fp));
fclose(fp);
Sleep(2000);
}

// 网络发

memset((void *)&localAddr, 0, sizeof(localAddr));
localAddr.sin_family = AF_INET;
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
localAddr.sin_port = htons(0);
memset((void *)&peerAddr, 0, sizeof(peerAddr));
peerAddr.sin_family = AF_INET;
peerAddr.sin_addr.s_addr = inet_addr("10.65.19.7");
peerAddr.sin_port = htons(3389);

printf("WSAStartup\n");
WSAStartup(MAKEWORD(2, 2), &wsaData);
Sleep(2000);

// UDP
printf("socket\n");
s = socket(AF_INET, SOCK_DGRAM, 0);
Sleep(2000);

printf("bind\n");
bind(s, (struct sockaddr *)&localAddr, sizeof(localAddr));
Sleep(2000);
for (i = 0; i < 20; i++) {
printf("sendto = %d\n", sendto(s, buff, i * 100, 0, (SOCKADDR *) &peerAddr, sizeof(peerAddr)));
Sleep(2000);
}
printf("closesocket\n");
closesocket(s);
Sleep(2000);

// TCP
printf("socket\n");
s = socket(AF_INET, SOCK_STREAM, 0);
Sleep(2000);

printf("bind\n");
bind(s, (struct sockaddr *)&localAddr, sizeof(localAddr));
Sleep(2000);

printf("connect\n");
connect(s, (SOCKADDR *) &peerAddr, sizeof(peerAddr));
Sleep(2000);

printf("send = %d\n", send(s, buff, sizeof(buff), 0));
Sleep(2000);

printf("closesocket\n");
closesocket(s);
Sleep(2000);

printf("WSACleanup\n");
WSACleanup();
}

int main(int argc, char ** argv) {
// 启动工作线程
_beginthread(workerThread, 0, 0);

printf("Ctrl-C to exit\n\n");
for (;;) {
printIoDelta();
Sleep(1000);
}
return 0;
}


其原理是在主线程中每隔1秒输出GetProcessIoCounters获取的6和数值相对于上1秒的差值,然后在工作线程中文件读写、TCP和UDP的发送操作。
...全文
759 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
野男孩 2011-03-25
  • 打赏
  • 举报
回复
嗯,果然。我也验证了一下,tcp的send和recv的流量都没有计算在这个I/O里面。
zyrr159487 2011-03-24
  • 打赏
  • 举报
回复
获取进程的I/O相关操作
sevencat 2011-03-24
  • 打赏
  • 举报
回复
不绑定本地端口,连另一台机器试试。
jwybobo2007 2011-03-24
  • 打赏
  • 举报
回复
应该属于
沙老师 2011-03-24
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 fishion 的回复:]

应该包含吧,难道是没发送成功了,所以就没显示?你写个客户端让这个程序进行通信行不
[/Quote]

应该发送成功了,我用抓包工具测过,另外程序显示的“sendto = ”和“send = ”就是这两个函数的返回值...今天再测一测,如果还是如此的话那只能按照这个经验性的结果往下做了...
沙老师 2011-03-24
  • 打赏
  • 举报
回复
http://technet.microsoft.com/en-us/library/cc749980.aspx

这里写道:

The Windows NT I/O architecture not only supports traditional file systems but has implemented its network redirector and server as file system drivers. The I/O Manager sees no difference between accessing files stored on a remote networked computer and accessing those stored locally on a hard disk. In addition, redirectors and servers can be loaded and unloaded dynamically, just like any other driver, and multiple redirectors and servers can coexist on the same computer.

从中可以猜测出所谓IO所包含的“网络”指的是类似于“网上邻居”之类的东西,Windows底层把它们等同于本地文件对待的
沙老师 2011-03-24
  • 打赏
  • 举报
回复
我用任务管理器观察了我们的一些网络通信程序(没有磁盘文件或数据库交互),其IO读写确实没有什么变化...更加确定了其IO是不包含网络的
沙老师 2011-03-24
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 sevencat 的回复:]
不绑定本地端口,连另一台机器试试。
[/Quote]

10.65.19.7是另外一台机器,我的机器是10.65.19.30,TCP和UDP的Socket肯定是要绑定本地IP地址和端口的...
fishion 2011-03-23
  • 打赏
  • 举报
回复
应该包含吧,难道是没发送成功了,所以就没显示?你写个客户端让这个程序进行通信行不
沙老师 2011-03-23
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 fishion 的回复:]

in-out不就是输入,输出吗
[/Quote]

关键问题是为什么GetProcessIoCounters获取的值不包含网络IO...
fishion 2011-03-23
  • 打赏
  • 举报
回复
in-out不就是输入,输出吗
IsItNothing 2011-03-23
  • 打赏
  • 举报
回复
你在系统的性能管理器里查看就可以验证你的程序了。
沙老师 2011-03-23
  • 打赏
  • 举报
回复

我记录下了程序的输出,非常诡异:


Ctrl-C to exit

Time Read Write Other Read(Bytes) Write(Bytes) Other(Bytes)
--------------------------------------------------------------------------------
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
fwrite = 500000
1000 0 98 1 0 499712 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
fclose
1000 0 1 1 0 288 0
1000 0 0 0 0 0 0
fread = 500000
1000 2 0 2 500000 0 0
1000 0 0 0 0 0 0
WSAStartup
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
socket
1000 0 0 37 0 0 0
1000 0 0 0 0 0 0
bind
1000 1 1 22 68 72 4270
1000 0 0 0 0 0 0
sendto = 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 100
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 200
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 300
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 400
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 500
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 600
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 700
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 800
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 900
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 1000
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
sendto = 1100
1000 0 0 1 0 0 1100
1000 0 0 0 0 0 0
sendto = 1200
1000 0 0 1 0 0 1200
1000 0 0 0 0 0 0
sendto = 1300
1000 0 0 1 0 0 1300
1000 0 0 0 0 0 0
sendto = 1400
1000 0 0 1 0 0 1400
1000 0 0 0 0 0 0
sendto = 1500
1000 0 0 1 0 0 1500
1000 0 0 0 0 0 0
sendto = 1600
1000 0 0 1 0 0 1600
1000 0 0 0 0 0 0
sendto = 1700
1000 0 0 1 0 0 1700
1000 0 0 0 0 0 0
sendto = 1800
1000 0 0 1 0 0 1800
1000 0 0 0 0 0 0
sendto = 1900
1000 0 0 1 0 0 1900
1000 0 0 0 0 0 0
closesocket
1000 0 0 1 0 0 0
1000 0 0 0 0 0 0
socket
1000 0 0 1 0 0 0
1000 0 0 0 0 0 0
bind
1000 0 0 2 0 0 1944
1000 0 0 0 0 0 0
connect
1000 0 0 2 0 0 0
1000 0 0 0 0 0 0
send = 500000
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
closesocket
1000 0 0 1 0 0 0
1000 0 0 0 0 0 0
WSACleanup
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
1000 0 0 0 0 0 0
^C


前面的文件读写和预料的差不多,写文件因为有缓存的存在,可以看到,直到fclose才将缓存中剩下的一点点内容写道硬盘中。

TCP和UDP的发送操作根本没有产生任何IO,这是令我最为不解的,只有bind时候产生了一些Others IO,另外UDP发送报文长度大于1000产生Others IO的原因后来也找到了:报文根本没有发出去,传回来的都是ICMP。

还有,我对比了任务管理器中有关IO的6栏,和GetProcessIoCounters返回的值是一致的,而任务管理器中的帮助明明写的是IO Read和IO Write是包含网络数据的,真TMD搞不懂了!!!

18,361

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧