Книга: UNIX: взаимодействие процессов

Программа измерения полосы пропускания дверей

Программа измерения полосы пропускания дверей

Программа измерения полосы пропускания интерфейса дверей сложнее, чем предыдущие, поскольку нам нужно вызвать fork перед созданием двери. Родительский процесс создает дверь и с помощью канала оповещает дочерний процесс о том, что ее можно открывать.

Другое изменение заключается в том, что в отличие от рис. А.7 функция reader не принимает данные. Данные принимаются функцией server, которая является процедурой сервера для данной двери. На рис. А.8 изображена схема программы. 


Рис. А.8. Схема программы измерения полосы пропускания дверей

Поскольку двери поддерживаются только в Solaris, мы упростим программу, предполагая наличие двустороннего канала (раздел 4.4).

Еще одно изменение вызвано фундаментальным различием между передачей сообщений и вызовом процедуры. В программе, работавшей с очередью сообщений Posix, например, записывающий процесс просто помещал сообщения в очередь в цикле, что осуществляется асинхронно. В какой-то момент очередь будет заполнена или записывающий процесс будет просто приостановлен, и тогда считывающий процесс получит сообщения. Если, например, в очередь помещается 8 сообщений и записывающий процесс помещал в нее 8 сообщений каждый раз, когда получал управление, а считывающий процесс считывал 8 сообщений, отправка N сообщений требовала N/4 переключения контекста. Интерфейс дверей является синхронным: вызывающий процесс блокируется каждый раз при вызове door_call и не может возобновиться до тех пор, пока сервер не завершит работу. Передача N сообщений в этом случае требует N/2 переключений контекста. С той же проблемой мы столкнемся при измерении полосы пропускания вызовов RPC. Несмотря на увеличившееся количество переключений контекста, из рис. А.1 следует, что двери обладают наибольшей полосой пропускания при размере сообщений не более 25 Кбайт.

В листинге А.9 приведен текст функции main нашей программы. Функции writer, server и reader приведены в листинге А.10.

Листинг А.9. Функция main измерения полосы пропускания интерфейса дверей

//bench/bw_door.c
1  #include "unpipc.h"
2  void reader(int, int);
3  void writer(int);
4  void server(void *, char *, size_t, door_desc_t *, size_t);
5  void *buf;
6  int totalnbytes, xfersize, contpipe[2];
7  int
8  main(int argc, char **argv)
9  {
10  int i, nloop, doorfd;
11  char c;
12  pid_t childpid;
13  ssize_t n;
14  if (argc != 5)
15   err_quit("usage: bw_door <pathname> <#loops> <#mbytes> <#bytes/write>");
16  nloop = atoi(argv[2]);
17  totalnbytes = atoi(argv[3]) * 1024 * 1024;
18  xfersize = atoi(argv[4]);
19  buf = Valloc(xfersize);
20  Touch(buf, xfersize);
21  unlink(argv[1]);
22  Close(Open(argv[1], O_CREAT | O_EXCL | O_RDWR, FILE_MODE));
23  Pipe(contpipe); /* предполагается наличие двустороннего канала SVR4 */
24  if ((childpid = Fork()) == 0) {
25   /* дочерний процесс = клиент */
26   if ((n = Read(contpipe[0], &c, 1)) != 1)
27    err_quit("child: pipe read returned %d", n);
28   doorfd = Open(argv[1], O_RDWR);
29   writer(doorfd);
30   exit(0);
31  }
32  /* родительский процесс = сервер */
33  doorfd = Door_create(server, NULL, 0);
34  Fattach(doorfd, argv[1]);
35  Write(contpipe[1], &c, 1); /* уведомление о готовности двери */
36  Start_time();
37  for (i = 0; i < nloop; i++)
38   reader(doorfd, totalnbytes);
39  printf("bandwidth: %.3f MB/secn",
40  totalnbytes / Stop_time() * nloop);
41  kill(childpid, SIGTERM);
42  unlink(argv[1]);
43  exit(0);
44 }

Листинг A.10. Функции writer, server, reader для интерфейса дверей

//bench/bw_door.c
45 void
46 writer(int doorfd)
47 {
48  int ntowrite;
49  door_arg_t arg;
50  arg.desc_ptr = NULL; /* дескрипторы не передаются */
51  arg.desc_num = 0;
52  arg.rbuf = NULL; /* значения не возвращаются */
53  arg.rsize = 0;
54  for(;;) {
55   Read(contpipe[0], &ntowrite, sizeof(ntowrite));
56   while (ntowrite > 0) {
57    arg.data_ptr = buf;
58    arg.data_size = xfersize;
59    Door_call(doorfd, &arg);
60    ntowrite –= xfersize;
61   }
62  }
63 }
64 static int ntoread, nread;
65 void
66 server(void *cookie, char *argp, size_t arg_size,
67  door_desc_t *dp, size_t n_descriptors)
68 {
69  char c;
70  nread += arg_size;
71  if (nread >= ntoread)
72   Write(contpipe[0], &c, 1); /* запись закончена */
73  Door_return(NULL, 0, NULL, 0);
74 }
75 void
76 reader(int doorfd, int nbytes)
77 {
78  char c;
79  ssize_t n;
80  ntoread = nbytes; /* глобальные переменные процедуры сервера */
81  nread = 0;
82  Write(contpipe[1], &nbytes, sizeof(nbytes));
83  if ((n = Read(contpipe[1], &c, 1)) != 1)
84   err_quit("reader: pipe read returned %d", n);
85 }

Оглавление книги


Генерация: 1.473. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз