Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

797 lines
20 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. ioclnt.c
  5. Abstract:
  6. I/O completion port perf
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 3/3/1996 Improved version of win32 sdk sockets sample.
  11. --*/
  12. #include "ioperf.h"
  13. #include <tchar.h>
  14. enum PROTOCOL {
  15. TCP = 0,
  16. SPX,
  17. NMPIPE,
  18. UDP
  19. } Protocol = TCP;
  20. CHAR *ProtocolNames[] = { "TCP/IP", "SPX", "Named Pipes", "UDP/IP" };
  21. typedef long STATUS;
  22. BOOL fUseTransact = 0;
  23. const char *USAGE = "-n <threads> -t <protocol> -s <server addr> -n <options>\n"
  24. "\t-n - Each threads acts as an additional client\n"
  25. "\t-t - tcp, spx, nmpipe (protseqs ok)\n"
  26. "\t-s - protocol specific address\n"
  27. "\t-n - Options:\n"
  28. "\t (named pipes) 0 - use writes/reads only\n"
  29. "\t (named pipes) 1 - use transactions for write-read\n"
  30. "\tDefault: 1 thread, named pipes, transactions, loopback\n"
  31. ;
  32. DWORD
  33. WINAPI
  34. NmWorker (
  35. PVOID ignored
  36. )
  37. {
  38. HANDLE hserver;
  39. DWORD startTime;
  40. DWORD endTime;
  41. DWORD totalTime;
  42. DWORD ReceiveBufferSize;
  43. DWORD SendBufferSize;
  44. MESSAGE Message;
  45. PMESSAGE pMessage;
  46. PMESSAGE pMessage2;
  47. INT err;
  48. DWORD i;
  49. BOOL b;
  50. DWORD nbytes, bytes_read;
  51. DWORD RequestSize;
  52. DWORD ReplySize;
  53. DWORD CompletedCalls;
  54. // Connect to the server
  55. TCHAR buffer[256];
  56. i = 0;
  57. while(buffer[i] = NetworkAddr[i])
  58. i++;
  59. _tcscat(buffer, NM_CLIENT_PORT);
  60. hserver = CreateFile(buffer,
  61. GENERIC_READ | GENERIC_WRITE,
  62. FILE_SHARE_READ | FILE_SHARE_WRITE,
  63. 0,
  64. OPEN_ALWAYS,
  65. (FILE_FLAG_OVERLAPPED, 0), // **********
  66. 0);
  67. if (hserver == INVALID_HANDLE_VALUE)
  68. {
  69. ApiError("CreateFile", GetLastError());
  70. }
  71. i = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  72. b = SetNamedPipeHandleState(hserver,
  73. &i,
  74. 0,
  75. 0);
  76. if (!b)
  77. {
  78. ApiError("SetNamedPipeHandleState", GetLastError());
  79. }
  80. // Prompt server for first test case
  81. Message.MessageType = CONNECT;
  82. b = WriteFile(hserver, (PVOID) &Message, sizeof (Message), &i, 0);
  83. if (!b || i != sizeof(Message))
  84. {
  85. ApiError("WriteFile", GetLastError());
  86. }
  87. // Wait for test case setup message
  88. b = ReadFile(hserver, &Message, sizeof(MESSAGE), &nbytes, 0);
  89. if (!b || nbytes != sizeof(MESSAGE))
  90. {
  91. ApiError("ReadFile", GetLastError());
  92. }
  93. if (Message.MessageType != SETUP)
  94. {
  95. printf("Expected message %08x, got %08x\n", SETUP, Message.MessageType);
  96. ApiError("Test sync", GetLastError());
  97. }
  98. RequestSize = Message.u.Setup.RequestSize;
  99. ReplySize = Message.u.Setup.ReplySize;
  100. // Allocate messages
  101. pMessage = Allocate(max(RequestSize, ReplySize));
  102. pMessage2 = Allocate(max(RequestSize, ReplySize));
  103. CompletedCalls = 0;
  104. startTime = GetTickCount ();
  105. do
  106. {
  107. DWORD bytes_written = 0;
  108. DWORD bytes_read;
  109. pMessage->MessageType = DATA_RQ;
  110. pMessage->u.Data.TotalSize = RequestSize;
  111. #define MAX_NM_BUF ((64*1024) - 1)
  112. while (RequestSize - bytes_written >= MAX_NM_BUF)
  113. {
  114. b = WriteFile(hserver, (PBYTE)pMessage + bytes_written, MAX_NM_BUF, &nbytes, 0);
  115. dbgprintf("WriteFile: %d %d (of %d)\n", b, nbytes, MAX_NM_BUF);
  116. if (!b || nbytes != MAX_NM_BUF)
  117. {
  118. ApiError("WriteFile", GetLastError());
  119. }
  120. bytes_written += MAX_NM_BUF;
  121. } // write >64k loop
  122. if (fUseTransact)
  123. {
  124. // write left over data and wait for reply
  125. b = TransactNamedPipe(hserver,
  126. pMessage,
  127. RequestSize - bytes_written,
  128. pMessage2,
  129. ((ReplySize >= MAX_NM_BUF) ? (MAX_NM_BUF) - 1: ReplySize),
  130. &nbytes,
  131. 0);
  132. bytes_read = nbytes;
  133. //dbgprintf("Transact: %d %d written, %d read\n", b, RequestSize - bytes_written, nbytes);
  134. if (!b && GetLastError() != ERROR_MORE_DATA && GetLastError() != ERROR_PIPE_BUSY)
  135. {
  136. ApiError("TransctNamedPipe", GetLastError());
  137. }
  138. }
  139. else
  140. {
  141. // read/write only case, write left over data
  142. if (bytes_written != RequestSize)
  143. {
  144. b = WriteFile(hserver, pMessage, RequestSize - bytes_written, &nbytes, 0);
  145. dbgprintf("WriteFile: %d %d (of %d)\n", b, nbytes, RequestSize - bytes_written);
  146. if (!b)
  147. {
  148. ApiError("WriteFile", GetLastError());
  149. }
  150. }
  151. bytes_read = 0;
  152. }
  153. while(bytes_read < ReplySize)
  154. {
  155. if (bytes_read > sizeof(MESSAGE))
  156. {
  157. if ( ( pMessage2->MessageType != DATA_RP
  158. && pMessage2->MessageType != FINISH )
  159. || pMessage2->u.Data.TotalSize != ReplySize )
  160. {
  161. printf("Got message %08x and size %d\n"
  162. "Expected message %08x and size %d\n",
  163. pMessage2->MessageType,
  164. pMessage2->u.Data.TotalSize,
  165. DATA_RP, ReplySize);
  166. ApiError("test sync", 0);
  167. }
  168. }
  169. b = ReadFile(hserver,
  170. (PBYTE)pMessage2 + bytes_read,
  171. ReplySize - bytes_read, &nbytes, 0);
  172. bytes_read += nbytes;
  173. dbgprintf("ReadFile: %d %d (of %d)\n", b, bytes_read, ReplySize);
  174. if (!b || nbytes == 0)
  175. {
  176. ApiError("ReadFile", GetLastError());
  177. }
  178. // Make sure we're doing ok.
  179. if (bytes_read > sizeof(MESSAGE))
  180. {
  181. }
  182. } // read loop
  183. CompletedCalls++;
  184. }
  185. while (pMessage2->MessageType != FINISH);
  186. endTime = GetTickCount ();
  187. totalTime = endTime - startTime;
  188. // Print results
  189. printf("Completed %d transactions in %d ms\n"
  190. "Sent %d bytes and received %d bytes\n"
  191. "%d T/S or %3d.%03d ms/T\n\n",
  192. CompletedCalls,
  193. totalTime,
  194. CompletedCalls * RequestSize,
  195. CompletedCalls * ReplySize,
  196. (CompletedCalls * 1000) / totalTime,
  197. totalTime / CompletedCalls,
  198. ((totalTime % CompletedCalls) * 1000) / CompletedCalls
  199. );
  200. Sleep(2000);
  201. // Close connection to remote host
  202. b = CloseHandle(hserver);
  203. if (!b)
  204. {
  205. ApiError("CloseHandle", GetLastError());
  206. }
  207. return(0);
  208. }
  209. DWORD
  210. WINAPI
  211. Worker (
  212. PVOID ignored
  213. )
  214. {
  215. HANDLE hserver;
  216. DWORD startTime;
  217. DWORD endTime;
  218. DWORD totalTime;
  219. DWORD ReceiveBufferSize;
  220. DWORD SendBufferSize;
  221. MESSAGE Message;
  222. PMESSAGE pMessage;
  223. DWORD iterations;
  224. INT err;
  225. DWORD i;
  226. DWORD bytesReceived;
  227. DWORD RequestSize;
  228. DWORD ReplySize;
  229. DWORD CompletedCalls;
  230. // TCP stuff
  231. SOCKET s;
  232. IN_ADDR TcpAddr;
  233. SOCKADDR_IN ServerAddrTcp;
  234. // SPX stuff
  235. if (Protocol == TCP)
  236. {
  237. //
  238. // Default to the loopback address for the Benchmark
  239. //
  240. TcpAddr.s_addr = htonl (INADDR_LOOPBACK);
  241. if (NetworkAddr != 0)
  242. {
  243. TcpAddr.s_addr = inet_addr(NetworkAddr);
  244. if (TcpAddr.s_addr == -1)
  245. {
  246. UNALIGNED struct hostent *phostent = gethostbyname(NetworkAddr);
  247. if (phostent == 0)
  248. {
  249. ApiError("Unable to resolve server address", GetLastError());
  250. }
  251. CopyMemory(&TcpAddr, phostent->h_addr, phostent->h_length);
  252. }
  253. }
  254. // Open a socket using the Internet Address family and TCP
  255. s = socket(AF_INET, SOCK_STREAM, 0);
  256. if (s == INVALID_SOCKET)
  257. {
  258. ApiError("socket", GetLastError());
  259. }
  260. // Connect to the server
  261. ZeroMemory (&ServerAddrTcp, sizeof (ServerAddrTcp));
  262. ServerAddrTcp.sin_family = AF_INET;
  263. ServerAddrTcp.sin_port = htons (TCP_PORT);
  264. ServerAddrTcp.sin_addr = TcpAddr;
  265. err = connect (s, (PSOCKADDR) & ServerAddrTcp, sizeof (ServerAddrTcp));
  266. if (err == SOCKET_ERROR)
  267. {
  268. ApiError("connect", GetLastError());
  269. }
  270. }
  271. else
  272. {
  273. ApiError("non-TCP not implemented yet", 0);
  274. }
  275. #if 0
  276. //
  277. // Set the receive buffer size...
  278. //
  279. err = setsockopt (s, SOL_SOCKET, SO_RCVBUF, (char *) &ReceiveBufferSize, sizeof (ReceiveBufferSize));
  280. if (err == SOCKET_ERROR)
  281. {
  282. printf ("DoEcho: setsockopt( SO_RCVBUF ) failed: %ld\n", GetLastError ());
  283. closesocket (s);
  284. return;
  285. }
  286. //
  287. // ...and the send buffer size for our new socket
  288. //
  289. err = setsockopt (s, SOL_SOCKET, SO_SNDBUF, (char *) &SendBufferSize, sizeof (SendBufferSize));
  290. if (err == SOCKET_ERROR)
  291. {
  292. printf ("DoEcho: setsockopt( SO_SNDBUF ) failed: %ld\n", GetLastError ());
  293. closesocket (s);
  294. return;
  295. }
  296. #endif
  297. // Prompt server for first test case
  298. Message.MessageType = CONNECT;
  299. send(s, (CHAR *) &Message, sizeof (Message), 0);
  300. bytesReceived = 0;
  301. do
  302. {
  303. // Will block here until all clients are ready for the test
  304. err = recv(s, (PUCHAR)&Message, sizeof(MESSAGE), 0);
  305. if (err == SOCKET_ERROR)
  306. {
  307. ApiError("recv", GetLastError());
  308. }
  309. bytesReceived += err;
  310. }
  311. while (bytesReceived < sizeof(MESSAGE));
  312. if (Message.MessageType != SETUP)
  313. {
  314. printf("Expected message %08x, got %08x\n", SETUP, Message.MessageType);
  315. ApiError("Test sync", GetLastError());
  316. }
  317. RequestSize = Message.u.Setup.RequestSize;
  318. ReplySize = Message.u.Setup.ReplySize;
  319. // Allocate message
  320. pMessage = Allocate(max(RequestSize, ReplySize));
  321. CompletedCalls = 0;
  322. startTime = GetTickCount();
  323. do
  324. {
  325. pMessage->MessageType = DATA_RQ;
  326. pMessage->u.Data.TotalSize = RequestSize;
  327. // Send request
  328. err = send(s, (PCHAR)pMessage, RequestSize, 0);
  329. if ((DWORD)err != RequestSize)
  330. {
  331. ApiError("send", GetLastError());
  332. }
  333. // Read as much as the remote host should send
  334. bytesReceived = 0;
  335. do
  336. {
  337. err = recv (s,
  338. ((PUCHAR)pMessage)+bytesReceived,
  339. ReplySize-bytesReceived,
  340. 0
  341. );
  342. if (err == SOCKET_ERROR)
  343. {
  344. ApiError("recv", GetLastError());
  345. }
  346. // FIX: Handle zero byte read as close
  347. bytesReceived += err;
  348. // Make sure we're doing ok.
  349. if (bytesReceived >= sizeof(MESSAGE))
  350. {
  351. if ( ( pMessage->MessageType != DATA_RP
  352. && pMessage->MessageType != FINISH)
  353. || pMessage->u.Data.TotalSize != ReplySize )
  354. {
  355. printf("Got message %08x and size %d\n"
  356. "Expected message %08x and size %d\n",
  357. pMessage->MessageType,
  358. pMessage->u.Data.TotalSize,
  359. DATA_RP, ReplySize);
  360. ApiError("test sync", 0);
  361. }
  362. }
  363. if (bytesReceived < ReplySize)
  364. {
  365. dbgprintf("Partial recv of %d (of %d)\n",
  366. bytesReceived, ReplySize);
  367. }
  368. }
  369. while (bytesReceived < (INT) ReplySize);
  370. CompletedCalls++;
  371. }
  372. while(pMessage->MessageType != FINISH);
  373. endTime = GetTickCount ();
  374. totalTime = endTime - startTime;
  375. // Print results
  376. printf("Completed %d transactions in %d ms\n"
  377. "Sent %d bytes and received %d bytes\n"
  378. "%d T/S or %3d.%03d ms/T\n\n",
  379. CompletedCalls,
  380. totalTime,
  381. CompletedCalls * RequestSize,
  382. CompletedCalls * ReplySize,
  383. (CompletedCalls * 1000) / totalTime,
  384. totalTime / CompletedCalls,
  385. ((totalTime % CompletedCalls) * 1000) / CompletedCalls
  386. );
  387. Sleep(2000);
  388. // Close connection to remote host
  389. err = closesocket (s);
  390. if (err == SOCKET_ERROR)
  391. {
  392. ApiError("closesocket", GetLastError());
  393. }
  394. return(0);
  395. }
  396. DWORD
  397. WINAPI
  398. UdpWorker(
  399. PVOID ignored
  400. )
  401. {
  402. HANDLE hserver;
  403. DWORD startTime;
  404. DWORD endTime;
  405. DWORD totalTime;
  406. DWORD ReceiveBufferSize;
  407. DWORD SendBufferSize;
  408. MESSAGE Message;
  409. PMESSAGE pMessage;
  410. DWORD iterations;
  411. INT err;
  412. DWORD i;
  413. DWORD Timeout;
  414. SOCKET s;
  415. IN_ADDR IpAddr;
  416. SOCKADDR_IN ServerAddr;
  417. SOCKADDR *pAddr = (PSOCKADDR)&ServerAddr;
  418. DWORD len = sizeof(SOCKADDR_IN);
  419. DWORD bytesReceived;
  420. DWORD RequestSize;
  421. DWORD ReplySize;
  422. DWORD CompletedCalls;
  423. //
  424. // Default to the loopback address for the Benchmark
  425. //
  426. IpAddr.s_addr = htonl (INADDR_LOOPBACK);
  427. if (NetworkAddr != 0)
  428. {
  429. IpAddr.s_addr = inet_addr(NetworkAddr);
  430. if (IpAddr.s_addr == -1)
  431. {
  432. UNALIGNED struct hostent *phostent = gethostbyname(NetworkAddr);
  433. if (phostent == 0)
  434. {
  435. ApiError("Unable to resolve server address", GetLastError());
  436. }
  437. CopyMemory(&IpAddr, phostent->h_addr, phostent->h_length);
  438. }
  439. }
  440. s = WSASocketW(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0, 0, 0);
  441. if (s == INVALID_SOCKET)
  442. {
  443. ApiError("socket", GetLastError());
  444. }
  445. ZeroMemory (&ServerAddr, sizeof (ServerAddr));
  446. ServerAddr.sin_family = AF_INET;
  447. ServerAddr.sin_port = htons(TCP_PORT);
  448. ServerAddr.sin_addr = IpAddr;
  449. #if 0
  450. // Connect to the server
  451. err = connect (s, (PSOCKADDR) &ServerAddr, sizeof (ServerAddr));
  452. if (err == SOCKET_ERROR)
  453. {
  454. ApiError("connect", GetLastError());
  455. }
  456. #endif
  457. // Prompt server for first test case
  458. Message.MessageType = CONNECT;
  459. Timeout = 1000;
  460. err = setsockopt(s,
  461. SOL_SOCKET,
  462. SO_RCVTIMEO,
  463. (char *) &Timeout,
  464. sizeof(Timeout)
  465. );
  466. if (err)
  467. {
  468. ApiError("setsockopt", GetLastError());
  469. }
  470. do
  471. {
  472. err = sendto(s, (CHAR *) &Message, sizeof (Message), 0, pAddr, len);
  473. if (err != sizeof(Message))
  474. {
  475. ApiError("sendto", GetLastError());
  476. }
  477. err = recvfrom(s, (PUCHAR)&Message, sizeof(MESSAGE), 0, pAddr, &len);
  478. if (err == sizeof(MESSAGE))
  479. {
  480. break;
  481. }
  482. if (GetLastError() == WSAETIMEDOUT)
  483. {
  484. printf("Request time out..\n");
  485. }
  486. }
  487. while (GetLastError() == WSAETIMEDOUT);
  488. if (err != sizeof(MESSAGE))
  489. {
  490. ApiError("recv", GetLastError());
  491. }
  492. pMessage = 0;
  493. Timeout = 1000;
  494. err = setsockopt(s,
  495. SOL_SOCKET,
  496. SO_RCVTIMEO,
  497. (char *) &Timeout,
  498. sizeof(Timeout)
  499. );
  500. if (err)
  501. {
  502. ApiError("setsockopt", GetLastError());
  503. }
  504. if (Message.MessageType != SETUP)
  505. {
  506. printf("Expected message %08x, got %08x\n", SETUP, Message.MessageType);
  507. ApiError("Test sync", GetLastError());
  508. }
  509. RequestSize = Message.u.Setup.RequestSize;
  510. ReplySize = Message.u.Setup.ReplySize;
  511. // Allocate message
  512. pMessage = Allocate(max(RequestSize, ReplySize));
  513. CompletedCalls = 0;
  514. startTime = GetTickCount ();
  515. do
  516. {
  517. pMessage->MessageType = DATA_RQ;
  518. pMessage->u.Data.TotalSize = RequestSize;
  519. // Send request
  520. do
  521. {
  522. err = sendto(s, (CHAR *) pMessage, RequestSize, 0, pAddr, len);
  523. if ((DWORD)err != RequestSize)
  524. {
  525. ApiError("sendto", GetLastError());
  526. }
  527. err = recvfrom(s, (PUCHAR)pMessage, ReplySize, 0, pAddr, &len);
  528. if ((DWORD)err == ReplySize)
  529. {
  530. break;
  531. }
  532. if (GetLastError() == WSAETIMEDOUT)
  533. {
  534. printf("Request time out..\n");
  535. }
  536. }
  537. while (GetLastError() == WSAETIMEDOUT);
  538. if ((DWORD)err != ReplySize)
  539. {
  540. ApiError("recv", GetLastError());
  541. }
  542. // Make sure we're doing ok.
  543. if ( ( pMessage->MessageType != DATA_RP
  544. && pMessage->MessageType != FINISH)
  545. || pMessage->u.Data.TotalSize != ReplySize )
  546. {
  547. printf("Got message %08x and size %d\n"
  548. "Expected message %08x and size %d\n",
  549. pMessage->MessageType,
  550. pMessage->u.Data.TotalSize,
  551. DATA_RP, ReplySize);
  552. ApiError("test sync", 0);
  553. }
  554. CompletedCalls++;
  555. }
  556. while(pMessage->MessageType != FINISH);
  557. endTime = GetTickCount ();
  558. totalTime = endTime - startTime;
  559. printf("Completed %d transactions in %d ms\n"
  560. "Sent %d bytes and received %d bytes\n"
  561. "%d T/S or %3d.%03d ms/T\n\n",
  562. CompletedCalls,
  563. totalTime,
  564. CompletedCalls * RequestSize,
  565. CompletedCalls * ReplySize,
  566. (CompletedCalls * 1000) / totalTime,
  567. totalTime / CompletedCalls,
  568. ((totalTime % CompletedCalls) * 1000) / CompletedCalls
  569. );
  570. Sleep(2000);
  571. // Close socket
  572. err = closesocket (s);
  573. if (err == SOCKET_ERROR)
  574. {
  575. ApiError("closesocket", GetLastError());
  576. }
  577. return(0);
  578. }
  579. typedef DWORD (*WORKER_FN) (LPVOID);
  580. int __cdecl
  581. main (
  582. int argc,
  583. char *argv[],
  584. char *envp[]
  585. )
  586. {
  587. WSADATA WsaData;
  588. STATUS status;
  589. DWORD threads;
  590. HANDLE *aClientThreads;
  591. int i;
  592. WORKER_FN pWorker;
  593. ParseArgv(argc, argv);
  594. if (_stricmp(Protseq, "tcp") == 0 || _stricmp(Protseq, "ncacn_ip_tcp") == 0 )
  595. {
  596. pWorker = Worker;
  597. Protocol = TCP;
  598. }
  599. else if ( _stricmp(Protseq, "spx") == 0 || _stricmp(Protseq, "ncacn_spx") == 0 )
  600. {
  601. pWorker = Worker;
  602. Protocol = SPX;
  603. }
  604. else if ( _stricmp(Protseq, "nmpipe") == 0 || _stricmp(Protseq, "ncacn_np") == 0 )
  605. {
  606. pWorker = NmWorker;
  607. Protocol = NMPIPE;
  608. }
  609. else if ( _stricmp(Protseq, "udp") == 0 || _stricmp(Protseq, "ncadg_ip_udp") == 0 )
  610. {
  611. pWorker = UdpWorker;
  612. Protocol = UDP;
  613. }
  614. if (Options[0] > 0)
  615. threads = Options[0];
  616. else
  617. threads = 1;
  618. if (Options[1] > 0)
  619. {
  620. if (Protocol == NMPIPE)
  621. {
  622. fUseTransact = Options[1];
  623. }
  624. }
  625. printf("%d client threads starting on %s\n", threads, ProtocolNames[Protocol]);
  626. if (Protocol != NMPIPE)
  627. {
  628. status = WSAStartup (0x2, &WsaData);
  629. CHECK_STATUS(status, "WSAStartup");
  630. }
  631. if (threads > 1)
  632. {
  633. DWORD i;
  634. aClientThreads = (HANDLE *)Allocate(sizeof(HANDLE) * threads);
  635. for (i = 0 ; i < threads; i++)
  636. {
  637. aClientThreads[i] = CreateThread(NULL,
  638. 0,
  639. pWorker,
  640. 0,
  641. 0,
  642. &status
  643. );
  644. if (aClientThreads[i] == 0)
  645. {
  646. ApiError("CreateThread", GetLastError());
  647. }
  648. }
  649. status = WaitForMultipleObjects(threads,
  650. aClientThreads,
  651. TRUE,
  652. INFINITE
  653. );
  654. if (status == WAIT_FAILED)
  655. {
  656. ApiError("WaitForMultipleObjects", GetLastError());
  657. }
  658. }
  659. else
  660. (pWorker)(0);
  661. printf("TEST DONE\n");
  662. return 0;
  663. }