Вателя и помещения их обратно в список текущих событий служит блок

UNLINK (вывести из списка), имеющий следующий формат:

             имя UNLINK X A,B,C,D,E,F

      В поле A указывается имя или номер списка пользователя. Поле B

содержит имя блока, в который переходят выведенные из списка поль-

зователя транзакты. В поле C указывается число выводимых транзактов

или ALL для вывода всех находящихся в списке транзактов.

      Операнды в полях D и E вместе со вспомогательным операндом X

определяют способ и условия вывода транзактов из списка пользовате-

ля. Если поля D и E пусты, то и операнд X не используется, а тран-

закты выводятся с начала списка пользователя. Если поле D содержит

  ключевое слово BACK, то поле E и вспомогательный операнд X не

используются, а транзакты выводятся с конца списка. В остальных

случаях значение поля D интерпретируется как номер параметра тран-

зактов, находящихся в списке пользователя, а из списка выводится

заданное число тех транзактов, у которых значение этого параметра

по отношению к значению операнда в поле E удовлетворяет условию,

заданному вспомогательным операндом X. Операнд X принимает те же

значения, что и в блоке TEST.

      В поле F указывается имя блока, куда переходит транзакт, выхо-

дящий из блока UNLINK, если из списка пользователя не выведен ни

один транзакт. Если это поле пусто, то выводящий транзакт переходит

в следующий блок независимо от количества выведенных транзактов.

     Например, блок

         UNLINK 5,NEXT,1

выводит из списка пользователя с номером 5 один транзакт с начала

списка и направляет его в блок с именем NEXT. Блок

         UNLINK BUFER,ENT1,1,BACK

выводит из списка пользователя с именем BUFER один транзакт с конца

списка и направляет его в блок с именем ENT1. Блок

         UNLINK E   P$UCH,MET2,ALL,COND,P$COND,MET3

выводит из списка пользователя, номер которого записан в параметре

UCH выводящего транзакта, и направляет в блок с именем MET2 все

транзакты, содержимое параметра COND которых равно содержимому од-

ноименного параметра выводящего транзакта. Если таких транзактов в

списке не окажется, то выводящий транзакт будет направлен в блок с

именем MET3, в противном случае - к следующему блоку.

      Следует отметить следующие особенности выполнения блока

UNLINK. Во-первых, если поля D и E содержат ссылки на СЧА транзак-

тов, то поле D вычисляется относительно транзактов в списке пользо-

вателя, а поле E - относительно активного транзакта. Во-вторых,

после вывода транзактов из списка симулятор продолжает или начинает

продвижение транзакта с наивысшим приоритетом, а при равенстве при-

оритетов отдает предпочтение транзакту-инициатору вывода.

      Каждый список пользователя имеет следующие СЧА: CH - текущая

длина списка; CA - средняя длина списка (целая часть); CM - макси-

мальная длина списка; CC - общее число транзактов, вошедших в

список; CT - целая часть среднего времени пребывания транзакта в

списке.

      Воспользуемся рассмотренными блоками для моделирования много-

канальной СМО с ожиданием транзактов в списке пользователя (рис.

17). Если МКУ с именем STO2 не заполнено, блок GATE впускает вновь

прибывший транзакт в блок ENTER, и в МКУ занимается один канал.

Если же МКУ заполнено, то блок GATE направляет транзакт в блок LINK

с именем WAIT, помещающий транзакт в конец списка пользователя с

именем BUFER, моделирующего очередь к МКУ. Каждый транзакт, покида-

ющий МКУ по завершении обслуживания и освобождающий один канал,

проходит блок UNLINK и выводит один транзакт с начала списка (если

список не пуст), направляя его в блок с именем ENT1 на занятие ка-

нала в МКУ.

 

    STO2 STORAGE 2

    EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

           GENERATE 100,FN$EXP

           GATE SNF STO2,WAIT

    ENT1 ENTER  STO2

           ADVANCE 160,FN$EXP

           LEAVE  STO2

           UNLINK BUFER,ENT1,1

           TERMINATE 1

    WAIT LINK   BUFER,FIFO

 

                         Рис. 17

 

      Заметим, что для изменения дисциплины обслуживания на "позже

пришел - раньше обслужен" достаточно или заменить в поле B блока

LINK FIFO на LIFO, или записать в поле D блока UNLINK операнд BACK.

Следует также обратить внимание на то, что блоки QUEUE-DEPART для

сбора статистики об ожидающих транзактах не используются, так как

почти все те же данные можно получить из статистики о списке поль-

зователя.

      Рассмотрим еще один пример, иллюстрирующий использование

списков пользователя для организации нестандартных дисциплин обслу-

живания. Пусть в одноканальной СМО с ожиданием требуется организо-

вать такую дисциплину, при которой приоритет отдается заявкам с на-

именьшим временем обслуживания. Такая модель будет иметь вид, пока-

занный на рис. 18.

      В параметр TSRV поступающих в модель транзактов в блоке ASSIGN

записывается случайное время обслуживания, вычисляемое с использо-

ванием функции EXP. Если устройство SYSTEM свободно, то блок GATE

впускает транзакт в блок SEIZE, и устройство занимается на время

P$TSRV. Если же в момент поступления транзакта устройство занято,

то блок GATE направляет транзакт в блок LINK, который вводит тран-

 

   EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

           GENERATE 100,FN$EXP

           ASSIGN TSRV,80,EXP

           GATE NU SYSTEM,WAIT

    SFAC SEIZE  SYSTEM

           ADVANCE P$TSRV

           RELEASE SYSTEM

           UNLINK LINE,SFAC,1

           TERMINATE 1

    WAIT LINK   LINE,P$TSRV

 

                         Рис. 18

 

закт в список пользователя LINE, упорядочивая транзакты по воз-

растанию времени обслуживания, записанного в параметре P$TSRV. Блок

UNLINK по освобождении устройства выводит с начала списка транзакт

с наименьшим временем обслуживания, обеспечивая тем самым заданную

дисциплину.

 

            3. УПРАВЛЯЮЩИЕ ОПЕРАТОРЫ GPSS/PC

 

      Для управления прогоном модели используются управляющие опера-

