Измерение полосы пропускания канала

We use cookies. Read the Privacy and Cookie Policy

Измерение полосы пропускания канала

На рис. А.7 приведена схема описываемой программы.

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

В листинге А.1 приведен текст первой половины программы bw_pipe, измеряющей полосу пропускания канала.

Листинг А.1. Функция main, измеряющая полосу пропускания канала

//bench/bw_pipe.c

1  #include "unpipc.h"

2  void reader(int, int, int);

3  void writer(int, int);

4  void *buf;

5  int totalnbytes, xfersize;

6  int

7  main(int argc, char **argv)

8  {

9   int i, nLoop, contpipe[2], datapipe[2];

10  pid_t childpid;

11  if (argc != 4)

12   err_quit("usage: bw_pipe <#loops> <#mbytes> <#bytes/write>");

13  nloop = atoi(argv[1]);

14  totalnbytes = atoi(argv[2]) * 1024 * 1024;

15  xfersize = atoi(argv[3]);

16  buf = Valloc(xfersize);

17  Touch(buf, xfersize);

18  Pipe(contpipe);

19  Pipe(datapipe);

20  if ((childpid = Fork()) == 0) {

21   writer(contpipe[0], datapipe[1]); /* child */

22   exit(0);

23  }

24  /* 4parent */

25  Start_time();

26  for (i = 0; i < nloop; i++)

27   reader(contpipe[1], datapipe[0], totalnbytes);

28  printf("bandwidth: %.3f MB/sec ",

29   totalnbytes / Stop_time() * nloop);

30  kill(childpid, SIGTERM);

31  exit(0);

32 }

Аргументы командной строки

11-15 Аргументы командной строки задают количество повторов (обычно 5), количество передаваемых мегабайтов (если указать 10, будет передано 10?1024?1024 байт) и количество байтов для каждой операции read и write (которое может принимать значения от 1024 до 65536 в наших измерениях).

Выделение буфера и помещение начального значения

16-17 Вызов valloc аналогичен malloc, но выделяемая память начинается с границы страницы памяти. Функция touch (листинг А.3) помещает 1 байт данных в каждую страницу буфера, заставляя ядро считать в память все страницы данного буфера. Мы всегда выполняем это перед проведением измерений.

ПРИМЕЧАНИЕ

Функция valloc не входит в стандарт Posix.1 и названа устаревшей в Unix 98. Она требовалась в ранних версиях спецификаций Х/Open, но уже не является необходимой. Обертка Valloc вызывает функцию malloc, если valloc недоступна.

Создание двух каналов

18-19 Создаются два канала: contpipe[0] и contpipe[1] используются для синхронизации процессов перед началом передачи, a datapipe[0] и datapipe[1] используются для передачи самих данных.

Вызов fork

20-31 Создается дочерний процесс, вызывающий функцию writer, а родительский процесс в это время вызывает функцию reader. Функция reader вызывается nlоор раз. Функция start_time вызывается непосредственно перед началом цикла, a stop_time — сразу после его окончания. Эти функции даны в листинге А.З. Полоса пропускания представляет собой количество байтов, переданных за все проходы цикла, поделенное на время, затраченное на передачу (stop_time возвращает количество микросекунд, прошедшее с момент запуска start_time). Затем дочерний процесс завершается сигналом SIGTERM и программа завершает свою работу. Вторая половина программы приведена в листинге А.2. Она состоит из функций reader и writer.

Листинг А.2. Функции reader и writer

//bench/bw_pipe.cvoid

33 void

34 writer(int contfd, int datafd)

35 {

36  int ntowrite;

37  for(;;) {

38   Read(contfd, &ntowrite, sizeof(ntowrite));

39   while (ntowrite > 0) {

40    Write(datafd, buf, xfersize);

41    ntowrite –= xfersize;

42   }

43  }

44 }

45 void

46 reader(int contfd, int datafd, int nbytes)

47 {

48  ssize_t n;

49  Write(contfd, &nbytes, sizeof(nbytes));

50  while ((nbytes > 0) &&

51   ((n = Read(datafd, buf, xfersize)) > 0)) {

52   nbytes –= n;

53  }

54 }

Функция writer

33-44 Функция writer представляет собой бесконечный цикл, вызываемый дочерним процессом. Он ожидает сообщения родительского процесса о готовности к приему данных, считывая целое число из управляющего канала. Это целое число определяет количество байтов, которое будет записано в канал данных. При получении этого числа дочерний процесс записывает данные в канал, отправляя их родителю. За один вызов write записывается xfersize байтов.

Функция reader

45-54 Эта функция вызывается родительским процессом в цикле. Каждый раз при вызове функции в управляющий канал записывается целое число, указывающее дочернему процессу на необходимость помещения соответствующего количества данных в канал данных. Затем функция вызывает read в цикле до тех пор, пока не будут приняты все данные.

Текст функций start_time, stop_time и touch приведен в листинге А.З.

Листинг А.З. Функции start_sime, stop_time и touch

//lib/timing.с

1  #include "unpipc.h"

2  static struct timeval tv_start, tv_stop;

3  int

4  start_time(void)

5  {

6   return(gettimeofday(&tv_start, NULL));

7  }

8  double

9  stop_time(void)

10 {

11  double clockus;

12  if (gettimeofday(&tv_stop, NULL) == –1)

13   return(0.0);

14  tv_sub(&tv_stop, &tv_start);

15  clockus = tv_stop.tv_sec * 1000000.0 + tv_stop.tv_usec;

16  return(clockus);

17 }

18 int

19 touch(void *vptr, int nbytes)

20 {

21  char *cptr;

22  static int pagesize = 0;

23  if (pagesize == 0) {

24   errno = 0;

25 #ifdef _SC_PAGESIZE

26   if ((pagesize = sysconf(_SC_PAGESIZE)) == –1)

27    return(-1);

28 #else

29   pagesize = getpagesize(); /* BSD */

30 #endif

31  }

32  cptr = vptr;

33  while (nbytes > 0) {

34   *cptr = 1;

35   cptr += pagesize;

36   nbytes –= pagesize;

37  }

38  return(0);

39 }

Текст функции tv_sub приведен в листинге А.4. Она осуществляет вычитание двух структур timeval, сохраняя результат в первой структуре.

Листинг А.4. Функция tv_sub: вычитание двух структур timeval

//lib/tv_sub.c

1  #include "unpipc.h"

2  void

3  tv_sub(struct timeval *out, struct timeval *in)

4  {

5   if ((out->tv_usec –= in->tv_usec) < 0) { /* out –= in */

6    --out->tv_sec;

7    out->tv_usec += 1000000;

8   }

9   out->tv_sec –= in->tv_sec;

10 }

На компьютере Sparc под управлением Solaris 2.6 при выполнении программы пять раз подряд получим следующий результат:

solaris % bw_pipe 5 10 65536

bandwidth: 13.722 MB/sec

solaris % bw_pipe 5 10 65536

bandwidth: 13.781 MB/sec

solaris % bw_pipe 5 10 65536

bandwidth: 13.685 MB/sec

solaris % bw_pipe 5 10 65536

bandwidth: 13.665 MB/sec

solaris % bw_pipe 5 10 65536

bandwidth: 13.584 MB/sec

Каждый раз мы задаем пять циклов, 10 Мбайт за цикл и 65536 байт за один вызов write или read. Среднее от этих пяти результатов даст величину 13,7 Мбайт в секунду, приведенную в табл. А.2.

Данный текст является ознакомительным фрагментом.