gpt4 book ai didi

c - 测试 Fortran IPC : Sending 4 MiB of data using TCP/IP is equally fast as sending 100 B

转载 作者:可可西里 更新时间:2023-11-01 02:34:27 24 4
gpt4 key购买 nike

我目前正在测试在两个 Fortran 程序之间有效传递数据的不同方法。我试过写入文件、管道和 TCP/IP。我的测试结果如下所示。请注意,图表仅显示 4*10^4 B 的时间,因为这是我为文件和管道设置的高度。 4*10^6 B测试只针对TCP/IP程序进行。

为了测试执行时间,我使用了大多数 Linux 发行版中的 time 程序,即:time ./program。然后我使用 real 值作为我的时间。

Graph, showing the time it took to send, process, and send back data.

很明显,写入文件和使用管道是线性的。有一些开销,但它非常简单。然而,TCP/IP 协议(protocol)似乎不受影响 - 无论数据量如何。

实际发生的是:

  • B.f90 启动并调用 server.c,在 localhost:55555 上启动服务器
  • A.f90 启动并调用连接到服务器的 client.c
  • A.f90 将 N 个整数(每个 4 个字节)传递给 B.f90(通过客户端/服务器)
  • B.f90 对每个整数进行平方并将它们发送回 A.f90

可以在下面的 4 个不同程序中看到执行此操作的代码。令我感到困惑的是,该程序的 TCP/IP 版本似乎不受数据量的影响。我尝试在发布之前发送 10^6 个整数 (4 MiB),速度也一样快。然而,10^7 整数将导致程序崩溃(段错误)。

A.f90

program performance_test
use iso_c_binding, only: C_CHAR, C_NULL_CHAR, C_INT, C_PTR, C_LOC
implicit none

! Interfaces that ensure type compatability between Fortran and C.
interface
subroutine client(ipaddr, portnum) bind(C, name="client")
use iso_c_binding, only: c_char, c_int
character(kind=c_char) :: ipaddr(*)
integer(kind=c_int), value :: portnum
end subroutine client

subroutine calc(indata, length) bind(C, name="calc")
use iso_c_binding, only: c_ptr, c_int
implicit none
integer(c_int), value :: length
type(c_ptr), value :: indata
end subroutine calc

end interface

! type declaration statements
integer(c_int), allocatable, target :: array(:)
type(c_ptr) :: cptr
integer portno, length, i

! executable statements
! Call client.c and connect to localhost on port number `portno'.
portno=55555
call client(C_CHAR_"localhost"//C_NULL_CHAR, portno)

! Put numbers in the array
length = 1000000
allocate(array(0:length))
cptr=c_loc(array(1))

do i=1, length
array(i) = 2
end do

! Call client.c and pass the query on towards calcs.f90.
call calc(cptr, length)

deallocate(array)

end program performance_test

客户端.c

/* The original code for this client can be found here:
* http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/client.c */
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

// Static variables
static int sockfd;


/* This function is called when a system call fails. It displays a message about
* the error on stderr and then aborts the program. */
void error(char *msg)
{
perror(msg);
exit(0);
}

/* Callable function from Fortran, used by calcf.f90, to connect to a server.
*/
int client(char *ipaddr, int in_portno)
{
int portno;

struct sockaddr_in serv_addr;
struct hostent *server;

portno = in_portno;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");

server = gethostbyname(ipaddr);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}

memset(((char *) &serv_addr), 0, (sizeof(serv_addr)));
serv_addr.sin_family = AF_INET;
memcpy(((char *)server->h_addr),
((char *)&serv_addr.sin_addr.s_addr),
(server->h_length));
serv_addr.sin_port = htons(portno);

if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");

return 0;
}

/* Callable function from Fortran, used by calcf.f90, as a calculator.
* calc passes the query stored in buffer to server and returns the
* answer. */
int *calc(int *indata, int length)
{

int n;
n = write(sockfd, indata, sizeof(int)*length);
if (n < 0)
error("ERROR writing to socket");

n = read(sockfd, indata, sizeof(int)*length);
if (n < 0)
error("ERROR reading from socket");

return indata;
}

服务器.c

/* The original code for this server can be found here:
* http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/server.c */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <math.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

/* This function is called when a system call fails. It displays a message about
* the error on stderr and then aborts the program. */
void error(char *msg)
{
perror(msg);
exit(1);
}

/* Callable function from Fortran, used by calcs.f90, to start a server that
* can recieve queries. */
int server(int in_portno)
{
int sockfd, newsockfd, portno, clilen;

struct sockaddr_in serv_addr, cli_addr; int n;

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");

memset(((char *) &serv_addr), 0, (sizeof(serv_addr)));

portno = in_portno;

serv_addr.sin_family = AF_INET;

serv_addr.sin_addr.s_addr = INADDR_ANY;

serv_addr.sin_port = htons(portno);

if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");

listen(sockfd,5);

clilen = sizeof(cli_addr);

while(1)
{
int length = 1000000;
int indata[length];
newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
if (newsockfd < 0)
error("ERROR on accept");

// Here comes the query from client.c
n = read(newsockfd, indata, sizeof(int)*length);
if (n < 0) error("ERROR reading from socket");

square(indata);

// write returns the data to the client
n = write(newsockfd, indata, sizeof(int)*length);

if (n < 0) error("ERROR writing to socket");
}

return 0;

}

B.f90

program calculator_server

! Calculator at the server side of the client/server calculator
! Responsible for starting up the server server.c

use iso_c_binding, only: C_CHAR, C_NULL_CHAR, C_INT, C_PTR
implicit none

! type declaration statements
integer calc, ans, portnum, calculate

! Interface that ensures type compatibility between Fortran and C
interface
subroutine server(portnum) bind(C, name="server")
use iso_c_binding, only: c_int
integer(kind=c_int), value :: portnum
end subroutine server
subroutine square(intarray) bind(C, name="square")
use iso_c_binding
type(c_ptr), value :: intarray
end subroutine square
end interface

! Start the server with portnumber
portnum = 55555
call server(portnum)

end program calculator_server


! **********************************************************************
subroutine square(cptr) bind(C, name="square")
use iso_c_binding
implicit none

! Variable declarations
type(c_ptr) :: cptr
integer*8 :: iptr
integer :: length, i
integer pointee(1000000)
pointer(iptr, pointee)
iptr = loc(cptr)
length = 1000000

! Execution
do i = 1, length
pointee(i)= pointee(i)**2
end do
end subroutine square

我的问题很简单,如果我遗漏了什么。自然地,我在程序的各个阶段打印了数据,以确保它确实被传递、平方和发回,所以程序执行它应该执行的操作。但是,我无法理解数据量无关紧要。我目前无法在两台不同的机器上尝试该程序,否则我也会那样做。

非常感谢任何关于可能导致此行为的想法。

最佳答案

至少存在一个问题:read() 返回的数据可能少于请求的数据。同样,send() 可能不会发送所有数据。以下列方式插入一对 printf()server.c

// Here comes the query from client.c
n = read(newsockfd, indata, sizeof(int)*length);
if (n < 0) error("ERROR reading from socket");

printf("received %d, expected %lu\n", n, sizeof(int)*length);
square(indata);

// write returns the data to the client
n = write(newsockfd, indata, sizeof(int)*length);
printf("sent %d out of %lu\n", n, sizeof(int)*length);

执行时打印出来

received 43690, expected 4000000

sent 2539008 out of 4000000

因此只收到了预期数据的 1/90。

关于c - 测试 Fortran IPC : Sending 4 MiB of data using TCP/IP is equally fast as sending 100 B,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38054685/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com