торы GPSS/PC. С одним из них - оператором START - мы уже сталкива-

лись при рассмотрении блока TERMINATE. Оператор START (начать) име-

ет следующий формат:

                    START A,B,C,D

     Поле A содержит константу, задающую начальное значение счетчи-

ка завершений. В поле B может быть записано ключевое слово NP -

признак подавления формирования стандартного отчета по завершении

моделирования. Если поле B пусто, то по окончании прогона модели

формируется отчет со стандартной статистической информацией о всех

объектах модели (см. разд. 5). Поле C не используется и сохранено

для совместимости со старыми версиями GPSS. Поле D может содержать

1 для включения в отчет списков текущих и будущих событий. Если по-

ле D пусто, то выдача в отчет содержимого этих списков не произво-

дится.

 

      Оператор SIMULATE (моделировать) устанавливает предел реально-

го времени, отводимого на прогон модели. Если прогон не завершится

до истечения этого времени, то он будет прерван принудительно с вы-

дачей накопленной статистики в отчет.

      Оператор SIMULATE имеет единственный операнд A, содержащий

предельное время моделирования в минутах, задаваемое константой.

Оператор размещается перед оператором START, начинающим лимитиро-

ванный прогон.

 

      Оператор RMULT (установить значения генераторов) позволяет пе-

    ред началом прогона установить начальные значения генераторов слу-

чайных чисел RN, определяющие генерируемые ими последовательности.

Поля A-G оператора могут содержать начальные значения генераторов

соответственно RN1-RN7, задаваемые константами. Начальные значения

генераторов, не установленные операторами RMULT, совпадают с номе-

рами генераторов.

 

      Оператор RESET (сбросить) сбрасывает всю статистическую инфор-

мацию, накопленную в процессе прогона модели. При этом состояние

аппаратных, динамических и запоминающих объектов, а также генерато-

ров случайных чисел сохраняется, и моделирование может быть возоб-

новлено с повторным сбором статистики. Оператор не имеет операндов.

     С оператором RESET связано различие между относительным (СЧА

C1) и абсолютным (СЧА AC1) модельным временем. Таймер относительно-

го времени C1 измеряет модельное время, прошедшее после последнего

сброса статистики оператором RESET, а таймер абсолютного времени

AC1 - модельное время, прошедшее после начала первого прогона моде-

ли. Если не использовалось ни одного оператора RESET, то значения

этих таймеров совпадают. Оператор RESET устанавливает таймер C1 в

ноль и не влияет на таймер AC1.

      Оператор RESET используется обычно при моделировании нестацио-

нарных процессов, когда требуется собрать статистику по отдельным

интервалам стационарности или исключить влияние переходного периода

на собираемую статистическую информацию.

      Пусть, например, в модели, приведенной на рис. 18, необходимо

отбросить статистику, собираемую на первой тысяче транзактов. Это

может быть сделано способом, показанным на рис. 19.

      Первый оператор START начинает прогон модели длиной 1000 тран-

зактов (переходный период). Поскольку статистика, накопленная на

этом периоде, не используется, в поле B оператора указан признак

подавления формирования отчета NP. Оператор RESET сбрасывает накоп-

ленную статистику, не изменяя состояния модели. Второй оператор

START начинает основной прогон модели с формированием отчета по за-

вершении прогона.

   EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

           GENERATE 100,FN$EXP

           ASSIGN TSRV,80,EXP

           GATE NU SYSTEM,WAIT

    SFAC SEIZE  SYSTEM

           ADVANCE P$TSRV

           RELEASE SYSTEM

           UNLINK LINE,SFAC,1

           TERMINATE 1

    WAIT LINK   LINE,P$TSRV

           START  1000,NP

           RESET

           START  10000

 

                         Рис. 19

 

      Оператор CLEAR (очистить) очищает модель, подготавливая ее к

повторному прогону. При этом сбрасывается вся накопленная в преды-

дущем прогоне статистика, из модели удаляются все транзакты, и она

приводится к исходному состоянию, как перед первым прогоном. Уста-

навливаются в ноль сохраняемые величины и матрицы, что следует учи-

тывать при использовании этих объектов для хранения исходных дан-

ных. Исключение составляют генераторы случайных чисел, которые не

 возвращаются к своим начальным значениям, что позволяет повторить

прогон модели на новой последовательности случайных чисел. Оператор

не имеет операндов.

      Оператор CLEAR используется обычно для организации нескольких

независимых прогонов модели на разных последовательностях случайных

чисел. Перед повторением прогона можно при необходимости переопре-

делить отдельные объекты модели, например емкости многоканальных

устройств.

      Пусть, например, требуется повторить прогон модели, приведен-

ной на рис. 17, три раза при емкости МКУ, равной 1, 2 и 3. Это мо-

жет быть выполнено так, как показано на рис. 20. После каждой

очистки модели оператором CLEAR оператор STORAGE устанавливает но-

вое значение емкости МКУ с именем STO2.

  

    Оператор END (закончить) завершает сеанс 0работы с GPSS/PC и

возвращает управление в операционную систему. Оператор не имеет

операндов.

 

  STO2 STORAGE 1

   EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

           GENERATE 100,FN$EXP

           GATE SNF STO2,WAIT

    ENT1 ENTER  STO2

           ADVANCE 160,FN$EXP

           LEAVE  STO2

           UNLINK BUFER,ENT1,1

           TERMINATE 1

    WAIT LINK   BUFER,FIFO

           START  10000

           CLEAR

    STO2 STORAGE 2

           START  10000

           CLEAR

    STO2 STORAGE 3

           START  10000

 

                         Рис. 20

 

      Как правило, управляющие операторы не включаются в исходную

программу, т.е. не имеют номеров строк, а вводятся пользователем

непосредственно с клавиатуры ПК.


 

    4. НЕКОТОРЫЕ ПРИЕМЫ КОНСТРУИРОВАНИЯ GPSS-МОДЕЛЕЙ

 

                4.1. Косвенная адресация

 

В рассматривавшихся до сих пор примерах моделей ссылки на раз-

личные объекты GPSS/PC производились исключительно по данным им

произвольным именам. Такая адресация объектов удобна, когда речь

идет о небольшом числе объектов каждого типа. Если же число объек-

тов некоторого типа велико, то во избежание пропорционального роста

количества блоков в модели используют ссылки на эти объекты по их

номерам с использованием так называемой косвенной адресации.

Идея косвенной адресации заключается в том, что каждый тран-

закт в некотором своем параметре содержит номер того или иного объ-

екта, а в полях блоков, адресующихся к объектам, записывается ссыл-

ка на этот параметр транзакта. Проиллюстрируем применение косвенной

адресации на примере следующей модели.

 

   EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

    CLASS FUNCTION RN1,D3

  .333,1/.667,2/1,3

    MEAN FUNCTION P$TYPE,L3

   1,70/2,80/3,90

    PRIOT VARIABLE 4-P$TYPE

    STO2 STORAGE 2

    WTIME QTABLE LINE,50,50,10

    TTIME TABLE  M1,100,100,12

           GENERATE 100,FN$EXP

           ASSIGN TYPE,FN$CLASS

           PRIORITY V$PRIOT

           QUEUE  LINE

           QUEUE  P$TYPE

           ENTER  STO2

           DEPART P$TYPE

           DEPART LINE

           ADVANCE FN$MEAN,FN$EXP

           LEAVE  STO2

           TABULATE TTIME

           TERMINATE 1

 

                         Рис. 21

 

Пусть на вход моделируемой многоканальной СМО с двумя каналами

обслуживания поступает пуассоновский поток заявок со средним интер-

валом поступления 100 единиц модельного времени. Каждая заявка с

равной вероятностью 1/3 относится к одному из трех классов: 1, 2

или 3, а среднее время обслуживания заявок каждого типа составляет

соответственно 70, 80 и 90 единиц модельного времени. Чем меньше

среднее время обслуживания заявки, тем выше ее приоритет. Необходи-

мо построить модель, позволяющую оценить средние значения времени

ожидания заявок каждого типа, а также распределения общего времени

ожидания в очереди и общего времени пребывания в системе. Такая мо-

дель имеет вид, показанный на рис. 21.

Переменная PRIOT служит для вычисления приоритета транзакта

как функции его класса, содержащегося в параметре с именем TYPE.

Транзакты класса 1 (P$TYPE=1) получат приоритет 3, транзакты класса

2 - приоритет 2 и транзакты класса 3 - приоритет 1.

В блоке ASSIGN в параметр TYPE транзактов записывается класс

заявки, разыгрываемый с помощью функции CLASS. В следующем блоке

PRIORITY с помощью переменной PRIOT определяется приоритет транзак-

тов, первоначально равный 0 (отсутствует поле E в блоке GENERATE).

Далее каждый транзакт "отмечается" в блоках QUEUE в двух оче-

редях. Очередь с именем LINE является общей для транзактов всех

классов. Входя в следующий блок QUEUE, транзакт отмечается в очере-

ди с номером 1, 2 или 3 в зависимости от класса заявки, записанного

в параметре TYPE. Аналогичным образом фиксируется уход из очередей

в блоках DEPART. Таким образом, в модели создается четыре объекта

типа "очередь": одна очередь с именем LINE и три с номерами 1, 2 и

3. При этом три последние очереди создаются одной парой блоков

QUEUE-DEPART! В этом и заключается эффект косвенной адресации.

Как уже отмечалось ранее, каждому имени объекта симулятор сам

ставит в соответствие некоторый номер. При ссылках на объекты одно-

го и того же типа одновременно по именам и номерам, как это имеет

место в рассматриваемом примере, существует опасность параллельной

адресации к одному и тому же объекту вместо двух разных или, наобо-

рот, к двум разным объектам вместо одного. Так, в рассматриваемой

модели мы, вообще говоря, не знаем, какой именно номер поставит си-

мулятор в соответствие имени очереди LINE. Если этот номер будет от

1 до 3, то это приведет к ошибке, так как в модели окажется не че-

тыре очереди, а три, причем в одну из них будет заноситься информа-

ция как обо всех транзактах, так и дополнительно о транзактах одно-

го из трех классов. Как избежать такой ситуации?

К счастью, в большинстве случаев об этом можно не заботиться,

поскольку симулятор ставит в соответствие именам объектов достаточ-

но большие номера, начиная с 10000. При необходимости же можно

воспользоваться оператором EQU, о котором уже говорилось выше, и

самостоятельно сопоставить имени объекта желаемый номер. Например,

в рассматриваемой модели для того, чтобы очередь с именем LINE име-

ла номер 4, достаточно записать оператор:

                    LINE EQU 4

 

          4.2. Обработка одновременных событий

 

Так как модельное время в GPSS целочисленно, то оказывается

вполне вероятным одновременное наступление двух или более событий,

причем вероятность этого тем больше, чем крупнее выбранная единица

модельного времени. В некоторых случаях одновременное наступление

нескольких событий, или так называемый временной узел, может су-

щественно нарушить логику модели.

Рассмотрим, например, еще раз модель на рис. 14. Здесь может

образоваться временной узел между событиями "поступление транзакта

на вход модели" и "завершение обслуживания в МКУ". Если не-

посредственно перед завершением обслуживания были заняты оба канала

МКУ, то обработка временного узла зависит от последовательности

транзактов, соответствующих событиям, в списке текущих событий.

Предположим, что первым в списке расположен транзакт, освобож-

дающий канал МКУ. Тогда вначале будет обработан этот транзакт, т.е.

событие "завершение обслуживания в МКУ", причем условие "МКУ STO2

не заполнено", проверяемое в блоке GATE, станет истинным. Затем бу-

дет обработан транзакт, поступивший на вход модели, в блок GATE с

именем ENT1, из блока GENERATE или из блока TRANSFER в безусловном

режиме. При этом транзакт будет впущен в блок ENTER, и МКУ в тот же

момент модельного времени снова окажется заполненным. Такая ситуа-

ция при обработке временного узла представляется естественной.

Предположим теперь, что первым в списке текущих событий распо-

ложен транзакт, поступающий на вход модели. Так как условие "МКУ

STO2 не заполнено" ложно, то блок GATE направит этот транзакт в

блок с именем REFUS. Таким образом, в модели будет зафиксирован от-

каз в обслуживании, хотя в этот же момент модельного времени, после

обработки транзакта, освобождающего канал, МКУ станет доступным.

Порядок расположения транзактов, соответствующих рассматривае-

мым событиям, в списке текущих событий случаен, и в среднем в поло-

вине случаев временной узел будет обрабатываться не так, как нужно.

В результате статистика, связанная с отказами, окажется искаженной.

Для правильной обработки временного узла надо обеспечить такой

порядок расположения транзактов в списке текущих событий, чтобы

транзакт, освобождающий МКУ, всегда располагался первым. Этого мож-

но добиться, управляя приоритетами транзактов (рис. 22).

 

    STO2 STORAGE 2

    EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

           GENERATE 100,FN$EXP

    ENT1 GATE SNF STO2,REFUS

           ENTER  STO2

           PRIORITY 1

           ADVANCE 160,FN$EXP

           LEAVE  STO2

           TERMINATE 1

    REFUS TRANSFER.1,,OUT

           ADVANCE 250,FN$EXP

           TRANSFER,ENT1

    OUT TERMINATE 1

 

                         Рис. 22

 

Транзакты, поступающие в модель через блок GENERATE, имеют ну-

левой приоритет. Такой же приоритет имеют транзакты, получившие от-

каз в обслуживании, направленные в блок с именем REFUS и затем пов-

торно поступающие в блок с именем ENT1. Те же транзакты, что посту-

пают на обслуживание, повышают приоритет до 1 в блоке PRIORITY, и

после выхода из блока ADVANCE возвращаются из списка будущих в

список текущих событий, располагаясь в начале списка. Таким обра-

зом, нужный порядок транзактов обеспечивается, и временной узел бу-

дет обработан правильно.

Опасность неверной обработки временных узлов характерна для

моделей со списками пользователя. Рассмотрим, например, еще раз мо-

дель на рис. 18. Здесь также возможен временной узел между события-

ми "приход транзакта" и "завершение обслуживания транзакта".

Пусть первым в списке текущих событий располагается вновь при-

шедший транзакт. Так как устройство с именем SYSTEM занято, то блок

GATE направит этот транзакт в блок LINK, и он будет введен в список

пользователя с именем LINE. Затем будет обработан транзакт, осво-

бождающий устройство. Проходя через блок UNLINK, он выведет тран-

закт с начала списка пользователя и направит его в список текущих

событий, где тот продвинется в блок SEIZE, занимая устройство

SYSTEM.

Если же первым в списке текущих событий располагается тран-

закт, освобождающий устройство, то он выведет первый из ожидающих

транзактов из списка пользователя в список текущих событий, где тот

расположится после вновь пришедшего транзакта. Поэтому первым будет

обработан вновь пришедший транзакт, который пройдет через блок GATE

и займет устройство "без очереди". Транзакт-очередник, который был

выведен из списка пользователя, "застрянет" перед блоком SEIZE и

после очередного освобождения устройства займет его, нарушая, в

свою очередь, логику работы модели.

Проведенный анализ показывает, что для правильной обработки

временного узла необходимо обеспечить такой порядок расположения

транзактов в списке текущих событий, чтобы первым всегда распола-

гался вновь пришедший транзакт. В рассматриваемом случае этого мож-

но добиться, используя блок PRIORITY с операндом BU (рис. 23).

Перед освобождением устройства обслуженный транзакт проходит

через блок PRIORITY, который, оставляя неизменным приоритет тран-

закта PR, переводит его в конец списка текущих событий. При новом

просмотре списка в случае наличия временного узла начинает обраба-

тываться вновь поступивший транзакт. Так как устройство еще занято,

он направляется блоком GATE в список пользователя. При повторной

обработке обслуженного транзакта тот освобождает устройство и выво-

дит очередной транзакт из списка пользователя. Таким образом, пра-

вильная обработка временного узла обеспечивается и в этом случае.

 

   EXP FUNCTION RN1,C24

   0,0/.1,.104/.2,.222/.3,.355/.4,.509/.5,.69/.6,.915

  .7,1.2/.75,1.38/.8,1.6/.84,1.85/.88,2.12/.9,2.3

  .92,2.52/.94,2.81/.95,2.99/.96,3.2/.97,3.5/.98,3.9

  .99,4.6/.995,5.3/.998,6.2/.999,7/.9998,8

           GENERATE 100,FN$EXP

           ASSIGN TSRV,80,EXP

           GATE NU SYSTEM,WAIT

    SFAC SEIZE  SYSTEM

           ADVANCE P$TSRV

           PRIORITY PR,BU

           RELEASE SYSTEM

           UNLINK LINE,SFAC,1

           TERMINATE 1

    WAIT LINK   LINE,P$TSRV

 

                         Рис. 23

 

 

    5. КОМАНДЫ GPSS/PC И ТЕХНОЛОГИЯ РАБОТЫ С ПАКЕТОМ

 

           5.1. Загрузка интегрированной среды

 

Пакет GPSS/PC включает в себя два основных модуля: модуль

GPSSPC.EXE, представляющий интегрированную среду, в которой произ-

водится ввод, редактирование, отладка и выполнение модели, и модуль

GPSSREPT.EXE, предназначенный для получения стандартного отчета

GPSS/PC. Загрузка обоих модулей производится обычным образом из ко-

мандной строки MS DOS или из программы-оболочки Norton Commander.

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

"заставка" с названием пакета: начинается так называемый сеанс ра-

боты с GPSS/PC. Затем заставка гасится, и появляется экран, разде-

ленный на две части: большая верхняя часть содержит так называемое

окно данных, меньшая нижняя часть - окно команд. Окно данных в на-

чальный момент пусто, в окне команд в верхней командной строке

высвечен символ "приглашения" >, сигнализирующий о готовности

системы принимать команды.

 

                 5.2. Ввод новой модели

 

Если исходная программа с моделью еще не введена и не записана

на диске, то необходимо ввести ее с клавиатуры. Ввод производится в

командную строку. Сначала вводится номер строки очередного операто-

ра и нажимается клавиша Пробел. Курсор автоматически перемещается к

началу следующего поля - поля имени, и в позиции курсора высвечива-

ется символ L, сигнализирующий о том, что вы находитесь в поле

имени (LABEL - метка). Если оператор имеет имя, необходимо ввести

его и нажать клавишу Пробел, в противном случае - сразу нажать кла-

вишу Пробел. В любом случае курсор переходит к началу следующего

поля - поля операции, о чем сигнализирует символ V (VERB - глагол)

в позиции курсора. Необходимо ввести название оператора и нажать

клавишу Пробел. Очень удобным является то, что название оператора

не обязательно вводить полностью: как только транслятор распознает

оператор по нескольким первым буквам, он после нажатия клавиши Про-

бел сам дополнит его до полного названия.

При синтаксической ошибке в операторе под командной строкой

появляется указатель на место ошибки, причем ошибочный символ не

вводится. Необходимо в этом случае повторить ввод символа.

Аналогичным образом вводятся поля операндов, при этом в пози-

ции курсора высвечивается обозначение текущего поля (A,B,...,G).

Для перехода к следующему полю операндов вводится запятая, для пе-

рехода к полю комментариев - Пробел. При переходе курсора в поле

комментариев в позиции курсора высвечивается символ;, сигнализи-

рующий о возможности начать ввод комментария.

По окончании ввода последнего поля операндов или комментария

следует нажать клавишу Enter, при этом введенный оператор трансли-

руется и отображается в окне данных, а командная строка очищается,

и в ее первой позиции снова появляется символ "приглашения".

По мере ввода новых операторов окно данных заполняется, и по

окончании ввода в нем находится вся исходная программа в последова-

тельности ввода, необязательно совпадающей с последовательностью

нумерации строк. Для отображения в окне данных исходной программы в

последовательности нумерации строк необходимо ввести в командную

строку команду DISPLAY (отобразить). Эта команда, как и все осталь-

ные команды GPSS/PC, вводится без номера строки. С помощью команды

DISPLAY можно также вывести в окно данных отдельную строку, указав

ее номер в поле A команды, или последовательность строк, указав на-

чальный и конечный номера в полях A и B соответственно.

 

           5.3. Редактирование текста модели

 

Удалить строки из исходной программы можно командой DELETE

(удалить), указав в полях A и B начальный и конечный номера удаляе-

мой последовательности. Для удаления одной строки достаточно ввести

лишь поле A.

При необходимости вставить в текст новый оператор, поместив

его между уже введенными операторами, достаточно ввести его с про-

межуточным номером строки. Вы можете перенумеровать строки, введя

команду RENUMBER (перенумеровать), в поле A которой указывается но-

мер первой строки, а в поле B - шаг перенумерации.

Отредактировать содержимое строки можно с помощью команды EDIT

(редактировать), в поле A которой указывается номер редактируемой

строки. При вводе такой команды в командной строке появляется ре-

дактируемая строка. Подводя курсор к нужным позициям строки, вы мо-

жете внести в нее необходимые изменения. По окончании редактирова-

ния следует нажать клавишу Enter, и отредактированная строка пере-

несется в окно данных, заменив в исходной программе первоначальную

строку с этим номером. Вы можете убедиться в этом, введя команду

DISPLAY 2.

Если редактируемый оператор короткий, а изменений в нем много,

то редактирование удобнее произвести, введя измененный оператор с

тем же номером строки.

 

         5.4. Запись и считывание модели с диска

 

Если работа с моделью предполагается и по окончании данного

сеанса, то после ввода и редактирования исходную программу имеет

смысл записать на диск. Для этого необходимо ввести команду SAVE

(сохранить), в поле A которой указывается имя файла, в который бу-

дет записана модель. Файл должен иметь расширение.GPS.

Записав модель в файл, вы сможете в следующем сеансе работы с

GPSS/PC не вводить ее заново с клавиатуры, а считать с диска, введя

команду @ спецификация_файла, где спецификация_файла - полное имя

файла, которое вы дали исходной программе в команде SAVE, включаю-

щее расширение.GPS. При выполнении команды @ операторы исходной

программы по мере их считывания из файла транслируются и выводятся

в окно данных.

 

    5.5. Прогон модели и наблюдение за моделированием

 

После того, как исходная программа модели введена с клавиатуры

или считана с диска и оттранслирована, в памяти ПК создалась теку-

щая модель, и теперь можно выполнить ее прогон. Для этого в команд-

ную строку необходимо ввести управляющий оператор START, указав в

поле A соответствующее начальное значение счетчика завершений.

После нажатия клавиши Enter оператор START переносится в окно дан-

ных, и прогон модели начинается. Об этом сигнализирует сообщение

                 Simulation in Progress         ,

появляющееся в нижней строке командного окна - строке состояния, а

также так называемый индикатор моделирования, мигающий в правой

стороне нижней части окна данных.

Если прогон модели достаточно длинный, то можно наблюдать за

процессом моделирования, открывая те или иные графические окна. Это

производится путем нажатия клавиши Alt одновременно с символьной

клавишей с первой буквой названия окна.

Например, после нажатия клавиш Alt+B в верхней части экрана на

месте окна данных появляется окно блоков (BLOCKS), изображающее ди-

намику продвижения транзактов через блок-схему модели. Рядом с каж-

дым блоком выводится текущее число транзактов в нем, которое обнов-

ляется в процессе моделирования. Нажав клавиши Alt+N, вы можете за-

менить эту информацию на общее число транзактов, прошедших через

каждый блок. Блок, в котором находится активный транзакт, выделен

повышенной яркостью (на цветных мониторах - другим цветом).

Нажав клавиши Alt+F, вы можете наблюдать окно устройств

(FACILITIES), в котором наглядно отображена информация о текущем

состоянии каждого устройства модели: его использовании, занятости,

очереди к нему.

Аналогичную информацию о многоканальных устройствах можно по-

лучить, нажав Alt+S и открыв окно памятей (STORAGES).

Если в модели используются статистические таблицы, то, нажав

клавиши Alt+T, вы откроете окно таблиц (TABLES) с гистограммой

распределения соответствующего атрибута модели, обновляющейся в

процессе моделирования. Над гистограммой выводятся также текущие

значения среднего и среднеквадратического отклонения табулируемого

атрибута.

Если в модели используются матрицы, то, нажав клавиши Alt+M,

вы откроете окно матриц (MATRICES), в котором можно наблюдать об-

новляющиеся в процессе моделирования значения элементов матриц.

Находясь в любом из перечисленных окон, вы можете путем нажа-

тия клавиш Alt+L включить трассировку активного транзакта. При этом

в верхней части окна появляется строка, содержащая информацию о те-

кущем модельном времени, номере активного транзакта и его продвиже-

нии через блок-схему модели. Отключить трассировку можно повторным

нажатием этих же клавиш.

Перемещение внутри окна любого типа к тому или иному объекту

этого типа осуществляется путем нажатия клавиш управления курсором

PgUp, PgDn и End. Возвращение в окно данных производится путем на-

жатия клавиш Alt+D.

Следует заметить, что наблюдение графических окон и особенно

строки трассировки существенно замедляет моделирование, и при длин-

ных прогонах моделей этой возможностью не следует злоупотреблять.

Открытие того или иного окна может быть выполнено также с по-

мощью команды WINDOW (окно), в поле A которой указывается имя окна,

однако удобнее это делать так, как описано выше.

Кроме графических окон внутри любого из них, кроме окна дан-

ных, может быть открыто до четырех микроокон. Микроокна открываются

и закрываются командой MICROWINDOW (микроокно), имеющей следующий

формат:

          MICROWINDOW A,B,C; комментарий

В поле A указывается номер микроокна - константа 1, 2, 3 или

4. Поле B содержит наблюдаемую величину - любой СЧА модели. Поле C

определяет состояние микроокна в результате выполнения команды: ON

- открыто, OFF - закрыто. Если поле C пусто, то по умолчанию коман-

да открывает заданное микроокно. В поле комментария может быть за-

дано название микроокна длиной до восьми символов.

При открытии любого окна заданные микроокна с обновляющейся в

процессе моделирования информацией появляются в правой части соот-

ветствующего окна. Микроокно имеет форму прямоугольника с названием

над  рамкой, если оно было задано в комментарии к команде

MICROWINDOW.

В процессе моделирования можно также наблюдать одновременно до

двух графиков зависимостей любых СЧА модели от модельного времени.

Для этого необходимо до запуска модели ввести одну или две команды

PLOT (начертить), имеющие следующий формат:

            PLOT A,B,C,D; комментарий

В поле A указывается аргумент зависимости - любой СЧА модели.

Поле B должно содержать максимальное значение этого СЧА, определяю-

щее масштаб изображения по оси Y. Операнд B задается константой,

значение которой должно быть не менее 13. Поля C и D определяют на-

чальное и конечное значения модельного времени, определяющие масш-

таб изображения по оси X. Эти операнды также задаются константами.

В поле комментария может быть задан заголовок графика длиной до 34

символов.

График обновляется при каждом изменении модельного времени,

если оно попадает в диапазон, заданный операндами C и D. Указанный

в поле A СЧА-аргумент вычисляется относительно первого транзакта,

обрабатываемого после изменения модельного времени.

Процесс моделирования можно прервать, нажав одну из клавиш Esc

или Home. При этом в строке состояния командного окна появляется

сообщение о номере активного транзакта, обрабатываемого симулятором

в момент прерывания. Вы можете узнать значения интересующих вас

стандартных числовых атрибутов модели в момент прерывания, введя

команду SHOW (показать), операндом которой служат отдельные СЧА или

выражения из них. Значение заданного в команде СЧА или выражения

выводится в окно данных или другое активное окно. Введя команду

EVENTS (события), можно увидеть в окне данных содержимое списков

текущих и будущих событий. Команда USERCHAINS (списки пользователя)

позволяет просматривать в окне данных содержимое списков пользова-

теля. Обе последние команды не имеют операндов.

Инициировать прерывание моделирования можно также с помощью

команды STOP (остановить), имеющей следующий формат:

                      STOP A,B,C

В поле A указывается номер транзакта, вызывающего прерывание,

задаваемый константой. Если это поле пусто, то прерывание вызыва-

ется любым транзактом. В поле B задается имя или номер блока, при

входе в который происходит прерывание. Если этот операнд опущен, то

прерывание происходит при входе в любой блок. В поле C указывается

ON для установки условия прерывания и OFF для снятия этого условия

(по умолчанию ON).

Например, команда

                    STOP 100,MET1

устанавливает условие прерывания моделирования при входе транзакта

с номером 100 в блок с именем MET1. Команда

                    STOP 2

будет вызывать прерывание при каждом продвижении транзакта с номе-

ром 2, а команда

                    STOP,CHAIR

при каждом входе любого транзакта в блок с именем CHAIR. Наконец,

команда

                    STOP

без операндов будет вызывать прерывание при каждом продвижении лю-

бого транзакта, а команда

                    STOP,,OFF

снимает все условия прерывания, установленные ранее другими коман-

дами STOP.

Прервав моделирование, можно также воспользоваться командой

STEP (выполнить шаг) для пошагового выполнения модели с целью ее

отладки. Операнд в поле A команды задает количество входов активно-

го транзакта в блоки, которое производится при каждом выполнении

команды. Обычно этот операнд равен 1, и каждое выполнение команды

STEP приводит к продвижению активного транзакта к следующему блоку.

Отладку с использованием команды STEP удобно проводить, находясь в

окне блоков.

Для продолжения моделирования после прерывания следует ввести

в командную строку команду CONTINUE (продолжить).

Команды STEP и CONTINUE могут не только вводиться в командную

строку с клавиатуры, но и выбираться из меню команд, появляющемся в

командном окне при активизации любого графического окна. Выбор про-

изводится подводом крестообразного курсора в прямоугольную область

нужной команды и нажатием клавиши Ins. В окне блоков меню команд

предоставляет также некоторые дополнительные возможности [8].

Команды STEP, CONTINUE, а также любые другие часто используе-

мые команды удобно загрузить на функциональные клавиши F1-F10. Для

этого после ввода загружаемой команды с клавиатуры необходимо на-

жать клавиши Ctrl+Fn, где n - номер выбранной функциональной клави-

ши. После загрузки команды на функциональную клавишу для ее выпол-

нения достаточно нажатия этой клавиши.

 

   5.6. Получение и интерпретация стандартного отчета

 

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

строке состояния появляются сообщения

Writing REPORT.GPS Simulation Complete Reporting...,

сигнализирующие о том, что моделирование закончено и в данный мо-

мент производится создание отчета о прогоне модели. Затем система

переходит в состояние ожидания дальнейших команд.

Отчет, создаваемый по завершении моделирования, записывается в

файл со стандартным именем REPORT.GPS. Это имя может быть изменено

командой REPORT (создать отчет), имеющей следующий формат:

                       REPORT A,B

В поле A указывается спецификация файла, в который должен быть

выведен отчет. Если поле B содержит ключевое слово NOW, то отчет

создается немедленно после ввода команды.

Необходимо иметь ввиду, что отчет, создаваемый автоматически

по завершении прогона модели или командой REPORT, является 1неформа-

тированным, т.е. непригодным для непосредственного просмотра. Для

форматирования и создания стандартного отчета GPSS/PC необходимо

завершить сеанс и выполнить программу форматирования отчета. Выход

из интегрированной среды (завершение сеанса) производится путем

ввода управляющего оператора END (закончить). При этом производится

выход в MS DOS или в программу-оболочку Norton Commander.

Для форматирования отчета необходимо загрузить модуль формати-

рования GPSSREPT.EXE. После его загрузки на экране появляется

"заставка" с названием модуля, двумя окнами в нижней части экрана и

сообщениями-подсказками. В левом окне выведено имя файла, в котором

находится неформатированный отчет (по умолчанию это файл

REPORT.GPS). В правом окне выведено обозначение устройства, куда

должен быть выведен форматированный отчет (по умолчанию это экран

дисплея SCRN:). Форматированный отчет может быть также выведен на

печать или на диск. Для этого в правое окно надо ввести обозначение

PRN: или имя файла на диске соответственно. Для переключения окон

используется клавиша Enter. Для создания отчета на выбранном уст-

ройстве следует нажать клавишу Пробел, для выхода из программы -

клавишу Esc.

Если содержимое окон по умолчанию оставлено без изменения, то

после нажатия клавиши Пробел на экране появляется отчет о последнем

прогоне модели, выполненном перед завершением сеанса работы с моду-

лем GPSSPC.EXE. Отчет содержит следующую информацию:

1) общие сведения о модели и ее прогоне, включающие модельное

время начала (START_TIME) и конца (END_TIME) прогона, количество

блоков в модели (BLOCKS), количество устройств (FACILITIES), коли-

чество многоканальных устройств (STORAGES), объем памяти, оставав-

шейся свободной при прогоне модели (FREE_MEMORY);

2) сведения об именах объектов модели, включающие для каждого

имени идентификатор (NAME), присвоенное ему числовое значение

(VALUE) и тип имени: 0, если числовое значение имени присвоено

пользователем с помощью оператора EQU; 1, если числовое значение

имени присвоено системой; 2, если имя является именем блока;

3) сведения о блоках модели, включающие для каждого блока но-

мер строки исходной программы (LINE), номер или имя блока (LOC),

название блока (BLOCK_TYPE), количество транзактов, прошедших через

блок (ENTRY_COUNT), текущее количество транзактов в блоке в момент

завершения моделирования (CURRENT_COUNT), количество транзактов,

заблокированных перед блоком в момент завершения моделирования

(RETRY);

4) сведения об устройствах модели, включающие для каждого уст-

ройства его имя или номер (FACILITY), количество занятий устройства

(ENTRIES), коэффициент использования (UTIL.), среднее время на одно

занятие (AVE._TIME) и ряд других данных;

5) сведения о многоканальных устройствах модели, включающие

для каждого МКУ его имя или номер (STORAGE), емкость (CAP.), коли-

чество свободных каналов в момент завершения моделирования

(REMAIN.), наименьшее (MIN.) и наибольшее (MAX.) количество занятых

каналов в процессе моделирования, количество занятий МКУ (ENTRIES),

среднее количество занятых каналов (AVE.C.), коэффициент использо-

вания (UTIL.) и ряд других данных;

6) сведения об очередях модели, включающие для каждой очереди

ее имя или номер (QUEUE), максимальную длину очереди в процессе мо-

делирования (MAX.), текущую длину очереди в момент завершения моде-

лирования (CONT.), общее количество транзактов, вошедших в очередь

в процессе моделирования (ENTRIES), и количество "нулевых" входов в

очередь (ENTRIES(0)), среднюю длину очереди (AVE.CONT.), среднее

время ожидания в очереди с учетом всех транзактов (AVE.TIME) и без

учета "нулевых" входов (AVE.(-0));

7) сведения о статистических таблицах модели, включающие для

каждой таблицы ее имя или номер (TABLE), среднее значение (MEAN) и

среднеквадратическое отклонение (STD.DEV.) табулируемой величины,

границы частотных интервалов (RANGE), частоты (FREQUENCY) и накоп-

ленные частоты в процентах (CUM.%) попадания наблюдений в эти ин-

тервалы;

8) сведения о списках пользователя модели, включающие для каж-

дого списка его имя или номер (USER_CHAIN), количество транзактов в

списке в момент завершения моделирования (CHAIN_SIZE), среднее ко-

личество транзактов в списке (AVE.CONT), общее количество транзак-

тов, вошедших в список в процессе моделирования (ENTRIES), макси-

мальное количество транзактов, находившихся в списке (MAX), среднее

время пребывания транзакта в списке (AVE.TIME);

9) сведения о логических переключателях модели, включающие для

каждого ЛП его имя или номер (LOGICSWITCH) и состояние ЛП в момент

завершения моделирования: 1 - "включен", 0 - "выключен";

10) сведения о сохраняемых величинах модели, включающие для

каждой сохраняемой величины ее имя или номер (SAVEVALUE) и значение

в момент завершения моделирования (VALUE);

11) сведения о матрицах модели, включающие для каждой матрицы

ее имя или номер (MATRIX), а также список всех элементов матрицы в

формате: "строка" (ROW), "столбец" (COLUMN), "значение" (VALUE).

Если в операторе START задан вывод в отчет списков текущих и

будущих событий, то отчет включает в себя также сведения о транзак-

тах, находившихся в момент завершения моделирования в этих списках.

Сведения о транзактах размещаются в отчете в соответствии с разме-

щением транзактов в каждом списке.

Информация о списке текущих событий включает в себя для каждо-

го транзакта его номер (XACT_NUMBER), приоритет (PRI), резидентное

время транзакта (M1), номер текущего блока (CURRENT), номер следую-

щего блока (NEXT), а также перечень всех параметров транзакта в

формате: "параметр" (PARAMETER), "значение" (VALUE).

Информация о списке будущих событий включает для каждого тран-

закта те же данные, однако вместо резидентного времени транзакта

(M1) выводится запланированное время выхода транзакта из списка бу-

дущих событий (BDT).

Разумеется, сведения об объектах того или иного типа появля-

ются в отчете только в том случае, если в модели присутствует хотя

бы один объект данного типа. Кроме того, включением в отчет сведе-

ний об объектах разных типов можно управлять с помощью так называе-

мого установочного файла SETTINGS.GPS [8]. В отчетах о прогоне мо-

делей, включающих в себя другие, не рассматривавшиеся здесь объекты

GPSS/PC, появляется соответствующая информация и об этих объектах.

На рис. 24 приведен отчет о прогоне модели примера на рис. 21.

 

START_TIME END_TIME BLOCKS FACILITIES STORAGES FREE_MEMORY

  0  14617 12      0     1   274320

 

LINE LOC BLOCK_TYPE ENTRY_COUNT CURRENT_COUNT RETRY

 80 1  GENERATE       150         0    0

 90 2  ASSIGN         150         0    0

 100 3  PRIORITY       150         0    0

 110 4  QUEUE          150         0    0

 120 5  QUEUE          150         0    0

 130 6  ENTER          150         0    0

 140 7  DEPART         150         0    0

 150 8  DEPART         150          0    0

 160 9  ADVANCE        150         0    0

 170 10 LEAVE          150         0    0

 180 11 TABULATE       150         0    0

 190 12 TERMINATE      150              0    0

 

QUEUE MAX CONT. ENTRIES ENTRIES(0) AVE.CONT. AVE.TIME AVE.(-0)

1  1 0 54   48 0.02   6.07 54.67

2  1 0 42   35 0.01   4.14 24.86

3  1 0 54   49 0.02   6.22 67.20

 LINE 2 0 150  132 0.06   5.59 46.56

 

STORAGE   CAP. REMAIN. MIN. MAX. ENTRIES AVL. AVE.C. UTIL.

 STO2        2 2 0 2 150 1  0.66 0.328

 

TABLE MEAN STD.DEV. RETRY RANGE      FREQUENCY CUM.%

 WTIME 5.59 25.23 0

                            -   50    144 96.00

                         50 -  100      3 98.00

                        100 -  150      1 98.67

                        150 -  200      2 100.00

 

 TTIME 69.48 70.88 0

                            -  100    117 78.00

                        100 -  200     23 93.33

                        200 -  300      8 98.67

                        300 -  400      2 100.00

 

                         Рис. 24

 

Отчет выводится на экран постранично. Для вывода очередной

страницы необходимо нажать клавишу Пробел, для прекращения вывода

отчета - клавишу Esc. По окончании вывода отчета на экране появля-

ется сообщение

    [SPACE] for another report Any other key to end

Для создания отчета на другом устройстве или другого отчета надо

нажать клавишу Пробел, для выхода из программы GPSSREPT - любую

другую клавишу.

Помимо отчета отдельные результаты моделирования могут быть

также выведены в базу данных GPSS/PC [8] с помощью команд RESULT.

Однофакторный дисперсионный анализ и получение доверительных интер-

валов для выведенных в базу данных характеристик модели могут быть

выполнены с помощью команды ANOVA. Рассмотрение этих команд выходит

за рамки данного издания.

 

 

                    СПИСОК ЛИТЕРАТУРЫ

 

1. Шакин В.Н., Воробейчиков Л.А., Шибанов С.Е., Семенова Т.И.

Моделирование систем и сетей связи: Учебное пособие/МИС.- М., 1988.

2. Игельник Б.М., Лившиц В.М., Шибанов С.Е. Аналитическое мо-

делирование систем связи: Учебное пособие/МИС. - М., 1989.

3. Шакин В.Н., Лившиц В.М. Принципы построения локальных сетей

и анализ их характеристик: Учебное пособие для слушателей ФПКП/

МИС. - М., 1990.

4. Методические указания по использованию средств имитационно-

го моделирования систем и сетей связи для слушателей ФПКП/ Л.А.Во-

робейчиков, В.Н.Шакин, С.Е.Шибанов/МИС. - М., 1990.

5. Шеннон Р. Имитационное моделирование систем - искусство и

наука: Пер. с англ. - М.: Мир, 1978.

6. Максимей И.В. Имитационное моделирование на ЭВМ. - М.: Ра-

дио и связь, 1988.

7. Шрайбер Т.Дж. Моделирование на GPSS: Пер. с англ. - М.: Ма-

шиностроение, 1980.

8. GPSS/PC general purpose simulation. Reference Manual. -

Minuteman software. P.O. Box 171. Stow, Massachusetts 01775, 1986.                             

 



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: